[Rt-commit] rt branch, 4.1-trunk, created. rt-3.9.7-1009-g42c487b

Alex Vandiver alexmv at bestpractical.com
Wed Dec 22 17:03:09 EST 2010


The branch, 4.1-trunk has been created
        at  42c487b8f36d1af80563fa84b565963f974cb946 (commit)

- Log -----------------------------------------------------------------
commit 4147adb3435bfb3397a73c0875fb1d9b2277aed2
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Dec 15 14:28:17 2010 -0500

    Refresh the titlebox title tabs a little for aileron
    
    The rollup/down arrows are now sprites so we can use a different color
    in aileron but preserve the original color for older themes.
    
    The top padding on .titlebox-content is a little much when there isn't a
    right side links bar.  But without it most content runs into the link
    bar.
    
    Still needs testing in IE and undoubtedly fixes.

diff --git a/share/html/NoAuth/css/aileron/boxes.css b/share/html/NoAuth/css/aileron/boxes.css
index f906b27..aa15c43 100644
--- a/share/html/NoAuth/css/aileron/boxes.css
+++ b/share/html/NoAuth/css/aileron/boxes.css
@@ -46,22 +46,21 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 .titlebox {
- border-left: 1px solid #ccc;
- border-top: 1px solid #ccc;
- background-color: #efefef;
- padding-top: 1em;
  margin-top: 1em;
  margin-left: 1em;
- -moz-border-radius: 0.5em;
- -webkit-border-radius: 0.5em;
- margin-bottom: 2em;
- border-bottom: 2px solid #aaa;
- border-right: 2px solid #aaa;
- padding-right: 1em;
-
-
-  border-radius: 0.5em;
+    margin-bottom: 2em;
+}
 
+.titlebox .titlebox-content {
+    border-left: 1px solid #ccc;
+    border-top: 1px solid #ccc;
+    background-color: #efefef;
+    -moz-border-radius: 0.5em;
+    -webkit-border-radius: 0.5em;
+    border-bottom: 2px solid #aaa;
+    border-right: 2px solid #aaa;
+    border-radius: 0.5em;
+    padding: 1.5em 1em 1em 1em;
 }
 
 * html .titlebox {
@@ -71,12 +70,15 @@
 
 .titlebox .titlebox {
 
- background-color: #ffffff;
  margin-top: 1em;
  margin-right: 0.25em;
 
 }
 
+.titlebox .titlebox .titlebox-content {
+    background-color: white;
+}
+
 
 .titlebox {
  margin-left: 0em;
@@ -89,11 +91,6 @@
 
 .titlebox .titlebox-title {
  position: relative;
- margin-top: -1.5em;
- padding-bottom: 0.25em;
- padding-left: 1em;
- margin-right: -1em;
-
 }
 
 .titlebox .titlebox-title a {
@@ -107,21 +104,24 @@
 
 }
 
+.titlebox.rolled-up .titlebox-title {
+    border-bottom: 1px solid #ccc;
+}
+
+.titlebox.rolled-up .titlebox-title .right {
+    display: none;
+}
+
 .titlebox .titlebox-title .left {
     font-weight: bold;
     background: #ccc;
-    margin-left: 0.75em;
-    padding:0.5em;
-    padding-left: 0.75em;
-    padding-right: 0.75em;
-    -moz-border-radius: 0.5em;
-    -webkit-border-radius: 0.5em;
-    border-bottom: 2px solid #aaa;
-    border-right: 2px solid #aaa;
-
-    border-radius: 0.5em;
-
-
+/*    position: absolute;
+    left: 0.75em;*/
+    margin-left: 1em;
+    padding: 0.25em 0.75em 0.25em 2em;
+    line-height: 1.5em;
+    -webkit-border-top-left-radius: 0.3em;
+    -webkit-border-top-right-radius: 0.3em;
 }
 
 .titlebox .titlebox-title .right-empty {
@@ -130,8 +130,8 @@
 
 .titlebox .titlebox-title .right {
   position: absolute;
-   right: 0;
-   top: 0.5em;
+   right: 2px;
+   top: 1.75em;
   font-size: 0.9em;
   background: #dedede;
   border-left: 1px solid #ccc;
@@ -157,36 +157,22 @@
  color: #000;
 }
 
-.titlebox .titlebox-content {
- padding-top: 0.5em;
- padding-left: 1em;
- padding-bottom: 1em;
-
-}
-
 .titlebox .titlebox-title .widget a {
   display: block;
   margin: 0;
-  margin-top: 0.5em;
   width: 20px;
 
-  background: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rollup-arrow.gif) no-repeat center center;
-
+  background: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rollup-arrow.gif) no-repeat;
+  background-position: center 0;
+  
   position: absolute;
-  top: -1em;
-  left: 0.15em;
-  float: left;
-
-  padding: 11px 0 0 0;
+  top: 0.5em;
+  left: 1.2em;
+  
+  padding: 7px 0 0 0;
   overflow: hidden;
 }
 
-* html .titlebox .titlebox-title .widget a {
-    background-position: center 0.3em;
-    top: 0em;
-    left: -1.5em;
-}
-
 .titlebox.rolled-up .titlebox-title .widget a {
     background-image: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rolldown-arrow.gif);
 }
diff --git a/share/html/NoAuth/css/aileron/forms.css b/share/html/NoAuth/css/aileron/forms.css
new file mode 100644
index 0000000..fc3675c
--- /dev/null
+++ b/share/html/NoAuth/css/aileron/forms.css
@@ -0,0 +1,26 @@
+/* These override the base titlebox rules in base/forms.css. They try not to
+   duplicate properties. */
+
+div.error .titlebox-title span.left {
+    border: none;
+}
+
+div.results .titlebox {
+    border: none;
+    background: none;
+}
+
+div.results .titlebox-content {
+    border: 1px solid #aa9;
+    border-bottom: 2px solid #990;
+    border-right: 2px solid #990;
+}
+
+div.results .titlebox-title .left {
+    border: solid #aa9;
+    border-width: 1px 1px 0 1px;
+}
+
+div.results .titlebox-content {
+    background: #ffc;
+}
diff --git a/share/html/NoAuth/css/aileron/login.css b/share/html/NoAuth/css/aileron/login.css
new file mode 100644
index 0000000..f7de8f3
--- /dev/null
+++ b/share/html/NoAuth/css/aileron/login.css
@@ -0,0 +1,3 @@
+#login-box .titlebox-title .left {
+    padding-left: 0.75em;
+}
diff --git a/share/html/NoAuth/css/aileron/main.css b/share/html/NoAuth/css/aileron/main.css
index 995db8b..00c2f02 100644
--- a/share/html/NoAuth/css/aileron/main.css
+++ b/share/html/NoAuth/css/aileron/main.css
@@ -53,6 +53,8 @@
 @import "layout.css";
 @import "nav.css";
 @import "boxes.css";
+ at import "forms.css";
+ at import "login.css";
 @import "ticket-lists.css";
 @import "ticket-search.css";
 @import "ticket.css";
diff --git a/share/html/NoAuth/css/aileron/ticket.css b/share/html/NoAuth/css/aileron/ticket.css
index e201247..211135c 100644
--- a/share/html/NoAuth/css/aileron/ticket.css
+++ b/share/html/NoAuth/css/aileron/ticket.css
@@ -190,8 +190,7 @@ div#ticket-history .messagebody .messagebody{
 .ticket-transaction.other .type { background: #abc; }
 
 
-
-
+/* Color the titlebox tabs */
 .ticket-info-cfs .titlebox-title .left { background-color: #b32; color: #fff;}
 .ticket-info-basics .titlebox-title .left { background-color: #b32;  color: #fff;}
 .ticket-info-people .titlebox-title .left { background-color: #48c;  color: #fff;}
@@ -201,6 +200,16 @@ div#ticket-history .messagebody .messagebody{
 .ticket-info-dates .titlebox-title .left { background-color: #633063;  color: #fff;}
 .ticket-info-attachments .titlebox-title .left { background-color: #993366;  color: #fff;}
 
+/* Use a lighter colored toggle arrow */
+.ticket-info-cfs .titlebox-title .widget a { background-position: center -7px; }
+.ticket-info-basics .titlebox-title .widget a { background-position: center -7px; }
+.ticket-info-people .titlebox-title .widget a { background-position: center -7px; }
+.ticket-info-requestor .titlebox-title .widget a { background-position: center -7px; }
+.ticket-info-links .titlebox-title .widget a { background-position: center -7px; }
+.ticket-info-reminders .titlebox-title .widget a { background-position: center -7px; }
+.ticket-info-dates .titlebox-title .widget a { background-position: center -7px; }
+.ticket-info-attachments .titlebox-title .widget a { background-position: center -7px; }
+
 
 .ticket-summary .titlebox-title .left a, .ticket-summary .titlebox-title .left a:visited { color: #fff;}
 
diff --git a/share/html/NoAuth/css/ballard/boxes.css b/share/html/NoAuth/css/ballard/boxes.css
index 87066b2..45ea79e 100644
--- a/share/html/NoAuth/css/ballard/boxes.css
+++ b/share/html/NoAuth/css/ballard/boxes.css
@@ -160,22 +160,21 @@
 .titlebox .titlebox-title .widget a {
   display: block;
   margin: 0;
-  margin-top: 0.5em;
+  margin-top: 0.6em;
   width: 20px;
 
-  background: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rollup-arrow.gif) no-repeat center center;
+  background: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rollup-arrow.gif) no-repeat center 0;
 
   position: absolute;
   top: -1em;
   left: 0.15em;
   float: left;
 
-  padding: 11px 0 0 0;
+  padding: 7px 0 0 0;
   overflow: hidden;
 }
 
 * html .titlebox .titlebox-title .widget a {
-    background-position: center 0.3em;
     top: 0em;
     left: -1.5em; 
 }
diff --git a/share/html/NoAuth/css/web2/boxes.css b/share/html/NoAuth/css/web2/boxes.css
index d3f055b..dc3c9ff 100644
--- a/share/html/NoAuth/css/web2/boxes.css
+++ b/share/html/NoAuth/css/web2/boxes.css
@@ -167,22 +167,21 @@
 .titlebox .titlebox-title .widget a {
   display: block;
   margin: 0;
-  margin-top: 0.5em;
+  margin-top: 0.6em;
   width: 20px;
 
-  background: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rollup-arrow.gif) no-repeat center center;
+  background: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rollup-arrow.gif) no-repeat center 0;
 
   position: absolute;
   top: -1em;
   left: 0.15em;
   float: left;
 
-  padding: 11px 0 0 0;
+  padding: 7px 0 0 0;
   overflow: hidden;
 }
 
 * html .titlebox .titlebox-title .widget a {
-    background-position: center 0.3em;
     top: 0em;
     left: -1.5em; 
 }
diff --git a/share/html/NoAuth/images/css/rolldown-arrow.gif b/share/html/NoAuth/images/css/rolldown-arrow.gif
index 3c296dc..181ab86 100644
Binary files a/share/html/NoAuth/images/css/rolldown-arrow.gif and b/share/html/NoAuth/images/css/rolldown-arrow.gif differ
diff --git a/share/html/NoAuth/images/css/rollup-arrow.gif b/share/html/NoAuth/images/css/rollup-arrow.gif
index f009ff4..2daaa55 100644
Binary files a/share/html/NoAuth/images/css/rollup-arrow.gif and b/share/html/NoAuth/images/css/rollup-arrow.gif differ

commit 8a5779e1a053c8fec2a5428ce588e0203fcd0d4b
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Fri Dec 17 15:23:28 2010 -0500

    Fix our DTD on index.html

diff --git a/share/html/index.html b/share/html/index.html
index 24cc9da..812de72 100755
--- a/share/html/index.html
+++ b/share/html/index.html
@@ -1,6 +1,4 @@
-<!DOCTYPE html 
-     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html>
 <!--
 % $m->out('--'.'>');
 % $m->comp('/Elements/Header', Title=>loc("RT at a glance"), Refresh => $session{'home_refresh_interval'}||RT->Config->Get('HomePageRefreshInterval', $session{'CurrentUser'} ));

commit 0b5233e035e889b5374d760101993d6bb52d90d8
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Fri Dec 17 15:24:05 2010 -0500

    fix rounding on new tabs

diff --git a/share/html/NoAuth/css/aileron/boxes.css b/share/html/NoAuth/css/aileron/boxes.css
index aa15c43..4a91ae8 100644
--- a/share/html/NoAuth/css/aileron/boxes.css
+++ b/share/html/NoAuth/css/aileron/boxes.css
@@ -122,6 +122,9 @@
     line-height: 1.5em;
     -webkit-border-top-left-radius: 0.3em;
     -webkit-border-top-right-radius: 0.3em;
+    -moz-border-radius-topleft: 0.3em;
+    -moz-border-radius-topright: 0.3em;
+    border-radius: 0.3em 0.3em 0 0;
 }
 
 .titlebox .titlebox-title .right-empty {

commit debf6652f86f3c68b10f23a8673dee08a92a4eae
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Fri Dec 17 15:24:29 2010 -0500

    tweaks for titleboxes on IE

diff --git a/share/html/NoAuth/css/aileron/msie.css b/share/html/NoAuth/css/aileron/msie.css
index ebe1092..981009a 100644
--- a/share/html/NoAuth/css/aileron/msie.css
+++ b/share/html/NoAuth/css/aileron/msie.css
@@ -48,7 +48,6 @@
 
 div#body {
     top: 3em;
-    padding-top: 3em;
 }
 
 div#logo .rtname {
@@ -109,21 +108,18 @@ div#nav li.last {
 .ticket-transaction .type a { font-weight: normal; text-decoration: none; color: #fff; }
 
 
-.titlebox {
- border-top: none;
- border-left: none;
-}
 
-.titlebox .titlebox-title .left {
-    padding: 0.5em;
+
+.titlebox .titlebox-title .widget a {
+  height:7px;
 }
 
 
+
 .titlebox .titlebox-title .right {
-    border-right: 2px solid #aaa;
     display: block;
-    margin-top: 0.1em;
-    right: -0.2em;
+    margin-top: 0.4em;
+    padding-right: 0.3em;
 
 }
 
@@ -148,22 +144,10 @@ table.queue-summary td, td.collection-as-table {
     padding: 0.25em;
 }
 
- .titlebox-title {
+.titlebox-title {
     position: relative;
 }
 
-.titlebox-title .widget {
-    position: absolute;
-    top: -0.75em;
-    left: -0.25em;
-
-}
-.titlebox-title .left {
-    position: absolute;
-    top: -0.75em;
-    left: 1em;
-}
-
 /* nested things. like the ticket dates tab */
 .titlebox .titlebox .titlebox-title .right{
     top: 0.25em;
diff --git a/share/html/NoAuth/css/aileron/msie6.css b/share/html/NoAuth/css/aileron/msie6.css
index 55888ef..76820fb 100644
--- a/share/html/NoAuth/css/aileron/msie6.css
+++ b/share/html/NoAuth/css/aileron/msie6.css
@@ -61,7 +61,7 @@ div#body {
 }
 .titlebox .titlebox-title .right{
     position: absolute;
-    top: 0.6em;
+    top: 1.5em;
 }
 
 .titlebox

commit 919ffb85b1db8703c35d6e8938ebec325824e06e
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Fri Dec 17 17:05:00 2010 -0500

    Fixes for IE7's box model and the titlebox toggle

diff --git a/share/html/NoAuth/css/aileron/msie.css b/share/html/NoAuth/css/aileron/msie.css
index 981009a..18580b7 100644
--- a/share/html/NoAuth/css/aileron/msie.css
+++ b/share/html/NoAuth/css/aileron/msie.css
@@ -109,9 +109,11 @@ div#nav li.last {
 
 
 
-
+/* IE's box model is wrong */
 .titlebox .titlebox-title .widget a {
-  height:7px;
+    padding-top: 0;
+    height: 7px;
+    top: 0.75em;
 }
 
 

commit f78d5fd99d12ef1a646b4efa4b277ed58a24e798
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Mon Dec 20 13:03:46 2010 -0500

    Fix a bug in upgrades that caused the new columns on ACL to make the
    3.9.1 upgrades explode since the schema hadn't yet been updated.

diff --git a/etc/upgrade/3.9.1/content b/etc/upgrade/3.9.1/content
index c7bc535..bed3e74 100644
--- a/etc/upgrade/3.9.1/content
+++ b/etc/upgrade/3.9.1/content
@@ -1,6 +1,15 @@
 @Initial = (
     sub {
         use strict;
+        use RT::ACE;
+        {
+            package RT::ACE;
+            my $throwaway = RT::ACE->new(RT->SystemUser);
+            delete $TABLE_ATTR{'RT::ACE'}->{LastUpdated};
+            delete $TABLE_ATTR{'RT::ACE'}->{LastUpdatedBy};
+        }
+
+
         $RT::Logger->debug('Make sure templates all have known types');
 
         my $templates = RT::Templates->new(RT->SystemUser);
diff --git a/etc/upgrade/3.9.7/content b/etc/upgrade/3.9.7/content
index 9dfb114..7ca2744 100644
--- a/etc/upgrade/3.9.7/content
+++ b/etc/upgrade/3.9.7/content
@@ -20,6 +20,19 @@ my $move_attributes = sub {
 
 @Initial = (
     sub {
+        use RT::ACE;
+        {
+            # if we're coming from 3.8, we've gone and disabled attributes
+            # on the ACL table in 3.9.1 or so. Regenerating them is important
+            package RT::ACE;
+            my $throwaway = RT::ACE->new(RT->SystemUser);
+            delete $TABLE_ATTR{'RT::ACE'};
+            $throwaway = RT::ACE->new(RT->SystemUser);
+        }
+
+
+    },
+    sub {
         return $move_attributes->( 'Users', 'RT::User', 'AuthToken');
     },
     sub {

commit 4a0ebf8042f76969b15c7b60b64f26ea97bb8a2c
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Mon Dec 20 13:13:04 2010 -0500

    reformat the reminder creation form to fix a significant UI regression

diff --git a/share/html/Ticket/Elements/Reminders b/share/html/Ticket/Elements/Reminders
index 5d47f5f..4e8d2d5 100644
--- a/share/html/Ticket/Elements/Reminders
+++ b/share/html/Ticket/Elements/Reminders
@@ -152,6 +152,8 @@ $Ticket
 <tr>
 <td class="label"><&|/l&>Owner</&>:</td>
 <td class="entry"><& /Elements/SelectOwner, Name => 'NewReminder-Owner', QueueObj => $Ticket->QueueObj, Default=>$session{'CurrentUser'}->id, DefaultValue => 0 &></td>
+</tr>
+<tr>
 <td class="label"><&|/l&>Due</&>:</td>
 <td class="entry"><& /Elements/SelectDate, Name => "NewReminder-Due", Default => "" &></td>
 </tr>

commit a973a5da438f3c0f2100d2d1539fdd2781050bc7
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Dec 20 14:34:24 2010 -0500

    Monkey-patch jQuery UI's datepicker to handle IDs containing single quotes
    
    Query builder inputs for date and datetime CFs have IDs like:
    ValueOf'CF.{Name of Field}'

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 1b33f30..2390137 100755
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -2205,6 +2205,7 @@ Set(@JSFilesInHead, qw/
     jquery_noconflict.js
     jquery-ui-1.8.4.custom.min.js
     jquery.tablesorter.min.js
+    jquery-ui-patch-datepicker.js
     ui.timepickr.js
     titlebox-state.js
     util.js
diff --git a/share/html/NoAuth/js/jquery-ui-patch-datepicker.js b/share/html/NoAuth/js/jquery-ui-patch-datepicker.js
new file mode 100644
index 0000000..c612fc1
--- /dev/null
+++ b/share/html/NoAuth/js/jquery-ui-patch-datepicker.js
@@ -0,0 +1,14 @@
+(function($){
+    $.datepicker._newInst_orig = $.datepicker._newInst;
+    $.datepicker._newInst = function(target, inline) {
+        var data = this._newInst_orig(target, inline);
+
+        // Escape single quotes to avoid incorrect quoting in onclick handlers
+        // when other datepicker code interpolates inst.id.  They'll already be
+        // escaped by the original _newInst for handing to jQuery's CSS
+        // selector parser.
+        data.id = data.id.replace(/'/g, "\\'");
+
+        return data;
+    };
+})(jQuery);

commit 62ff36fa6d7b09b8f316da26f1e24288c409f316
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Mon Dec 20 15:08:51 2010 -0500

    Update the documentation to match reality, on the topic of default db name

diff --git a/configure.ac b/configure.ac
index 85fddd7..02894e1 100755
--- a/configure.ac
+++ b/configure.ac
@@ -161,7 +161,7 @@ AC_SUBST(DB_DBA)
 dnl DB_DATABASE
 AC_ARG_WITH(db-database,
 	    AC_HELP_STRING([--with-db-database=DBNAME],
-	    		   [name of the database to use (default: rt3)]),
+	    		   [name of the database to use (default: rt4)]),
             DB_DATABASE=$withval,
             DB_DATABASE=rt4)
 AC_SUBST(DB_DATABASE)

commit 760d1da77a9fd499590f0ba61d6c01c042df2733
Author: Shawn M Moore <sartak at bestpractical.com>
Date:   Mon Dec 20 15:19:26 2010 -0500

    No need to turn off once warnings now that SystemUser is a method

diff --git a/sbin/rt-attributes-viewer.in b/sbin/rt-attributes-viewer.in
index b8f25ae..988dd20 100644
--- a/sbin/rt-attributes-viewer.in
+++ b/sbin/rt-attributes-viewer.in
@@ -90,7 +90,7 @@ RT::LoadConfig();
 RT::Init();
 
 require RT::Attribute;
-my $attr = RT::Attribute->new( do { no warnings 'once'; RT->SystemUser } );
+my $attr = RT::Attribute->new( RT->SystemUser );
 $attr->Load( $id );
 unless ( $attr->id ) {
     print STDERR "Couldn't load attribute #$id\n";

commit cc12809c93a08c06764d1cd988b91fdeb42f8392
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Dec 20 15:42:08 2010 -0500

    Update the rights editor styles for readability

diff --git a/share/html/NoAuth/css/base/rights-editor.css b/share/html/NoAuth/css/base/rights-editor.css
index 2cd954d..43f82fa 100644
--- a/share/html/NoAuth/css/base/rights-editor.css
+++ b/share/html/NoAuth/css/base/rights-editor.css
@@ -45,16 +45,12 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-/* This selector is very heavy handed, but the jQuery UI theme is tenacious */
-.rights-editor, .rights-editor * {
-    font-family: arial, helvetica, sans-serif !important;
-}
-
 /* Styles for putting jQuery UI tabs on the left */
 .rights-editor {
     border: none;
     background: transparent;
     width: 100%;
+    font-size: 110%;
 }
 
 /* Position and style the left tabs */
@@ -111,10 +107,6 @@ li.category ~ li.category {
     font-size: 80%;
 }
 
-.rights-editor ul.rights-list {
-    list-style: none;
-}
-
 .category-tabs {
     width: 100%;
     border: none;
@@ -135,6 +127,7 @@ li.category ~ li.category {
     background: white !important;
     color: #222 !important;
     border-color: #aaa !important; 
+    font-weight: bold;
 }
 
 .rights-editor .ui-state-active a,
@@ -151,6 +144,22 @@ li.category ~ li.category {
     display: none;
 }
 
+.rights-editor ul.rights-list {
+    list-style: none;
+}
+
+.rights-editor ul.rights-list li {
+    padding: 0.2em 0;
+}
+
+.rights-editor ul.rights-list li:nth-child(even) {
+    background: #f4f4f4;
+}
+
+.rights-editor ul.rights-list li label {
+    cursor: pointer;
+}
+
 .rights-editor .rightname {
     color: #888;
     font-size: 0.9em;

commit 9e76a3be9767805dcaa72234ad48ea8798839db7
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Dec 20 15:51:15 2010 -0500

    Standardize on a Save Changes button in the rights editor and kill Reset

diff --git a/share/html/Admin/Articles/Classes/GroupRights.html b/share/html/Admin/Articles/Classes/GroupRights.html
index 0031bc2..96a058c 100644
--- a/share/html/Admin/Articles/Classes/GroupRights.html
+++ b/share/html/Admin/Articles/Classes/GroupRights.html
@@ -53,7 +53,7 @@
 
   <& /Admin/Elements/EditRights, Context => $ClassObj, Principals => \@principals &>
 
-<& /Elements/Submit, Caption => loc("Modify Group Rights"), Reset => 1 &>
+  <& /Elements/Submit, Label => loc('Save Changes') &>
 </form>
 <%INIT>
 
diff --git a/share/html/Admin/Articles/Classes/UserRights.html b/share/html/Admin/Articles/Classes/UserRights.html
index bd9b879..57583c6 100644
--- a/share/html/Admin/Articles/Classes/UserRights.html
+++ b/share/html/Admin/Articles/Classes/UserRights.html
@@ -51,8 +51,8 @@
 <form method="post" action="UserRights.html" name="ModifyUserRights" id="ModifyUserRights">
 <input type="hidden" name="id" value="<% $ClassObj->id %>" />
   <& /Admin/Elements/EditRights, Context => $ClassObj, Principals => \@principals &>
- 
-  <& /Elements/Submit, Label => loc('Modify User Rights'), Reset => 1 &>
+
+  <& /Elements/Submit, Label => loc('Save Changes') &> 
 <%INIT>
 my @results =  ProcessACLs(\%ARGS);
 
diff --git a/share/html/Admin/CustomFields/GroupRights.html b/share/html/Admin/CustomFields/GroupRights.html
index ee85364..9707988 100644
--- a/share/html/Admin/CustomFields/GroupRights.html
+++ b/share/html/Admin/CustomFields/GroupRights.html
@@ -53,7 +53,7 @@
     <input type="hidden" class="hidden" name="id" value="<% $CustomFieldObj->id %>" />
 
     <& /Admin/Elements/EditRights, Context => $CustomFieldObj, Principals => \@principals &>
-    <& /Elements/Submit, Caption => loc("Be sure to save your changes"), Reset => 1 &>
+    <& /Elements/Submit, Label => loc('Save Changes') &>
   </form>
 
 <%INIT>
diff --git a/share/html/Admin/CustomFields/UserRights.html b/share/html/Admin/CustomFields/UserRights.html
index 48afc73..6a72f4a 100644
--- a/share/html/Admin/CustomFields/UserRights.html
+++ b/share/html/Admin/CustomFields/UserRights.html
@@ -52,7 +52,7 @@
   <form method="post" action="UserRights.html" name="ModifyUserRights" id="ModifyUserRights">
     <input type="hidden" class="hidden" name="id" value="<% $CustomFieldObj->id %>" />
     <& /Admin/Elements/EditRights, Context => $CustomFieldObj, Principals => \@principals &>
-    <& /Elements/Submit, Caption => loc("Be sure to save your changes"), Reset => 1 &>
+    <& /Elements/Submit, Label => loc('Save Changes') &>
   </form>
 <%INIT>
 # Update the acls.
diff --git a/share/html/Admin/Global/GroupRights.html b/share/html/Admin/Global/GroupRights.html
index fb8bd1b..b526ca7 100755
--- a/share/html/Admin/Global/GroupRights.html
+++ b/share/html/Admin/Global/GroupRights.html
@@ -51,7 +51,7 @@
 
 <form method="post" action="GroupRights.html" id="ModifyGroupRights" name="ModifyGroupRights">
   <& /Admin/Elements/EditRights, Context => $RT::System, Principals => \@principals &>
-  <& /Elements/Submit, Label => loc('Modify Group Rights'), Reset => 1 &>
+  <& /Elements/Submit, Label => loc('Save Changes') &>
 </form>
   
 <%INIT>
diff --git a/share/html/Admin/Global/UserRights.html b/share/html/Admin/Global/UserRights.html
index 85410ba..f3505fb 100755
--- a/share/html/Admin/Global/UserRights.html
+++ b/share/html/Admin/Global/UserRights.html
@@ -51,7 +51,7 @@
 
 <form method="post" action="UserRights.html" name="ModifyUserRights" id="ModifyUserRights">
   <& /Admin/Elements/EditRights, Context => $RT::System, Principals => \@principals &>
-  <& /Elements/Submit, Label => loc('Modify User Rights'), Reset => 1 &>
+  <& /Elements/Submit, Label => loc('Save Changes') &>
 </form>
 <%INIT>
 my @results = ProcessACLs(\%ARGS);
diff --git a/share/html/Admin/Groups/GroupRights.html b/share/html/Admin/Groups/GroupRights.html
index 8e99ec8..ca1cff7 100755
--- a/share/html/Admin/Groups/GroupRights.html
+++ b/share/html/Admin/Groups/GroupRights.html
@@ -52,7 +52,7 @@
   <form method="post" action="GroupRights.html" id="ModifyGroupRights" name="ModifyGroupRights">
     <input type="hidden" class="hidden" name="id" value="<% $GroupObj->id %>" />
     <& /Admin/Elements/EditRights, Context => $GroupObj, Principals => \@principals &>
-    <& /Elements/Submit, Label => loc('Modify Group Rights'), Reset => 1 &>
+    <& /Elements/Submit, Label => loc('Save Changes') &>
   </form>
 <%INIT>
 # Update the acls.
diff --git a/share/html/Admin/Groups/UserRights.html b/share/html/Admin/Groups/UserRights.html
index c547b32..ece5ea8 100755
--- a/share/html/Admin/Groups/UserRights.html
+++ b/share/html/Admin/Groups/UserRights.html
@@ -52,7 +52,7 @@
   <form method="post" action="UserRights.html" name="ModifyUserRights" id="ModifyUserRights">
     <input type="hidden" class="hidden" name="id" value="<% $GroupObj->id %>" />
     <& /Admin/Elements/EditRights, Context => $GroupObj, Principals => \@principals &>
-    <& /Elements/Submit, Label => loc('Modify User Rights'), Reset => 1 &>
+    <& /Elements/Submit, Label => loc('Save Changes') &>
   </form>
 
 <%INIT>
diff --git a/share/html/Admin/Queues/GroupRights.html b/share/html/Admin/Queues/GroupRights.html
index d19584b..1e85d7d 100755
--- a/share/html/Admin/Queues/GroupRights.html
+++ b/share/html/Admin/Queues/GroupRights.html
@@ -56,7 +56,7 @@
 
   <& /Admin/Elements/EditRights, Context => $QueueObj, Principals => \@principals &>
 
-  <& /Elements/Submit, Label => loc('Modify Group Rights'), Reset => 1 &>
+  <& /Elements/Submit, Label => loc('Save Changes') &>
 </form>
 
 <%INIT>
diff --git a/share/html/Admin/Queues/UserRights.html b/share/html/Admin/Queues/UserRights.html
index 8f8f8ae..4681911 100755
--- a/share/html/Admin/Queues/UserRights.html
+++ b/share/html/Admin/Queues/UserRights.html
@@ -57,8 +57,7 @@
 
   <& /Admin/Elements/EditRights, Context => $QueueObj, Principals => \@principals &>
  
-  <& /Elements/Submit, Label => loc('Modify User Rights'), Reset => 1 &>
-
+  <& /Elements/Submit, Label => loc('Save Changes') &>
 </form>
 
 <%INIT>

commit d70f8b30ab6b3114aaaeef3830d21c552ccfaace
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Mon Dec 20 15:18:23 2010 -0500

    Allow ignoring of current columns when upgrading through old versions
    
    RT 3.9.5 added three columns to the ACL table; if the user is
    upgrading through any versions before that which attempt to add rows
    to the ACL table (3.8.2, 3.9.1), they will fail.  Work around this by
    temporarily removing the columns from RT's internal schema if the an
    upgrade predates the columns being added.  To determine when key
    columns were added, look for a file named 'backcompat' in the
    appropriate upgrade directory.

diff --git a/etc/upgrade/3.9.1/content b/etc/upgrade/3.9.1/content
index bed3e74..c7bc535 100644
--- a/etc/upgrade/3.9.1/content
+++ b/etc/upgrade/3.9.1/content
@@ -1,15 +1,6 @@
 @Initial = (
     sub {
         use strict;
-        use RT::ACE;
-        {
-            package RT::ACE;
-            my $throwaway = RT::ACE->new(RT->SystemUser);
-            delete $TABLE_ATTR{'RT::ACE'}->{LastUpdated};
-            delete $TABLE_ATTR{'RT::ACE'}->{LastUpdatedBy};
-        }
-
-
         $RT::Logger->debug('Make sure templates all have known types');
 
         my $templates = RT::Templates->new(RT->SystemUser);
diff --git a/etc/upgrade/3.9.5/backcompat b/etc/upgrade/3.9.5/backcompat
new file mode 100644
index 0000000..611ab51
--- /dev/null
+++ b/etc/upgrade/3.9.5/backcompat
@@ -0,0 +1 @@
+RT::ACE		LastUpdated LastUpdatedBy Creator Created
diff --git a/etc/upgrade/3.9.7/content b/etc/upgrade/3.9.7/content
index 7ca2744..9dfb114 100644
--- a/etc/upgrade/3.9.7/content
+++ b/etc/upgrade/3.9.7/content
@@ -20,19 +20,6 @@ my $move_attributes = sub {
 
 @Initial = (
     sub {
-        use RT::ACE;
-        {
-            # if we're coming from 3.8, we've gone and disabled attributes
-            # on the ACL table in 3.9.1 or so. Regenerating them is important
-            package RT::ACE;
-            my $throwaway = RT::ACE->new(RT->SystemUser);
-            delete $TABLE_ATTR{'RT::ACE'};
-            $throwaway = RT::ACE->new(RT->SystemUser);
-        }
-
-
-    },
-    sub {
         return $move_attributes->( 'Users', 'RT::User', 'AuthToken');
     },
     sub {
diff --git a/sbin/rt-setup-database.in b/sbin/rt-setup-database.in
index 01687c8..c5ac3c4 100755
--- a/sbin/rt-setup-database.in
+++ b/sbin/rt-setup-database.in
@@ -266,7 +266,30 @@ sub action_insert {
     $file = $RT::EtcPath . "/initialdata" if $init && !$file;
     $file ||= $args{'datadir'}."/content";
 
-    return $RT::Handle->InsertData( $file, $root_password );
+    # Slurp in backcompat
+    my %removed;
+    my @back = @{$args{backcompat} || []};
+    if (@back) {
+        my @lines = do {local @ARGV = @back; <>};
+        for (@lines) {
+            s/\#.*//;
+            next unless /\S/;
+            my ($class, @fields) = split;
+            $class->_BuildTableAttributes;
+            $RT::Logger->debug("Temporarily removing @fields from $class");
+            $removed{$class}{$_} = delete $RT::Record::_TABLE_ATTR->{$class}{$_}
+                for @fields;
+        }
+    }
+
+    my @ret = $RT::Handle->InsertData( $file, $root_password );
+
+    # Put back the fields we chopped off
+    for my $class (keys %removed) {
+        $RT::Record::_TABLE_ATTR->{$class}{$_} = $removed{$class}{$_}
+            for keys %{$removed{$class}};
+    }
+    return @ret;
 }
 
 sub action_upgrade {
@@ -350,9 +373,11 @@ sub action_upgrade {
     print "\nIT'S VERY IMPORTANT TO BACK UP BEFORE THIS STEP\n\n";
     _yesno() or exit(-2) unless $args{'force'};
 
-    foreach my $v ( @versions ) {
+    foreach my $n ( 0..$#versions ) {
+        my $v = $versions[$n];
+        my @back = grep {-e $_} map {"$base_dir/$versions[$_]/backcompat"} $n+1..$#versions;
         print "Processing $v\n";
-        my %tmp = (%args, datadir => "$base_dir/$v", datafile => undef);
+        my %tmp = (%args, datadir => "$base_dir/$v", datafile => undef, backcompat => \@back);
         if ( -e "$base_dir/$v/schema.$db_type" ) {
             action_schema( %tmp );
         }

commit e1758162d3d2a56bcbec852f4b163fb3b97f5d7c
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Mon Dec 20 18:02:44 2010 -0500

    precache the user's system rights, saving 8 SQL queries per page

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index b7aa9f4..1bf2efd 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -460,6 +460,9 @@ sub ShowRequestedPage {
 
     my $m = $HTML::Mason::Commands::m;
 
+    # precache all system level rights for the current user
+    $HTML::Mason::Commands::session{CurrentUser}->PrincipalObj->HasRights( Object => RT->System );
+
     InitializeMenu();
 
     SendSessionCookie();

commit d87fbc66217452072ff16d708951278cb2cec525
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Mon Dec 20 18:03:22 2010 -0500

    correct calls from $RT::System to RT->System

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 05a91cc..045e77b 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -120,16 +120,16 @@ if ( $request_path !~ m{^/SelfService/} ) {
     $tools->child( offline => title => loc('Offline'), path    => '/Tools/Offline.html', sort_order => 10,
                    description => loc('Create tickets offline') );
 
-    if ( $session{'CurrentUser'}->HasRight( Right => 'ShowApprovalsTab', Object => $RT::System ) )
+    if ( $session{'CurrentUser'}->HasRight( Right => 'ShowApprovalsTab', Object => RT->System ) )
     {
         $tools->child( approval => title => loc('Approval'), path     => '/Approvals/', sort_order=> 3,
                        description => loc('My Approvals') );
     }
 
-    if ( $session{'CurrentUser'}->HasRight( Right => 'ShowConfigTab', Object => $RT::System ) )
+    if ( $session{'CurrentUser'}->HasRight( Right => 'ShowConfigTab', Object => RT->System ) )
     {
         my $admin = $tools->child( config => title => loc('Configuration'), path   => '/Admin/', sort_order => 1 );
-        if ( $session{'CurrentUser'}->HasRight( Object => $RT::System, Right => 'AdminUsers' ) ) {
+        if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminUsers' ) ) {
             my $users = $admin->child( users => title => loc('Users'), path => '/Admin/Users/', description => loc('Manage users and passwords') );
             $users->child( select => title => loc('Select'), path   => "/Admin/Users/" );
             $users->child( create => title => loc('Create'), path => "/Admin/Users/Modify.html?Create=1" );
@@ -143,7 +143,7 @@ if ( $request_path !~ m{^/SelfService/} ) {
         $queues->child( select => title => loc('Select'), path => "/Admin/Queues/" );
         $queues->child( create => title => loc('Create'), path => "/Admin/Queues/Modify.html?Create=1" );
 
-        if ( $session{'CurrentUser'}->HasRight( Object => $RT::System, Right => 'AdminCustomField' ) ) {
+        if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminCustomField' ) ) {
             my $cfs = $admin->child( 'custom-fields' => title => loc('Custom Fields'), path => '/Admin/CustomFields/', description => loc('Manage custom fields and custom field values') );
             $cfs->child( select => title => loc('Select'), path   => "/Admin/CustomFields/" );
             $cfs->child( create => title => loc('Create'), path => "/Admin/CustomFields/Modify.html?Create=1" );
@@ -208,7 +208,7 @@ if ( $request_path !~ m{^/SelfService/} ) {
         $admin_tools->child( configuration => title => loc('System Configuration'), path => '/Admin/Tools/Configuration.html',
                              description => loc('Detailed information about your RT setup') );
         if (RT->Config->Get('StatementLog')
-            && $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => $RT::System )) {
+            && $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System )) {
            $admin_tools->child( 'sql-queries' => title => loc('SQL Queries'), path => '/Admin/Tools/Queries.html',
                                 description => loc('Browse the SQL queries made in this process') );
         }
@@ -224,7 +224,7 @@ if ( $request_path !~ m{^/SelfService/} ) {
 
 
     if ( $session{'CurrentUser'}->UserObj
-         && $session{'CurrentUser'}->HasRight( Right  => 'ModifySelf', Object => $RT::System )) {
+         && $session{'CurrentUser'}->HasRight( Right  => 'ModifySelf', Object => RT->System )) {
         my $settings = $about_me->child( settings => title => loc('Settings'), path => '/Prefs/Other.html', );
         $settings->child( options => title => loc('Options'), path     => '/Prefs/Other.html', );
         $settings->child( about_me => title => loc('About me'), path     => '/User/Prefs.html', );
@@ -636,7 +636,7 @@ if ( $request_path !~ m{^/SelfService/} ) {
 
             if ($request_path =~ m{^/Search/Results.html}
                 &&                        #XXX TODO better abstraction
-                $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => $RT::System )) {
+                $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System )) {
                 my $shred_args = $query_string->(
                     search          => 1,
                     plugin          => 'Tickets',
@@ -727,7 +727,7 @@ if ( $request_path =~ m{^/SelfService} ) {
                     sort_order   => 99
     );
 
-    if ( $session{'CurrentUser'}->HasRight( Right => 'ModifySelf', Object => $RT::System ) ) {
+    if ( $session{'CurrentUser'}->HasRight( Right => 'ModifySelf', Object => RT->System ) ) {
         $about_me->child( prefs => title => loc('Preferences'), path  => '/SelfService/Prefs.html' );
     }
 
@@ -737,7 +737,7 @@ if ( $request_path =~ m{^/SelfService} ) {
         $about_me->child( logout => title => loc('Logout'), path   => '/NoAuth/Logout.html' );
     }
 
-    if ($session{'CurrentUser'}->HasRight( Right => 'ShowArticle', Object => $RT::System )) {
+    if ($session{'CurrentUser'}->HasRight( Right => 'ShowArticle', Object => RT->System )) {
         PageWidgets->child( 'goto-article' => raw_html => $m->scomp('/SelfService/Elements/SearchArticle') );
     }
 

commit b7b86fea30a33cae2894ac09455c94bd04666821
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Mon Dec 20 19:11:36 2010 -0500

    Privileged and Unprivileged groups should change about as often as
    SystemUser and Nobody. cache them in the RT process

diff --git a/lib/RT.pm b/lib/RT.pm
index 0d5c823..47725ba 100755
--- a/lib/RT.pm
+++ b/lib/RT.pm
@@ -55,7 +55,7 @@ package RT;
 use File::Spec ();
 use Cwd ();
 
-use vars qw($Config $System $SystemUser $Nobody $Handle $Logger $_INSTALL_MODE);
+use vars qw($Config $System $SystemUser $Nobody $Handle $Logger $_Privileged $_Unprivileged $_INSTALL_MODE);
 
 use vars qw($BasePath
  $EtcPath
@@ -550,6 +550,23 @@ also L</InitSystemObjects>.
 
 sub Nobody { return $Nobody }
 
+sub PrivilegedUsers {
+    if (!$_Privileged) {
+    $_Privileged = RT::Group->new(RT->SystemUser);
+    $_Privileged->LoadSystemInternalGroup('Privileged');
+    }
+    return $_Privileged;
+}
+
+sub UnprivilegedUsers {
+    if (!$_Unprivileged) {
+    $_Unprivileged = RT::Group->new(RT->SystemUser);
+    $_Unprivileged->LoadSystemInternalGroup('Unprivileged');
+    }
+    return $_Unprivileged;
+}
+
+
 =head2 Plugins
 
 Returns a listref of all Plugins currently configured for this RT instance.
diff --git a/lib/RT/Interface/Email/Auth/MailFrom.pm b/lib/RT/Interface/Email/Auth/MailFrom.pm
index d483202..a15f746 100755
--- a/lib/RT/Interface/Email/Auth/MailFrom.pm
+++ b/lib/RT/Interface/Email/Auth/MailFrom.pm
@@ -77,8 +77,7 @@ sub GetCurrentUser {
     }
 
     # If the user can't be loaded, we may need to create one. Figure out the acl situation.
-    my $unpriv = RT::Group->new( RT->SystemUser );
-    $unpriv->LoadSystemInternalGroup('Unprivileged');
+    my $unpriv = RT->UnprivilegedUsers();
     unless ( $unpriv->Id ) {
         $RT::Logger->crit("Couldn't find the 'Unprivileged' internal group");
         return ( $args{'CurrentUser'}, -1 );
diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 1bf2efd..6774779 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -2475,9 +2475,7 @@ sub GetPrincipalsMap {
             ];
         }
         elsif (/Users/) {
-            my $Privileged = RT::Group->new($session{'CurrentUser'});
-            $Privileged->LoadSystemInternalGroup('Privileged');
-            my $Users = $Privileged->UserMembersObj();
+            my $Users = RT->PrivilegedUsers->UserMembersObj();
             $Users->OrderBy( FIELD => 'Name', ORDER => 'ASC' );
 
             # Only show users who have rights granted on this object
diff --git a/lib/RT/User_Overlay.pm b/lib/RT/User_Overlay.pm
index d7ef799..6b95929 100755
--- a/lib/RT/User_Overlay.pm
+++ b/lib/RT/User_Overlay.pm
@@ -367,9 +367,7 @@ Returns true if this user is privileged. Returns undef otherwise.
 
 sub Privileged {
     my $self = shift;
-    my $priv = RT::Group->new($self->CurrentUser);
-    $priv->LoadSystemInternalGroup('Privileged');
-    if ( $priv->HasMember( $self->PrincipalId ) ) {
+    if ( RT->PrivilegedUsers->HasMember( $self->id ) ) {
         return(1);
     } else {
         return(undef);
diff --git a/lib/RT/Users_Overlay.pm b/lib/RT/Users_Overlay.pm
index 5db7770..62b654a 100755
--- a/lib/RT/Users_Overlay.pm
+++ b/lib/RT/Users_Overlay.pm
@@ -200,13 +200,7 @@ Limits to users who can be made members of ACLs and groups
 
 sub LimitToPrivileged {
     my $self = shift;
-
-    my $priv = RT::Group->new( $self->CurrentUser );
-    $priv->LoadSystemInternalGroup('Privileged');
-    unless ( $priv->Id ) {
-        $RT::Logger->crit("Couldn't find a privileged users group");
-    }
-    $self->MemberOfGroup( $priv->PrincipalId );
+    $self->MemberOfGroup( RT->PrivilegedUsers->id );
 }
 
 =head2 LimitToUnprivileged
@@ -217,13 +211,7 @@ Limits to unprivileged users only
 
 sub LimitToUnprivileged {
     my $self = shift;
-
-    my $unpriv = RT::Group->new( $self->CurrentUser );
-    $unpriv->LoadSystemInternalGroup('Unprivileged');
-    unless ( $unpriv->Id ) {
-        $RT::Logger->crit("Couldn't find an 'Unprivileged' users group");
-    }
-    $self->MemberOfGroup( $unpriv->PrincipalId );
+    $self->MemberOfGroup( RT->UnprivilegedUsers->id);
 }
 
 

commit 6b24639e1152acb91878bb4cbdcdac7bd705a89f
Author: Shawn M Moore <sartak at bestpractical.com>
Date:   Mon Dec 20 20:10:43 2010 -0500

    Better Mason-generated stack traces for SQL Queries

diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index e745b59..5f380be 100755
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -1123,6 +1123,18 @@ sub FillIn {
     return $sql;
 }
 
+# log a mason stack trace instead of a Carp::longmess because it's less painful
+# and uses mason component paths properly
+sub _LogSQLStatement {
+    my $self = shift;
+    my $statement = shift;
+    my $duration = shift;
+    my @bind = @_;
+
+    require HTML::Mason::Exceptions;
+    push @{$self->{'StatementLog'}} , ([Time::HiRes::time(), $statement, [@bind], $duration, HTML::Mason::Exception->new->as_string]);
+}
+
 __PACKAGE__->FinalizeDatabaseType;
 
 RT::Base->_ImportOverlays();
diff --git a/t/web/query_log.t b/t/web/query_log.t
index 25edfd2..e19f44d 100644
--- a/t/web/query_log.t
+++ b/t/web/query_log.t
@@ -14,7 +14,7 @@ $root->LoadByEmail('root at localhost');
 
 $m->get_ok("/Admin/Tools/Queries.html");
 $m->text_contains("/index.html", "we include info about a page we hit while logging in");
-$m->text_contains("Executed SQL query at", "stack traces");
-$m->text_like(qr/HTML::Mason::Interp::exec\(.*\) called at/, "stack traces");
+$m->text_contains("Stack:", "stack traces");
+$m->text_like(qr{share/html/autohandler:\d+}, "stack trace includes mason components");
 $m->text_contains("SELECT * FROM Principals WHERE id = '".$root->id."'", "we interpolate bind params");
 

commit 94bed282b184c41104a7cce7803dc9bb7771e298
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Tue Dec 21 13:54:05 2010 +0800

    make sure to require Module::Refresh in devel mode

diff --git a/sbin/rt-server.in b/sbin/rt-server.in
index 97ad46a..ff7c993 100755
--- a/sbin/rt-server.in
+++ b/sbin/rt-server.in
@@ -85,6 +85,7 @@ if (grep { m/help/ } @ARGV) {
 
 require RT;
 RT->LoadConfig();
+require Module::Refresh if RT->Config->Get('DevelMode');
 
 require RT::Handle;
 my ($integrity, $state, $msg) = RT::Handle->CheckIntegrity;
@@ -119,7 +120,6 @@ EOF
     RT->InstallMode(1);
 } else {
     RT->Init();
-    if (RT->Config->Get('DevelMode')) { require Module::Refresh; }
 
     my ($status, $msg) = RT::Handle->CheckCompatibility( $RT::Handle->dbh, 'post');
     unless ( $status ) {

commit 6da0ceebc1d3a0c669fbcb91466383fb4f369fc3
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Tue Dec 21 14:11:20 2010 +0800

    tweak bind error msg: we need to know the right port number

diff --git a/sbin/rt-server.in b/sbin/rt-server.in
index ff7c993..8b19c22 100755
--- a/sbin/rt-server.in
+++ b/sbin/rt-server.in
@@ -174,7 +174,17 @@ my $r = Plack::Runner->new( $0 =~ 'standalone' ? ( server => 'Standalone' ) :
                                                : (),
                             env => 'deployment' );
 my @args = @ARGV;
-push @args, '--port', $port unless grep { m/--port/ } @args;
+
+use List::MoreUtils 'last_index';
+my $last_index = last_index { $_ eq '--port' } @args; 
+
+if ( $last_index != -1 && $args[$last_index+1] =~ /^\d+$/ ) {
+    $port = $args[$last_index+1];
+}
+else {
+    push @args, '--port', $port;
+}
+
 push @args, '--server', 'Standalone' if RT->InstallMode;
 push @args, '--server', 'Starlet' unless $r->{server} || grep { m/--server/ } @args;
 
@@ -214,8 +224,8 @@ sub handle_bind_error {
 
     print STDERR <<EOF;
 WARNING: RT couldn't start up a web server on port @{[$port]}.
-This is often the case if you're running @{[$0]} as 
-someone other than your system's "root" user.  You may also specify a
+This is often the case if the port is already in use or you're running @{[$0]} 
+as someone other than your system's "root" user.  You may also specify a
 temporary port with: $0 --port <port>
 EOF
 

commit 167f010914fffc9468b599b38ea070e9171ade70
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Dec 21 16:46:56 2010 +0300

    use strict and warnings in all lib/RT/I18N/*.pm

diff --git a/lib/RT/I18N/cs.pm b/lib/RT/I18N/cs.pm
index c81f9c7..e84e20f 100755
--- a/lib/RT/I18N/cs.pm
+++ b/lib/RT/I18N/cs.pm
@@ -46,6 +46,9 @@
 #
 # END BPS TAGGED BLOCK }}}
 
+use strict;
+use warnings;
+
 package RT::I18N::cs;
 
 # # CZECH TRANSLATORS COMMENTS see Locale::Maketext::TPJ13
diff --git a/lib/RT/I18N/i_default.pm b/lib/RT/I18N/i_default.pm
index 4b5a892..17d1705 100755
--- a/lib/RT/I18N/i_default.pm
+++ b/lib/RT/I18N/i_default.pm
@@ -46,9 +46,11 @@
 #
 # END BPS TAGGED BLOCK }}}
 
+use strict;
+use warnings;
+
 package RT::I18N::i_default;
 use base 'RT::I18N';
-use strict;
 
 RT::Base->_ImportOverlays();
 
diff --git a/lib/RT/I18N/ru.pm b/lib/RT/I18N/ru.pm
index 82b7675..15aecf3 100755
--- a/lib/RT/I18N/ru.pm
+++ b/lib/RT/I18N/ru.pm
@@ -46,6 +46,9 @@
 #
 # END BPS TAGGED BLOCK }}}
 
+use strict;
+use warnings;
+
 package RT::I18N::ru;
 
 sub quant {

commit 7daa4b7b8b4eb0e4ed0a8bb60631d0ba9f84a2da
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Dec 21 16:47:34 2010 +0300

    custom <language>.pm files should inherit from RT::I18N

diff --git a/lib/RT/I18N/cs.pm b/lib/RT/I18N/cs.pm
index e84e20f..01de07b 100755
--- a/lib/RT/I18N/cs.pm
+++ b/lib/RT/I18N/cs.pm
@@ -50,6 +50,7 @@ use strict;
 use warnings;
 
 package RT::I18N::cs;
+use base 'RT::I18N';
 
 # # CZECH TRANSLATORS COMMENTS see Locale::Maketext::TPJ13
 # Obecne parametry musi byt docela slozite (v pripade Slavistickych jazyku)
diff --git a/lib/RT/I18N/ru.pm b/lib/RT/I18N/ru.pm
index 15aecf3..40e99cf 100755
--- a/lib/RT/I18N/ru.pm
+++ b/lib/RT/I18N/ru.pm
@@ -50,6 +50,7 @@ use strict;
 use warnings;
 
 package RT::I18N::ru;
+use base 'RT::I18N';
 
 sub quant {
     my($handle, $num, @forms) = @_;

commit 070ae0bee2695a3f528cb01fbacc43e712831746
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Dec 21 16:48:29 2010 +0300

    load overlays in RT::I18N::*

diff --git a/lib/RT/I18N/cs.pm b/lib/RT/I18N/cs.pm
index 01de07b..b7c6f8f 100755
--- a/lib/RT/I18N/cs.pm
+++ b/lib/RT/I18N/cs.pm
@@ -117,4 +117,6 @@ sub numf {
   return $num;
 }
 
+RT::Base->_ImportOverlays();
+
 1;
diff --git a/lib/RT/I18N/ru.pm b/lib/RT/I18N/ru.pm
index 40e99cf..b7b58be 100755
--- a/lib/RT/I18N/ru.pm
+++ b/lib/RT/I18N/ru.pm
@@ -75,4 +75,6 @@ sub numerate {
     return $forms[$form];
 }
 
+RT::Base->_ImportOverlays();
+
 1;

commit 6ff5f1463d445738305e32d959f4932eff3bf3f3
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Dec 21 17:06:22 2010 +0300

    magic title generating makes no sense when you have lifecycles

diff --git a/share/html/Ticket/Update.html b/share/html/Ticket/Update.html
index e8f05bf..9664e16 100755
--- a/share/html/Ticket/Update.html
+++ b/share/html/Ticket/Update.html
@@ -203,7 +203,6 @@
 my $CanRespond = 0;
 my $CanComment = 0;
 my $checks_failure = 0;
-my $title;
 
 my $TicketObj = LoadTicket($id);
 
@@ -215,11 +214,7 @@ unless($DefaultStatus){
     $DefaultStatus=($ARGS{'Status'} ||$TicketObj->Status());
 }
 
-if ($DefaultStatus eq 'resolved') {
-    $title = loc("Resolve ticket #[_1] ([_2])", $TicketObj->id, $TicketObj->Subject);
-} else {
-    $title = loc("Update ticket #[_1] ([_2])", $TicketObj->id, $TicketObj->Subject);
-}
+my $title = loc("Update ticket #[_1] ([_2])", $TicketObj->id, $TicketObj->Subject);
 
 # Things needed in the template - we'll do the processing here, just
 # for the convenience:

commit 3363415fc3fbdf09695b3b884dab15b3b5097096
Author: Christian Loos <cloos at netcologne.de>
Date:   Fri Dec 17 18:15:45 2010 +0100

    more consistent marking of squelched people
    
    This fixes that on Display.html within block People it says only
    'squelched' and on ModifyPeople.html it says 'Will not be sent email'.

diff --git a/lib/RT/User_Overlay.pm b/lib/RT/User_Overlay.pm
index 6b95929..bd71487 100755
--- a/lib/RT/User_Overlay.pm
+++ b/lib/RT/User_Overlay.pm
@@ -613,7 +613,7 @@ sub EmailFrequency {
     return '' unless $self->id && $self->id != RT->Nobody->id
         && $self->id != RT->SystemUser->id;
     return 'no email' unless my $email = $self->EmailAddress;
-    return 'squelched' if $args{'Ticket'} &&
+    return 'Will not be sent email' if $args{'Ticket'} &&
         grep lc $email eq lc $_->Content, $args{'Ticket'}->SquelchMailTo;
     my $frequency = RT->Config->Get( 'EmailFrequency', $self ) || '';
     return 'daily' if $frequency =~ /daily/i;
diff --git a/share/html/Ticket/Elements/EditWatchers b/share/html/Ticket/Elements/EditWatchers
index 0c27e3f..9ed611e 100755
--- a/share/html/Ticket/Elements/EditWatchers
+++ b/share/html/Ticket/Elements/EditWatchers
@@ -58,11 +58,7 @@
 <input type="checkbox" class="checkbox" name="Ticket-DeleteWatcher-Type-<% $Watchers->Type %>-Principal-<% $watcher->MemberId %>" value="1" unchecked />
 % if ( $member->isa( 'RT::User' ) ) { 
 <a href="<% RT->Config->Get('WebPath') %>/Admin/Users/Modify.html?id=<% $watcher->MemberId %>">
-<& /Elements/ShowUser, User => $member &></a>
-% if ($TicketObj and grep { $_->Content eq $member->EmailAddress } $TicketObj->SquelchMailTo)  {
-<b><&|/l&>(Will not be sent email)</&></b>
-% }
-
+<& /Elements/ShowUser, User => $member &></a> <& /Elements/ShowUserEmailFrequency, User => $member, Ticket => $TicketObj &>
 % } else {
 <a href="<% RT->Config->Get('WebPath') %>/Admin/Groups/Modify.html?id=<% $watcher->MemberId %>">
 <% $member->Name %></a>

commit e2eea72b51bf5b11e853715cd1b9ac802b7df02e
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Dec 21 17:46:53 2010 +0300

    more descriptive email frequency

diff --git a/lib/RT/User_Overlay.pm b/lib/RT/User_Overlay.pm
index bd71487..04fddd9 100755
--- a/lib/RT/User_Overlay.pm
+++ b/lib/RT/User_Overlay.pm
@@ -612,8 +612,8 @@ sub EmailFrequency {
     );
     return '' unless $self->id && $self->id != RT->Nobody->id
         && $self->id != RT->SystemUser->id;
-    return 'no email' unless my $email = $self->EmailAddress;
-    return 'Will not be sent email' if $args{'Ticket'} &&
+    return 'no email address' unless my $email = $self->EmailAddress;
+    return 'email disabled for ticket' if $args{'Ticket'} &&
         grep lc $email eq lc $_->Content, $args{'Ticket'}->SquelchMailTo;
     my $frequency = RT->Config->Get( 'EmailFrequency', $self ) || '';
     return 'daily' if $frequency =~ /daily/i;

commit 1f178f89ace5f093f570e557a598d78a601d6b47
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 10:37:48 2010 -0500

    Change $RT::System to RT->System in the theme editor

diff --git a/share/html/Admin/Global/Theme.html b/share/html/Admin/Global/Theme.html
index d99058c..f3fa3ba 100644
--- a/share/html/Admin/Global/Theme.html
+++ b/share/html/Admin/Global/Theme.html
@@ -194,7 +194,7 @@ eval { require Imager; require Convert::Color; 1 };
 
 my $img;
 if (my $file_hash = _UploadedFile( 'logo-upload' )) {
-    my ($id, $msg) = $RT::System->SetAttribute( Name => "UserLogo",
+    my ($id, $msg) = RT->System->SetAttribute( Name => "UserLogo",
                                                 Description => "User-provided logo",
                                                 Content => {
                                                     type => $file_hash->{ContentType},
@@ -208,10 +208,10 @@ if (my $file_hash = _UploadedFile( 'logo-upload' )) {
     }
 }
 elsif ($ARGS{'reset_logo'}) {
-    $RT::System->DeleteAttribute('UserLogo');
+    RT->System->DeleteAttribute('UserLogo');
 }
 else {
-    if (my $attr = $RT::System->FirstAttribute('UserLogo')) {
+    if (my $attr = RT->System->FirstAttribute('UserLogo')) {
         my $content = $attr->Content;
         if (ref($content) eq 'HASH') {
             $img = Imager->new;
@@ -221,18 +221,18 @@ else {
             }
         }
         else {
-            $RT::System->DeleteAttribute('UserLogo');
+            RT->System->DeleteAttribute('UserLogo');
         }
     }
 }
 
 if ($user_css) {
     if ($ARGS{'reset_css'}) {
-        $RT::System->DeleteAttribute('UserCSS');
+        RT->System->DeleteAttribute('UserCSS');
         undef $user_css;
     }
     else {
-        my ($id, $msg) = $RT::System->SetAttribute( Name => "UserCSS",
+        my ($id, $msg) = RT->System->SetAttribute( Name => "UserCSS",
                                                     Description => "User-provided css",
                                                     Content => $user_css );
         push @results, loc("Unable to set UserCSS: [_1]", $msg) unless $id;
@@ -240,7 +240,7 @@ if ($user_css) {
 }
 
 if (!$user_css) {
-    my $attr = $RT::System->FirstAttribute('UserCSS');
+    my $attr = RT->System->FirstAttribute('UserCSS');
     $user_css = $attr ? $attr->Content : join(
         "\n\n" => map {
             join "\n" => "/* ". $_->[0] ." */",

commit bd88cfb8a416c4d60e8950abc01ee3eb60404646
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 10:53:08 2010 -0500

    Move UserCSS into an inline <style> block
    
    Resolves [rt3 #16263].  This helps avoid caching problems and it should
    never be a huge chunk of content.  The theme editor can now just use the
    existing style block instead of creating it's own.

diff --git a/share/html/Admin/Global/Theme.html b/share/html/Admin/Global/Theme.html
index f3fa3ba..160be19 100644
--- a/share/html/Admin/Global/Theme.html
+++ b/share/html/Admin/Global/Theme.html
@@ -53,7 +53,6 @@
 <& /Elements/ListActions, actions => \@results &>
 
 <script type="text/javascript" src="<%RT->Config->Get('WebPath')%>/NoAuth/js/farbtastic.js"></script>
-<style type="text/css" id="test"></style>
 
 <div id="simple-customize">
 <div id="upload-logo">
@@ -128,14 +127,14 @@ jQuery(function($) {
                            .text(v[0]));
     });
 
-    $("style#test").text($('#user_css').val());
+    $("style#sitecss").text($('#user_css').val());
     $('#try').click(function() {
-        $("style#test").text($('#user_css').val());
+        $("style#sitecss").text($('#user_css').val());
     });
 
     $('#reset').click(function() {
         setTimeout(function() {
-          $("style#test").text($('#user_css').val());
+          $("style#sitecss").text($('#user_css').val());
         }, 1000);
     });
 
@@ -171,7 +170,7 @@ jQuery(function($) {
           }
       }
       $('#user_css').val(css);
-      $("style#test").text(css);
+      $("style#sitecss").text(css);
     }
 
     $('#color-picker').farbtastic(function(color){ change_color(color, this.hsl[2] > <% $text_threshold %> ? '#000' : '#fff') });
diff --git a/share/html/Elements/Header b/share/html/Elements/Header
index c7fdf30..160d4f8 100755
--- a/share/html/Elements/Header
+++ b/share/html/Elements/Header
@@ -57,7 +57,6 @@
 
 <link rel="shortcut icon" href="<%RT->Config->Get('WebImagesURL')%>/favicon.png" type="image/png" />
 <link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/<% $style_path %>" type="text/css" media="all" />
-<link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/site.css" type="text/css" media="all" />
 <link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/print.css" type="text/css" media="print" />
 
 % for (keys %{$LinkRel || {}}) {
@@ -77,6 +76,13 @@
 <& $stylesheet_plugin &>
 % }
 
+<!-- Site CSS from theme editor -->
+<style type="text/css" media="all" id="sitecss">
+% if (my $attr = RT->System->FirstAttribute('UserCSS')) {
+<% $attr->Content |n %>
+% }
+</style>
+
 % $m->callback( %ARGS, CallbackName => 'Head' );
 
 </head>
diff --git a/share/html/NoAuth/css/site.css b/share/html/NoAuth/css/site.css
deleted file mode 100644
index 491609b..0000000
--- a/share/html/NoAuth/css/site.css
+++ /dev/null
@@ -1,4 +0,0 @@
-% if (my $attr = $RT::System->FirstAttribute('UserCSS')) {
-<% $attr->Content |n%>
-% }
-% $m->abort();

commit e5e762ace8129bc9de7515ce3763d7faded779e6
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 11:53:18 2010 -0500

    Make sure we don't output two doctypes for RT at a Glance
    
    This also updates the doctype for RT at a Glance.

diff --git a/share/html/Elements/Header b/share/html/Elements/Header
index 160d4f8..34a3ac7 100755
--- a/share/html/Elements/Header
+++ b/share/html/Elements/Header
@@ -45,7 +45,10 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
+%# index.html gets two doctypes unless we can skip it here
+% unless ($SkipDoctype) {
 <!DOCTYPE html>
+% }
 
 <html lang="en">
   <head>
@@ -135,4 +138,5 @@ $RSSAutoDiscovery => undef
 $onload => undef
 $LinkRel => undef
 $JavaScript => 1
+$SkipDoctype => 0
 </%ARGS>
diff --git a/share/html/index.html b/share/html/index.html
index 24cc9da..64a4117 100755
--- a/share/html/index.html
+++ b/share/html/index.html
@@ -1,9 +1,7 @@
-<!DOCTYPE html 
-     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html>
 <!--
 % $m->out('--'.'>');
-% $m->comp('/Elements/Header', Title=>loc("RT at a glance"), Refresh => $session{'home_refresh_interval'}||RT->Config->Get('HomePageRefreshInterval', $session{'CurrentUser'} ));
+% $m->comp('/Elements/Header', Title=>loc("RT at a glance"), Refresh => $session{'home_refresh_interval'}||RT->Config->Get('HomePageRefreshInterval', $session{'CurrentUser'}), SkipDoctype => 1 );
 % if (0) {
 %# -->
 <html><head>

commit 47fdd039da29e48e948e428b113f0bf1c630728f
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 13:19:17 2010 -0500

    Remove the submenus from the ListMenu display component. They were way
    too cluttering

diff --git a/share/html/Elements/ListMenu b/share/html/Elements/ListMenu
index ed1cffa..891ee78 100644
--- a/share/html/Elements/ListMenu
+++ b/share/html/Elements/ListMenu
@@ -54,13 +54,6 @@ $menu
 % if ( my $description = $child->description ) {
 <span class="description"><% $description %></span>\
 % }
-% if ( $child->has_children ) {
-<ul>
-% for my $grand ($child->children) {
-<li><% $show_link->( $grand ) |n %></li>
-% }
-</ul>
-% }
 </li>
 % }
 </ul>

commit 4cac51a6eac58760d03dc74d8ce05adf4c303457
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 13:22:08 2010 -0500

    Remove the embarassingly outdated "Reports" menus. We have much better
    built in reporting today.  The menu will be resurrected when we have
    something useful to put under the tab

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 045e77b..06a780a 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -99,15 +99,6 @@ if ( $request_path !~ m{^/SelfService/} ) {
     $articles->child( articles => title => loc('Articles') => path => "/Articles/index.html" );
     $articles->child( topics   => title => loc('Topics') => path => "/Articles/Topics.html" );
 
-    my $reports = $tools->child( reports => title => loc('Reports'), path => '/Tools/Reports/index.html', sort_order => 4,
-                                 description => loc('Various RT reports') );
-    $reports->child( loc('Resolved by owner'), path => '/Tools/Reports/ResolvedByOwner.html',
-        description => loc('Examine tickets resolved in a queue, grouped by owner'), );
-    $reports->child( loc('Resolved in date range'), path => '/Tools/Reports/ResolvedByDates.html',
-        description => loc('Examine tickets resolved in a queue between two dates'), );
-    $reports->child( loc('Created in a date range'), path => '/Tools/Reports/CreatedByDates.html',
-        description => loc('Examine tickets created in a queue between two dates'), );
-
     $tools->child( my_day => title => loc('My Day'), path   => '/Tools/MyDay.html', sort_order => 5,
                    description => loc('Easy updating of your open tickets') );
 
diff --git a/share/html/Tools/Reports/CreatedByDates.html b/share/html/Tools/Reports/CreatedByDates.html
deleted file mode 100644
index 3b446a2..0000000
--- a/share/html/Tools/Reports/CreatedByDates.html
+++ /dev/null
@@ -1,94 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2010 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 }}}
-<%args>
-$Queue => undef
-$CreatedBefore => undef
-$CreatedAfter => undef
-</%args>
-<%init>
-my $title = loc("Created tickets in period, grouped by status");
-my $q = RT::Queue->new($session{'CurrentUser'});
-my $before = RT::Date->new($session{'CurrentUser'});
-my $after = RT::Date->new($session{'CurrentUser'});
-my $query = 'Status != "deleted" ';
-
-
-if ($CreatedAfter) {
-    $after->Set(Format => 'unknown', Value => $CreatedAfter);
-    $CreatedAfter = $after->AsString;
-}
-if ($CreatedBefore) {
-    $before->Set(Format => 'unknown', Value => $CreatedBefore);
-    $CreatedBefore = $before->AsString;
-}
-
-
-$q->LoadByCols(Name => $Queue);
-</%init>
-<& /Elements/Header, Title => $title &>
-<& /Elements/Tabs &>
-<form method="post" action="CreatedByDates.html">
-% if ($Queue|| $CreatedBefore ||$CreatedAfter) {
-% # if we have a queue, do the search
-% if ($Queue) { $query .= " AND Queue = '$Queue'"}
-% if ($CreatedBefore) { $query .= " AND Created < '".$before->ISO(Timezone => 'user') ."'"; }
-% if ($CreatedAfter) { $query .= " AND Created > '".$after->ISO(Timezone => 'user')."'"}
-% my $groupby = 'Status';
-<& /Search/Elements/Chart, Query => $query, PrimaryGroupBy => $groupby &>
-% }
-
-<hr />
-
-<br /><&|/l&>Queue</&>: <& /Elements/SelectQueue, Name => 'Queue', NamedValues => 1, Default => $q->id &>
-<br /><&|/l&>Tickets created after</&>: 
-<& /Elements/SelectDate, Name => 'CreatedAfter', Default => ($CreatedAfter) ?  $after->ISO(Timezone => 'user') : ''&>
-<br /><&|/l&>Tickets created before</&>: 
-<& /Elements/SelectDate, Name => 'CreatedBefore', Default => ($CreatedBefore) ? $before->ISO(Timezone => 'user') : ''&>
-
-<& /Elements/Submit&>
-</form>
diff --git a/share/html/Tools/Reports/ResolvedByDates.html b/share/html/Tools/Reports/ResolvedByDates.html
deleted file mode 100644
index 2c9e992..0000000
--- a/share/html/Tools/Reports/ResolvedByDates.html
+++ /dev/null
@@ -1,95 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2010 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 }}}
-<%args>
-$Queue => undef
-$ResolvedBefore => undef
-$ResolvedAfter => undef
-</%args>
-<%init>
-my $title = loc("Resolved tickets in period, grouped by owner");
-my $q = RT::Queue->new($session{'CurrentUser'});
-my $before = RT::Date->new($session{'CurrentUser'});
-my $after = RT::Date->new($session{'CurrentUser'});
-my $query = '';
-
-
-if ($ResolvedAfter) {
-    $after->Set(Format => 'unknown', Value => $ResolvedAfter);
-    $ResolvedAfter = $after->AsString;
-}
-if ($ResolvedBefore) {
-    $before->Set(Format => 'unknown', Value => $ResolvedBefore);
-    $ResolvedBefore = $before->AsString;
-}
-
-
-$q->LoadByCols(Name => $Queue);
-</%init>
-<& /Elements/Header, Title => $title &>
-<& /Elements/Tabs &>
-<form method="post" action="ResolvedByDates.html">
-% if ($Queue|| $ResolvedBefore ||$ResolvedAfter) {
-% # if we have a queue, do the search
-% $query = "Status = 'resolved'";
-% if ($Queue) { $query .= " AND Queue = '$Queue'"}
-% if ($ResolvedBefore) { $query .= " AND Resolved < '".$before->ISO(Timezone => 'user')."'"; }
-% if ($ResolvedAfter) { $query .= " AND Resolved > '".$after->ISO(Timezone => 'user')."'"}
-% my $groupby = 'Owner';
-<& /Search/Elements/Chart, Query => $query, PrimaryGroupBy => $groupby &>
-% }
-
-<hr />
-
-<br /><&|/l&>Queue</&>: <& /Elements/SelectQueue, Name => 'Queue', NamedValues => 1, Default => $q->id &>
-<br /><&|/l&>Tickets resolved after</&>: 
-<& /Elements/SelectDate, Name => 'ResolvedAfter', Default => ($ResolvedAfter) ? $after->ISO(Timezone => 'user') : ''&>
-<br /><&|/l&>Tickets resolved before</&>: 
-<& /Elements/SelectDate, Name => 'ResolvedBefore', Default => ($ResolvedBefore) ? $before->ISO(Timezone => 'user') : ''&>
-
-<& /Elements/Submit&>
-</form>
diff --git a/share/html/Tools/Reports/ResolvedByOwner.html b/share/html/Tools/Reports/ResolvedByOwner.html
deleted file mode 100644
index 77447ab..0000000
--- a/share/html/Tools/Reports/ResolvedByOwner.html
+++ /dev/null
@@ -1,70 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2010 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 }}}
-<%args>
-$Queue => undef
-</%args>
-<%init>
-my $title = loc("Resolved tickets, grouped by owner");
-my $q = RT::Queue->new($session{'CurrentUser'});
-$q->LoadByCols(Name => $Queue);
-</%init>
-<& /Elements/Header, Title => $title &>
-<& /Elements/Tabs &>
-<form method="post" action="ResolvedByOwner.html">
-% if ($Queue) {
-% # if we have a queue, do the search
-% my $query = "Status = 'resolved' AND Queue = '$Queue'";
-% my $groupby = 'Owner';
-<& /Search/Elements/Chart, Query => $query, PrimaryGroupBy => $groupby &>
-% }
-
-<hr />
-
-<&|/l&>Queue</&>: <& /Elements/SelectQueue, Name => 'Queue', NamedValues => 1, Default => $q->id &>
-<& /Elements/Submit&>
-</form>
diff --git a/share/html/Tools/Reports/index.html b/share/html/Tools/Reports/index.html
deleted file mode 100644
index 4075263..0000000
--- a/share/html/Tools/Reports/index.html
+++ /dev/null
@@ -1,76 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2010 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 }}}
-<& /Elements/Header, Title => loc('Reports') &>
-<& /Elements/Tabs &>
-<& /Elements/ListMenu, menu => Menu()->child('tools')->child('reports') &>
-
-% $m->callback;
-
-<%init>
-
-my $tabs = {
-    A => {
-        title       => loc('Resolved by owner'),
-        path        => '/Tools/Reports/ResolvedByOwner.html',
-        description => loc('Examine tickets resolved in a queue, grouped by owner'),
-    },
-    B => {
-        title       => loc('Resolved in date range'),
-        path        => '/Tools/Reports/ResolvedByDates.html',
-        description => loc('Examine tickets resolved in a queue between two dates'),
-    },
-    C => {
-        title       => loc('Created in a date range'),
-        path        => '/Tools/Reports/CreatedByDates.html',
-        description => loc('Examine tickets created in a queue between two dates'),
-    },
-};
-
-$m->callback( CallbackName => 'ListReports', %ARGS, tabs => $tabs );
-
-</%init>
diff --git a/t/web/walk.t b/t/web/walk.t
index 2699daa..1986ed1 100644
--- a/t/web/walk.t
+++ b/t/web/walk.t
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 94;
+use RT::Test tests => 93;
 
 my ( $baseurl, $m ) = RT::Test->started_ok;
 
@@ -33,7 +33,7 @@ diag 'walk into /Tools' if $ENV{TEST_VERBOSE};
     $m->get_ok( $baseurl, 'homepage' );
     $m->follow_link_ok( { text => 'Tools' }, '-> Tools' );
 
-    for my $tab ( 'Dashboards', 'Offline', 'Reports', 'My Day' )
+    for my $tab ( 'Dashboards', 'Offline', 'My Day' )
     {
 
         $m->follow_link_ok( { text => $tab }, "-> $tab" );

commit f5286d08579619f07d6fa927eef175535b07fdbe
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 13:49:11 2010 -0500

    Slight cleanup to tools menu

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 06a780a..12e2db0 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -86,34 +86,39 @@ if ( $request_path !~ m{^/SelfService/} ) {
     $tickets->child( new => title => loc('New Search') => path => "/Search/Build.html?NewQuery=1" );
 
     my $tools = Menu->child(  tools => title => loc('Tools'), path => '/Tools/index.html' );
-    my $dashes = $tools->child( dashboards => title => loc('Dashboards'), path => '/Dashboards/index.html', sort_order => 2,
-                                description => loc('Named, shared collection of portlets') );
+
+
+    my $articles = $tools->child( articles => title => loc('Articles') => path => "/Articles/index.html");
+    $articles->child( articles => title => loc('Overview') => path => "/Articles/index.html" );
+    $articles->child( search   => title => loc('Search') => path => "/Articles/Article/Search.html" );
+    $articles->child( topics   => title => loc('Topics') => path => "/Articles/Topics.html" );
+
+
+
+
+    my $dashes = $tools->child( dashboards => title => loc('Dashboards'), path => '/Dashboards/index.html',
+                                description => loc('Custom reports online and by email') );
     $dashes->child( select => title => loc('Select'), path => "/Dashboards/index.html" );
     my $dashboard = RT::Dashboard->new( $session{CurrentUser} );
     if ( $dashboard->CurrentUserCanCreateAny ) {
         $dashes->child( loc('Create') => path => "/Dashboards/Modify.html?Create=1" );
     }
 
-    my $articles = $tools->child( articles => title => loc('Articles') => path => "/Articles/index.html", sort_order => 10 );
-    $articles->child( search   => title => loc('Search') => path => "/Articles/Article/Search.html" );
-    $articles->child( articles => title => loc('Articles') => path => "/Articles/index.html" );
-    $articles->child( topics   => title => loc('Topics') => path => "/Articles/Topics.html" );
-
-    $tools->child( my_day => title => loc('My Day'), path   => '/Tools/MyDay.html', sort_order => 5,
+    $tools->child( my_day => title => loc('My Day'), path   => '/Tools/MyDay.html',
                    description => loc('Easy updating of your open tickets') );
 
     if ( RT->Config->Get('EnableReminders') )
     {
-        $tools->child( my_reminders => title => loc('My Reminders'), path => '/Tools/MyReminders.html', sort_order => 6,
+        $tools->child( my_reminders => title => loc('My Reminders'), path => '/Tools/MyReminders.html',
                        description => loc('Easy viewing of your reminders') );
     }
 
-    $tools->child( offline => title => loc('Offline'), path    => '/Tools/Offline.html', sort_order => 10,
+    $tools->child( offline => title => loc('Offline'), path    => '/Tools/Offline.html',
                    description => loc('Create tickets offline') );
 
     if ( $session{'CurrentUser'}->HasRight( Right => 'ShowApprovalsTab', Object => RT->System ) )
     {
-        $tools->child( approval => title => loc('Approval'), path     => '/Approvals/', sort_order=> 3,
+        $tools->child( approval => title => loc('Approval'), path     => '/Approvals/',
                        description => loc('My Approvals') );
     }
 

commit 53b49d1275dc8a74f96da90bf0044f61e00c539a
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 13:49:27 2010 -0500

    Pill the Admin menus out into a sub

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 12e2db0..254997f 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -122,8 +122,8 @@ if ( $request_path !~ m{^/SelfService/} ) {
                        description => loc('My Approvals') );
     }
 
-    if ( $session{'CurrentUser'}->HasRight( Right => 'ShowConfigTab', Object => RT->System ) )
-    {
+
+my $build_admin_menu = sub {
         my $admin = $tools->child( config => title => loc('Configuration'), path   => '/Admin/', sort_order => 1 );
         if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminUsers' ) ) {
             my $users = $admin->child( users => title => loc('Users'), path => '/Admin/Users/', description => loc('Manage users and passwords') );
@@ -210,56 +210,6 @@ if ( $request_path !~ m{^/SelfService/} ) {
         }
         $admin_tools->child( shredder => title => loc('Shredder'), path => '/Admin/Tools/Shredder',
                              description => loc('Permanently wipeout data from RT'));
-    }
-
-    my $about_me = Menu->child( 'preferences' => title =>
-                        loc( 'Logged in as <span class="current-user">[_1]</span>', $session{'CurrentUser'}->Name),
-                    escape_title => 0,
-                    sort_order   => 99
-    );
-
-
-    if ( $session{'CurrentUser'}->UserObj
-         && $session{'CurrentUser'}->HasRight( Right  => 'ModifySelf', Object => RT->System )) {
-        my $settings = $about_me->child( settings => title => loc('Settings'), path => '/Prefs/Other.html', );
-        $settings->child( options => title => loc('Options'), path     => '/Prefs/Other.html', );
-        $settings->child( about_me => title => loc('About me'), path     => '/User/Prefs.html', );
-        $settings->child( search_options => title => loc('Search options'), path => '/Prefs/SearchOptions.html', );
-        $settings->child( myrt => title => loc('RT at a glance'), path => '/Prefs/MyRT.html', );
-        $settings->child( quicksearch => title => 'Quick search' => title => loc('Quick search'), path => '/Prefs/Quicksearch.html');
-
-        my $search_menu = $settings->child( 'saved-searches' => title => 'Saved Searches' );
-        my $searches = [ $m->comp( "/Search/Elements/SearchesForObject",
-                          Object => RT::System->new( $session{'CurrentUser'} )) ];
-        my $i = 0;
-
-        for my $search (@$searches) {
-            $search_menu->child( "search-" . $i++, title => $search->[0], path  => "/Prefs/Search.html?"
-                          . $query_string->( name => ref( $search->[1] ) . '-' . $search->[1]->Id),);
-
-        }
-    }
-    if ( $session{'CurrentUser'}->Name
-         && (   !RT->Config->Get('WebExternalAuth')
-              || RT->Config->Get('WebFallbackToInternalAuth') )) {
-        $about_me->child( logout => title => loc('Logout'), path   => '/NoAuth/Logout.html' );
-    }
-    if ( $request_path =~ m{^/Dashboards/(\d+)?}) {
-        if ( my $id = ( $1 || $m->request_args->{'id'} ) ) {
-            my $obj = RT::Dashboard->new( $session{'CurrentUser'} );
-            $obj->LoadById($id);
-            if ( $obj and $obj->id ) {
-                my $tabs = PageMenu;
-                $tabs->child( basics => title => loc('Basics'), path => "/Dashboards/Modify.html?id=" . $obj->id);
-                $tabs->child(content => title => loc('Content'), path => "/Dashboards/Queries.html?id=" . $obj->id);
-                $tabs->child( subscription => title => loc('Subscription'),
-                        path => "/Dashboards/Subscription.html?id=" . $obj->id
-                ) if $obj->CurrentUserCanSubscribe;
-                $tabs->child( show => title => loc('Show'), path => "/Dashboards/" . $obj->id . "/" . $obj->Name)
-            }
-        }
-    }
-
     if ( $request_path =~ m{^/Admin/(Queues|Users|Groups|CustomFields)} ) {
         my $type = $1;
         my $tabs = PageMenu();
@@ -420,6 +370,66 @@ if ( $request_path !~ m{^/SelfService/} ) {
         }
     }
 
+    };
+
+
+    if ( $session{'CurrentUser'}->HasRight( Right => 'ShowConfigTab', Object => RT->System ) )
+    {
+        $build_admin_menu->();
+    }
+
+
+
+
+    my $about_me = Menu->child( 'preferences' => title =>
+                        loc( 'Logged in as <span class="current-user">[_1]</span>', $session{'CurrentUser'}->Name),
+                    escape_title => 0,
+                    sort_order   => 99
+    );
+
+
+    if ( $session{'CurrentUser'}->UserObj
+         && $session{'CurrentUser'}->HasRight( Right  => 'ModifySelf', Object => RT->System )) {
+        my $settings = $about_me->child( settings => title => loc('Settings'), path => '/Prefs/Other.html', );
+        $settings->child( options => title => loc('Options'), path     => '/Prefs/Other.html', );
+        $settings->child( about_me => title => loc('About me'), path     => '/User/Prefs.html', );
+        $settings->child( search_options => title => loc('Search options'), path => '/Prefs/SearchOptions.html', );
+        $settings->child( myrt => title => loc('RT at a glance'), path => '/Prefs/MyRT.html', );
+        $settings->child( quicksearch => title => 'Quick search' => title => loc('Quick search'), path => '/Prefs/Quicksearch.html');
+
+        my $search_menu = $settings->child( 'saved-searches' => title => 'Saved Searches' );
+        my $searches = [ $m->comp( "/Search/Elements/SearchesForObject",
+                          Object => RT::System->new( $session{'CurrentUser'} )) ];
+        my $i = 0;
+
+        for my $search (@$searches) {
+            $search_menu->child( "search-" . $i++, title => $search->[0], path  => "/Prefs/Search.html?"
+                          . $query_string->( name => ref( $search->[1] ) . '-' . $search->[1]->Id),);
+
+        }
+    }
+    if ( $session{'CurrentUser'}->Name
+         && (   !RT->Config->Get('WebExternalAuth')
+              || RT->Config->Get('WebFallbackToInternalAuth') )) {
+        $about_me->child( logout => title => loc('Logout'), path   => '/NoAuth/Logout.html' );
+    }
+    if ( $request_path =~ m{^/Dashboards/(\d+)?}) {
+        if ( my $id = ( $1 || $m->request_args->{'id'} ) ) {
+            my $obj = RT::Dashboard->new( $session{'CurrentUser'} );
+            $obj->LoadById($id);
+            if ( $obj and $obj->id ) {
+                my $tabs = PageMenu;
+                $tabs->child( basics => title => loc('Basics'), path => "/Dashboards/Modify.html?id=" . $obj->id);
+                $tabs->child(content => title => loc('Content'), path => "/Dashboards/Queries.html?id=" . $obj->id);
+                $tabs->child( subscription => title => loc('Subscription'),
+                        path => "/Dashboards/Subscription.html?id=" . $obj->id
+                ) if $obj->CurrentUserCanSubscribe;
+                $tabs->child( show => title => loc('Show'), path => "/Dashboards/" . $obj->id . "/" . $obj->Name)
+            }
+        }
+    }
+
+
     if ( $request_path =~ m{^/Ticket/} ) {
         if ( ( $m->request_args->{'id'} || '' ) =~ /^(\d+)$/ ) {
             my $id  = $1;

commit e43d875dddc0649962f327c288e9e6a0ee96d2ac
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 13:53:58 2010 -0500

    move "Configuration" to the end of the tools menu

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 254997f..a993c05 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -124,7 +124,7 @@ if ( $request_path !~ m{^/SelfService/} ) {
 
 
 my $build_admin_menu = sub {
-        my $admin = $tools->child( config => title => loc('Configuration'), path   => '/Admin/', sort_order => 1 );
+        my $admin = $tools->child( config => title => loc('Configuration'), path   => '/Admin/', sort_order => 99 );
         if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminUsers' ) ) {
             my $users = $admin->child( users => title => loc('Users'), path => '/Admin/Users/', description => loc('Manage users and passwords') );
             $users->child( select => title => loc('Select'), path   => "/Admin/Users/" );

commit 0f5bea79a7cac35b4b32ad5902f90154e9c6dd20
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 13:54:11 2010 -0500

    make "main" and "selfservice" nav into subs

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index a993c05..9c1c1eb 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -58,7 +58,8 @@ my $query_string = sub {
     return $u->query;
 };
 
-if ( $request_path !~ m{^/SelfService/} ) {
+my $build_main_nav = sub {
+
     my $home = Menu->child( home => title => loc('Homepage'), path => '/' );
     my @dashboards = $m->comp("/Dashboards/Elements/ListOfDashboards");
     my $limit      = 7;
@@ -699,10 +700,9 @@ my $build_admin_menu = sub {
     PageWidgets()->child( create_ticket => raw_html => $m->scomp('CreateTicket') );
 
     $m->callback( CallbackName => 'Privileged' );
-}
-
-if ( $request_path =~ m{^/SelfService} ) {
+};
 
+my $build_selfservice_nav = sub {
     my $queues = RT::Queues->new( $session{'CurrentUser'} );
     $queues->FindAllRows;
 
@@ -750,8 +750,19 @@ if ( $request_path =~ m{^/SelfService} ) {
     PageWidgets->child( goto => raw_html => $m->scomp('/SelfService/Elements/GotoTicket') );
 
     $m->callback( CallbackName => 'SelfService' );
+};
+
+
+
+if ( $request_path !~ m{^/SelfService/} ) {
+    $build_main_nav->();
+} else {
+    $build_selfservice_nav->();
 }
 
+
+
+
 </%INIT>
 <%ARGS>
 $show_menu => 1

commit a3b14f9764567cde477e727515353567a20dfac1
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 14:26:51 2010 -0500

    Remove the submit button we don't need for the create ticket widget
    (only if the user has javascript that will autosubmit the form)

diff --git a/share/html/Elements/CreateTicket b/share/html/Elements/CreateTicket
index f14e837..36f13aa 100755
--- a/share/html/Elements/CreateTicket
+++ b/share/html/Elements/CreateTicket
@@ -50,6 +50,11 @@
 >
 <&|/l, $m->scomp('/Elements/SelectNewTicketQueue', OnChange => 'document.CreateTicketInQueue.submit()', SendTo => $SendTo ) &><input type="submit" class="button" value="New ticket in" />&nbsp;[_1]</&>
 % $m->callback(CallbackName => 'BeforeFormEnd');
+<script>
+jQuery('#CreateTicketInQueue select').prepend('<option value=""><%loc('Create ticket...')%></option>');
+jQuery('#CreateTicketInQueue input').remove();
+
+</script>
 </form>
 <%ARGS>
 $SendTo => '/Ticket/Create.html',

commit e84ec1c2327fada4098f6a69cd1492d7ac0e8198
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 14:27:19 2010 -0500

    Move dashboard nav out of 'Tools' and into the list of dashboards

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 9c1c1eb..a40d8ed 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -72,14 +72,18 @@ my $build_main_nav = sub {
 
     my $position = 0;
 
+    my $dashes = Menu()->child('home');
     if (@dashboards) {
-        my $dashes = Menu()->child('home');
         for my $dash (@dashboards) {
             $home->child( 'dashboard-' . $dash->id, title => $dash->Name,
                        path => '/Dashboards/' . $dash->id . '/' . $dash->Name,);
         }
 
-        $dashes->child( more => title => loc('More...'), path  => 'Dashboards/index.html' ) if ($more);
+        $dashes->child( more => title => loc('All Dashboards...'), path  => 'Dashboards/index.html' );
+    }
+    my $dashboard = RT::Dashboard->new( $session{CurrentUser} );
+    if ( $dashboard->CurrentUserCanCreateAny ) {
+        $dashes->child( loc('New Dashboard...') => path => "/Dashboards/Modify.html?Create=1" );
     }
 
     my $tickets = Menu->child( search => title => loc('Tickets'), path => '/Search/Build.html' );
@@ -97,14 +101,6 @@ my $build_main_nav = sub {
 
 
 
-    my $dashes = $tools->child( dashboards => title => loc('Dashboards'), path => '/Dashboards/index.html',
-                                description => loc('Custom reports online and by email') );
-    $dashes->child( select => title => loc('Select'), path => "/Dashboards/index.html" );
-    my $dashboard = RT::Dashboard->new( $session{CurrentUser} );
-    if ( $dashboard->CurrentUserCanCreateAny ) {
-        $dashes->child( loc('Create') => path => "/Dashboards/Modify.html?Create=1" );
-    }
-
     $tools->child( my_day => title => loc('My Day'), path   => '/Tools/MyDay.html',
                    description => loc('Easy updating of your open tickets') );
 

commit 5fe3f6f8cff781ee4d7ded6c05e69a31311f0458
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 15:31:11 2010 -0500

    update tests to keep pace with dashboards menu updates

diff --git a/share/html/Elements/ShowUserVerbose b/share/html/Elements/ShowUserVerbose
index c8902b0..e867c7c 100644
--- a/share/html/Elements/ShowUserVerbose
+++ b/share/html/Elements/ShowUserVerbose
@@ -54,21 +54,12 @@ my  $comment = '';
 
 if ($User) {
     $address = $User->EmailAddress;
-    $phrase  = $User->RealName
-      if $User->RealName && lc $User->RealName ne lc $address;
+    $phrase  = $User->RealName if $User->RealName && lc $User->RealName ne lc $address;
     $comment = $User->Name if lc $User->Name ne lc $address;
-    $comment = "($comment)" if defined $comment and length $comment;
-    $Address = Email::Address->new( $phrase, $address, $comment );
 }
 
-$Address->comment('') if $comment and defined $Address->user and lc $Address->user eq lc $comment;
-if ( $phrase and my ( $l, $r ) = ( $phrase =~ /^(\w+) (\w+)$/ ) ) {
-    $Address->phrase('')
-      if $Address->user =~ /^\Q$l\E.\Q$r\E$/
-      || $Address->user =~ /^\Q$r\E.\Q$l\E$/;
-}
+my $display = ($phrase || $comment || '' ) . ($address ?  ' <'.$address.'>' : '');
 
-my $display = $Address->format;
    $display = $m->interp->apply_escapes( $display, 'h' )
         unless $ARGS{'NoEscape'};
 </%INIT>
diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index a40d8ed..2dcad5e 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -83,7 +83,7 @@ my $build_main_nav = sub {
     }
     my $dashboard = RT::Dashboard->new( $session{CurrentUser} );
     if ( $dashboard->CurrentUserCanCreateAny ) {
-        $dashes->child( loc('New Dashboard...') => path => "/Dashboards/Modify.html?Create=1" );
+        $dashes->child('dashboard_create' => title => loc('New Dashboard...') => path => "/Dashboards/Modify.html?Create=1" );
     }
 
     my $tickets = Menu->child( search => title => loc('Tickets'), path => '/Search/Build.html' );
diff --git a/t/web/dashboards-basics.t b/t/web/dashboards-basics.t
index 362cbd0..3e29463 100644
--- a/t/web/dashboards-basics.t
+++ b/t/web/dashboards-basics.t
@@ -63,7 +63,7 @@ $m->content_contains("Create");
 
 $m->get_ok($url."Dashboards/index.html");
 $m->content_contains("New", "'New' link because we now have ModifyOwnDashboard");
-$m->follow_link_ok({ id => 'tools-dashboards-create'});
+$m->follow_link_ok({ id => 'home-dashboard_create'});
 $m->form_name('ModifyDashboard');
 $m->field("Name" => 'different dashboard');
 $m->content_lacks('Delete', "Delete button hidden because we are creating");
diff --git a/t/web/dashboards-groups.t b/t/web/dashboards-groups.t
index 0899c5b..f424d68 100644
--- a/t/web/dashboards-groups.t
+++ b/t/web/dashboards-groups.t
@@ -54,14 +54,14 @@ ok($inner_group->HasMemberRecursively($user_obj->PrincipalId), "inner has user r
 ok $m->login(customer => 'customer'), "logged in";
 
 
-$m->follow_link_ok({ id => 'tools-dashboards-create'});
+$m->follow_link_ok({ id => 'home-dashboard_create'});
 $m->form_name('ModifyDashboard');
 is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id], "the only selectable privacy is user");
 $m->content_lacks('Delete', "Delete button hidden because we are creating");
 
 $user_obj->PrincipalObj->GrantRight(Right => 'CreateGroupDashboard', Object => $inner_group);
 
-$m->follow_link_ok({ id => 'tools-dashboards-create'});
+$m->follow_link_ok({ id => 'home-dashboard_create'});
 $m->form_name('ModifyDashboard');
 is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id, "RT::Group-" . $inner_group->Id], "the only selectable privacies are user and inner group (not outer group)");
 $m->field("Name" => 'inner dashboard');
@@ -70,7 +70,7 @@ $m->content_lacks('Delete', "Delete button hidden because we are creating");
 
 $m->click_button(value => 'Create');
 
-$m->content_contains("created", "we lack SeeGroupDashboard, so we end up back at the index.");
+$m->content_contains("saved", "we lack SeeGroupDashboard, so we end up back at the index.");
 $user_obj->PrincipalObj->GrantRight(
     Right  => 'SeeGroupDashboard',
     Object => $inner_group,
diff --git a/t/web/dashboards-permissions.t b/t/web/dashboards-permissions.t
index c0a0b11..f2e59e5 100644
--- a/t/web/dashboards-permissions.t
+++ b/t/web/dashboards-permissions.t
@@ -29,7 +29,7 @@ $user_obj->PrincipalObj->GrantRight(Right => $_, Object => $RT::System)
 ok $m->login(customer => 'customer'), "logged in";
 
 
-$m->follow_link_ok( {id => 'tools-dashboards-create'});
+$m->follow_link_ok( {id => 'home-dashboard_create'});
 $m->form_name('ModifyDashboard');
 is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id], "the only selectable privacy is user");
 $m->content_lacks('Delete', "Delete button hidden because we are creating");
diff --git a/t/web/walk.t b/t/web/walk.t
index 1986ed1..abdac2c 100644
--- a/t/web/walk.t
+++ b/t/web/walk.t
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 93;
+use RT::Test tests => 92;
 
 my ( $baseurl, $m ) = RT::Test->started_ok;
 
@@ -33,7 +33,7 @@ diag 'walk into /Tools' if $ENV{TEST_VERBOSE};
     $m->get_ok( $baseurl, 'homepage' );
     $m->follow_link_ok( { text => 'Tools' }, '-> Tools' );
 
-    for my $tab ( 'Dashboards', 'Offline', 'My Day' )
+    for my $tab ( 'Offline', 'My Day' )
     {
 
         $m->follow_link_ok( { text => $tab }, "-> $tab" );

commit cb7798845c736618d7a1b1c8c5d8672a49e21692
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 15:48:42 2010 -0500

    Switch from ~english to boring error message

diff --git a/share/html/Articles/Article/PreCreate.html b/share/html/Articles/Article/PreCreate.html
index 5e375bc..6c3c033 100644
--- a/share/html/Articles/Article/PreCreate.html
+++ b/share/html/Articles/Article/PreCreate.html
@@ -57,5 +57,5 @@
 % }
 </ul>
 % unless ( $have_classes ) {
-<span><&|/l&>No classes you have access to...</&></span>
+<span><&|/l&>Permission Denied</&></span>
 % }

commit fc3879855bdeb2e7191f5e935dc62eb0493ef660
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 15:49:25 2010 -0500

    specify a default value to fix an explosion in bulk update with bad old
    data

diff --git a/share/html/Elements/EditCustomFieldSelect b/share/html/Elements/EditCustomFieldSelect
index 9473d75..a1658f2 100644
--- a/share/html/Elements/EditCustomFieldSelect
+++ b/share/html/Elements/EditCustomFieldSelect
@@ -149,7 +149,7 @@ $Multiple => 0
 $Rows => undef
 $HideCategory => 0
 $RenderType => undef
-$MaxValues
+$MaxValues => 1
 </%ARGS>
 
 <%METHOD options>

commit 433008bbd992f4dd8f60d1f1724b4da2475d875f
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 15:50:23 2010 -0500

    Move "Chart" out of the "More" menu and change "More" to "Feeds"

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 2dcad5e..e4b06d4 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -598,22 +598,21 @@ my $build_admin_menu = sub {
         } else {
             $current_search_menu = PageMenu();
         }
-        if ($has_query) {
-            $current_search_menu->child( results => title => loc('Show Results') => path => "/Search/Results.html$args" );
-
-        }
 
         $current_search_menu->child( edit_search => title => loc('Edit Search') =>
                                      path => "/Search/Build.html" . ( ($has_query) ? $args : '' ) );
         $current_search_menu->child( loc('Advanced') => path => "/Search/Edit.html$args" );
+        if ($has_query) {
+            $current_search_menu->child( results => title => loc('Show Results') => path => "/Search/Results.html$args" );
+        }
 
         if ( $has_query ) {
             $current_search_menu->child( bulk => title => loc('Bulk Update') => path => "/Search/Bulk.html$args" );
+            $current_search_menu->child( chart => title => loc('Chart'),
+                                         path => "/Search/Chart.html$args" );
 
-            my $more = $current_search_menu->child( more => title => loc('More...') );
+            my $more = $current_search_menu->child( more => title => loc('Feeds...') );
             
-            $more->child( chart => title => loc('Graph'),
-                                         path => "/Search/Chart.html$args" );
             $more->child(
                                    spreadsheet => title => loc('Spreadsheet'),
                                    path => "/Search/Results.tsv$args" );

commit 350ca500b3a1e0ddf1f757117022db15a2af7bea
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 15:50:43 2010 -0500

    Graph -> Chart to be a bit more consistent

diff --git a/share/html/Search/Chart.html b/share/html/Search/Chart.html
index 478bef7..55dab94 100644
--- a/share/html/Search/Chart.html
+++ b/share/html/Search/Chart.html
@@ -86,13 +86,13 @@ my @actions = $m->comp( '/Widgets/SavedSearch:process', args => \%ARGS, self =>
 
 <div class="chart-meta">
 <div class="chart-type">
-<&| /Widgets/TitleBox, title => loc('Graph Properties')&>
+<&| /Widgets/TitleBox, title => loc('Chart Properties')&>
 <form method="get" action="<%RT->Config->Get('WebPath')%>/Search/Chart.html">
 <input type="hidden" class="hidden" name="Query" value="<% $ARGS{Query} %>" />
 <input type="hidden" class="hidden" name="SavedChartSearchId" value="<% $saved_search->{SearchId} || 'new' %>" />
 
 <&|/l, $m->scomp('Elements/SelectChartType', Name => 'ChartStyle', Default => $ChartStyle), $m->scomp('Elements/SelectGroupBy', Name => 'PrimaryGroupBy', Query => $ARGS{Query}, Default => $PrimaryGroupBy) 
-&>[_1] chart by [_2]</&><input type="submit" class="button" value="<%loc('Update Graph')%>" />
+&>[_1] chart by [_2]</&><input type="submit" class="button" value="<%loc('Update Chart')%>" />
 </form>
 </&>
 </div>

commit bed4fbc09b4887ee8ccefbb998478db02054530c
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 16:01:59 2010 -0500

    quiet a warning

diff --git a/t/web/squish.t b/t/web/squish.t
index 14dcc03..0a63b0a 100644
--- a/t/web/squish.t
+++ b/t/web/squish.t
@@ -32,7 +32,7 @@ diag "test squished files with customized files and devel mode disabled";
 SKIP:
 {
     skip 'need actual server to reinitialize', 6
-      if $ENV{RT_TEST_WEB_HANDLER} eq 'inline';
+      if ($ENV{RT_TEST_WEB_HANDLER} ||'') eq 'inline';
     require RT::Squish::JS;
     RT::Squish::JS->UpdateFilesMap( head => ['/NoAuth/js/IE7/IE7.js'] );
     require RT::Squish::CSS;

commit 037709f22916e099befbc191772423e88d1c63e2
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 16:06:03 2010 -0500

    Add "..." to Actions on ticket display pages

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index e4b06d4..3a1c82a 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -433,7 +433,7 @@ my $build_admin_menu = sub {
             my $obj = RT::Ticket->new( $session{'CurrentUser'} );
             $obj->Load($id);
 
-            my $actions = PageMenu()->child( actions => title => loc('Actions'), sort_order  => 95 );
+            my $actions = PageMenu()->child( actions => title => loc('Actions...'), sort_order  => 95 );
             my $tabs = PageMenu();
             $tabs->child( bookmark => raw_html => $m->scomp( '/Ticket/Elements/Bookmark', id => $id ),
                 sort_order => 99

commit 5651f1b83741816c4fecf6863080ebe036a618f8
Author: Shawn M Moore <sartak at bestpractical.com>
Date:   Tue Dec 21 17:23:49 2010 -0500

    Quote the database name in case it has dashes [issues.bestpractical.com #15042]

diff --git a/etc/upgrade/upgrade-mysql-schema.pl b/etc/upgrade/upgrade-mysql-schema.pl
index bc59c97..71b17fc 100755
--- a/etc/upgrade/upgrade-mysql-schema.pl
+++ b/etc/upgrade/upgrade-mysql-schema.pl
@@ -219,7 +219,7 @@ $db_name =~ s/:.*$//;
 my $version = ($dbh->selectrow_array("show variables like 'version'"))[1];
 ($version) = $version =~ /^(\d+\.\d+)/;
 
-push @sql_commands, qq{ALTER DATABASE $db_name DEFAULT CHARACTER SET utf8};
+push @sql_commands, qq{ALTER DATABASE `$db_name` DEFAULT CHARACTER SET utf8};
 convert_table($_) foreach @tables;
 
 print join "\n", map(/;$/? $_ : "$_;", @sql_commands), "";

commit 1aff7c68dd88c7f6c2904c5c09e4c0e7a2bba066
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 12:18:40 2010 -0500

    Add a missing period

diff --git a/share/html/Admin/Tools/Queries.html b/share/html/Admin/Tools/Queries.html
index 4d16fd3..a01bbaf 100644
--- a/share/html/Admin/Tools/Queries.html
+++ b/share/html/Admin/Tools/Queries.html
@@ -48,7 +48,7 @@
 <%init>
 my $title = loc('SQL Queries');
 unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'SuperUser')) {
- Abort(loc('This feature is only available to system administrators'));
+ Abort(loc('This feature is only available to system administrators.'));
 }
 </%init>
 <& /Admin/Elements/Header, Title => $title &>

commit 9f386ab048dd55118a7d23475170fee34afde066
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 12:23:26 2010 -0500

    Lock down the theme editor to SuperUsers only

diff --git a/share/html/Admin/Global/Theme.html b/share/html/Admin/Global/Theme.html
index 160be19..ce50d2c 100644
--- a/share/html/Admin/Global/Theme.html
+++ b/share/html/Admin/Global/Theme.html
@@ -183,6 +183,10 @@ jQuery(function($) {
 });
 </script>
 <%INIT>
+unless ($session{'CurrentUser'}->HasRight( Object=> RT->System, Right => 'SuperUser')) {
+    Abort(loc('This feature is only available to system administrators.'));
+}
+
 require JSON;
 
 my $text_threshold = 0.6;

commit 4024f896144612e44851a470ddcac3ccec0c9eca
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 17:59:37 2010 -0500

    Move the meat of ScrubHTML into RT::Interface::Web::ScrubHTML

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 6774779..694b40c 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -2541,6 +2541,56 @@ sub _parse_saved_search {
     return ( _load_container_object( $obj_type, $obj_id ), $search_id );
 }
 
+=head2 ScrubHTML content
+
+Removes unsafe and undesired HTML from the passed content
+
+=cut
+
+my $SCRUBBER;
+sub ScrubHTML {
+    my $Content = shift;
+    $SCRUBBER = _NewScrubber() unless $SCRUBBER;
+
+    $Content = '' if !defined($Content);
+    return $SCRUBBER->scrub($Content);
+}
+
+=head2 _NewScrubber
+
+Returns a new L<HTML::Scrubber> object.  Override this if you insist on
+letting more HTML through.
+
+=cut
+
+sub _NewScrubber {
+    require HTML::Scrubber;
+    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);
+
+    return $scrubber;
+}
+
 RT::Base->_ImportOverlays();
 
 1;
diff --git a/share/html/Elements/ScrubHTML b/share/html/Elements/ScrubHTML
index 662309e..47d4554 100644
--- a/share/html/Elements/ScrubHTML
+++ b/share/html/Elements/ScrubHTML
@@ -45,33 +45,8 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<%ONCE>
-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);
-</%ONCE>
 <%init>
-$Content = '' if !defined($Content);
-return $scrubber->scrub($Content);
+return ScrubHTML($Content);
 </%init>
 <%args>
 $Content => undef

commit 438a9f30d49ff6f56abb013b228f9e5dc77c6989
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 18:05:46 2010 -0500

    Overhaul what CSS we allow in style attributes to be safer *and* more useful
    
    The regex takes care to accomodate Outlook's idiosyncrasies and ensure
    that the features of the rich text editor work.
    
    This is still a large hammer.  If there's any forbidden CSS property
    specified the entire style attribute will be stripped (including
    otherwise allowed properties).  The fix for this is parsing the CSS
    itself with something like CSS::Adaptor::Whitelist, but that's for
    another day.

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 694b40c..7292780 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -2578,8 +2578,24 @@ sub _NewScrubber {
             face   => 1,
             size   => 1,
             target => 1,
-            style  => qr{^(?:(?:color:\s*rgb\(\d+,\s*\d+,\s*\d+\))|
-                             (?:text-align:\s*))}ix,
+            style  => qr{
+                ^(?:\s*
+                    (?:(?:background-)?color: \s*
+                            (?:rgb\(\s* \d+, \s* \d+, \s* \d+ \s*\) |   # rgb(d,d,d)
+                               \#[a-f0-9]{3,6}                      |   # #fff or #ffffff
+                               [\w\-]+                                  # green, light-blue, etc.
+                               )                            |
+                       text-align: \s* \w+                  |
+                       font-size: \s* [\w.\-]+              |
+                       font-family: \s* [\w\s"',.\-]+       |
+                       font-weight: \s* [\w\-]+             |
+
+                       # MS Office styles, which are probably fine.  If we don't, then any
+                       # associated styles in the same attribute get stripped.
+                       mso-[\w\-]+?: \s* [\w\s"',.\-]+
+                    )\s* ;? \s*)
+                 +$ # one or more of these allowed properties from here 'till sunset
+            }ix,
         }
     );
     $scrubber->deny(qw[*]);
diff --git a/sbin/rt-test-dependencies.in b/sbin/rt-test-dependencies.in
index 506ecd3..3b3b1c7 100755
--- a/sbin/rt-test-dependencies.in
+++ b/sbin/rt-test-dependencies.in
@@ -279,6 +279,7 @@ Test::MockTime
 Log::Dispatch::Perl
 Test::WWW::Mechanize::PSGI
 Plack::Middleware::Test::StashWarnings
+Test::LongString
 .
 
 $deps{'FASTCGI'} = [ text_to_hash( << '.') ];
diff --git a/t/web/scrub.t b/t/web/scrub.t
new file mode 100644
index 0000000..6483a75
--- /dev/null
+++ b/t/web/scrub.t
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test nodb => 1, tests => 6;
+use RT::Interface::Web; # This gets us HTML::Mason::Commands
+use Test::LongString;
+
+{
+    my $html = 'This is a test of <span style="color: rgb(255, 0, 0); ">color</span> and <span style="font-size: 18px; "><span style="font-family: Georgia, serif; ">font</span></span> and <em><u><strike><strong>boldness</strong></strike></u></em>.';
+    is_string(scrub_html($html), $html, "CKEditor produced HTML sails through");
+}
+
+{
+    my $html = '<p style="text-align: right; ">
+        And <span style="color: rgb(255, 0, 0); "><span style="font-size: 16px; "><span style="font-family: Georgia, serif; ">alignment with color</span></span></span>?</p>';
+    is_string(scrub_html($html), $html, "CKEditor produced HTML sails through");
+}
+
+{
+    my $html = 'This is a test of <span style="color: rgb(255, 0, 0); content: url(/Nasty/URL);">color</span> and <span style="font-size: 18px; "><span style="font-family: Georgia, serif; ">font</span></span> and <em><u><strike><strong>boldness</strong></strike></u></em>.';
+    my $expected = 'This is a test of <span>color</span> and <span style="font-size: 18px; "><span style="font-family: Georgia, serif; ">font</span></span> and <em><u><strike><strong>boldness</strong></strike></u></em>.';
+    is_string(scrub_html($html), $expected, "nasty CSS not allowed through");
+}
+
+{
+    my $html = 'Let\'s add some <span style="color: blue; font-family: Georgia">color</span> up in <span style="color: #DEADBE">here</span>.';
+    is_string(scrub_html($html), $html, "multiple props and color specs allowed");
+}
+
+{
+    my $html = q[<span lang=EN-US style='font-family:"Century Gothic","sans-serif";'>oh hai I'm some text</span>];
+    my $expected = q[<span style="font-family:&quot;Century Gothic&quot;,&quot;sans-serif&quot;;">oh hai I'm some text</span>];
+    is_string(scrub_html($html), $expected, "font lists");
+}
+
+{
+    my $html = q[<span lang=EN-US style='font-size:7.5pt;font-family:"Century Gothic","sans-serif";color:#666666;mso-fareast-language:IT'>oh hai I'm some text</span>];
+    my $expected = q[<span style="font-size:7.5pt;font-family:&quot;Century Gothic&quot;,&quot;sans-serif&quot;;color:#666666;mso-fareast-language:IT">oh hai I'm some text</span>];
+    is_string(scrub_html($html), $expected, "outlook html");
+}
+
+sub scrub_html {
+    return HTML::Mason::Commands::ScrubHTML(shift);
+}
+

commit 41ed12ed639dabd9ac396cef52c9bb528f8a0d28
Author: Shawn M Moore <sartak at bestpractical.com>
Date:   Tue Dec 21 18:18:45 2010 -0500

    Try to load Module::Refresh before calling ->refresh
    
        Otherwise, in some circumstances, we won't have Module::Refresh
        loaded and it'll break. This happened in t/web/squish.t which
        enables DevelMode and not having Module::Refresh loaded broke a
        test. Tests being otherwise warnings-clean caught this. :)

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 7292780..3311021 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -191,7 +191,10 @@ sub WebExternalAutoInfo {
 sub HandleRequest {
     my $ARGS = shift;
 
-    Module::Refresh->refresh if RT->Config->Get('DevelMode');
+    if (RT->Config->Get('DevelMode')) {
+        require Module::Refresh;
+        Module::Refresh->refresh;
+    }
 
     $HTML::Mason::Commands::r->content_type("text/html; charset=utf-8");
 

commit 690eabee5db23a458a823b031e5517af2eea3c58
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 18:43:59 2010 -0500

    Pop the titlebox titles off the page a little more

diff --git a/share/html/NoAuth/css/aileron/boxes.css b/share/html/NoAuth/css/aileron/boxes.css
index 4a91ae8..3c19645 100644
--- a/share/html/NoAuth/css/aileron/boxes.css
+++ b/share/html/NoAuth/css/aileron/boxes.css
@@ -115,8 +115,6 @@
 .titlebox .titlebox-title .left {
     font-weight: bold;
     background: #ccc;
-/*    position: absolute;
-    left: 0.75em;*/
     margin-left: 1em;
     padding: 0.25em 0.75em 0.25em 2em;
     line-height: 1.5em;
@@ -125,6 +123,7 @@
     -moz-border-radius-topleft: 0.3em;
     -moz-border-radius-topright: 0.3em;
     border-radius: 0.3em 0.3em 0 0;
+    border-right: 2px solid #aaa;
 }
 
 .titlebox .titlebox-title .right-empty {

commit 8b5940492279b8c1bca87959797e08b0acf288f2
Merge: 41ed12e 690eabe
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Dec 21 18:44:42 2010 -0500

    Merge branch 'titlebox-title-tweaks' into 3.9-trunk


commit ff80d1a902875e402d87bb1550282341efe2f19e
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 19:30:12 2010 -0500

    lift the "default" menu list item to the top of the queue list, for easier selection

diff --git a/share/html/Elements/SelectQueue b/share/html/Elements/SelectQueue
index 7abdd5f..ec836ae 100755
--- a/share/html/Elements/SelectQueue
+++ b/share/html/Elements/SelectQueue
@@ -46,21 +46,23 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 % if ($Lite) {
-%     my $d = RT::Queue->new($session{'CurrentUser'});
-%     $d->Load($Default);
-<input name="<%$Name%>" size="25" value="<%$d->Name%>" class="<%$Class%>" />
+<input name="<%$Name%>" size="25" value="<%$default_queue->Name%>" class="<%$Class%>" />
 % }
 % else {
-<select name="<%$Name%>" <% ($Multiple) ? qq{multiple="multiple" size="$Size"} : '' |n%> <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>">
-%     if ($ShowNullOption) {
+<select name="<%$Name%>" <% ($Multiple) ? qq{multiple="multiple" size="$Size"} : '' |n%>\
+     <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>">
+% if ($ShowNullOption) {
   <option value=""><% $DefaultLabel %></option>
-%     }
-%     for my $queue (@{$session{$cache_key}{queues}}) {
-  <option value="<% ($NamedValues ? $queue->{Name} : $queue->{Id}) %>"\
-% if ($queue->{Id} eq ($Default||'') || $queue->{Name} eq ($Default||'')) {
- selected="selected"\
 % }
-><%$queue->{Name}%>\
+% if ($default_queue->id) {
+ <option value="<% $NamedValues ? $default_queue->Name : $default_queue->id %>"><%$default_queue->Name%>\
+% if ($Verbose && $default_queue->Description) {
+ (<%$default_queue->Description%>)\
+% }
+</option>
+%}
+%     for my $queue (@{$session{$cache_key}{queues}}) {
+  <option value="<% ($NamedValues ? $queue->{Name} : $queue->{Id}) %>"><%$queue->{Name}%>\
 %             if ($Verbose and $queue->{Description}) {
  (<%$queue->{Description}%>)\
 %             }
@@ -111,4 +113,9 @@ if ( not defined $session{$cache_key} and not $Lite ) {
     }
     $session{$cache_key}{lastupdated} = time();
 }
+
+my $default_queue = RT::Queue->new($session{CurrentUser});
+if ($Default) {
+    $default_queue->Load($Default);
+}
 </%init>

commit 6a3a872b074f83d7dad8073b2c8b6b131d79f57d
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 20:12:50 2010 -0500

    Revert "lift the "default" menu list item to the top of the queue list, for easier selection"
    
    This reverts commit ff80d1a902875e402d87bb1550282341efe2f19e.

diff --git a/share/html/Elements/SelectQueue b/share/html/Elements/SelectQueue
index ec836ae..7abdd5f 100755
--- a/share/html/Elements/SelectQueue
+++ b/share/html/Elements/SelectQueue
@@ -46,23 +46,21 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 % if ($Lite) {
-<input name="<%$Name%>" size="25" value="<%$default_queue->Name%>" class="<%$Class%>" />
+%     my $d = RT::Queue->new($session{'CurrentUser'});
+%     $d->Load($Default);
+<input name="<%$Name%>" size="25" value="<%$d->Name%>" class="<%$Class%>" />
 % }
 % else {
-<select name="<%$Name%>" <% ($Multiple) ? qq{multiple="multiple" size="$Size"} : '' |n%>\
-     <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>">
-% if ($ShowNullOption) {
+<select name="<%$Name%>" <% ($Multiple) ? qq{multiple="multiple" size="$Size"} : '' |n%> <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>">
+%     if ($ShowNullOption) {
   <option value=""><% $DefaultLabel %></option>
-% }
-% if ($default_queue->id) {
- <option value="<% $NamedValues ? $default_queue->Name : $default_queue->id %>"><%$default_queue->Name%>\
-% if ($Verbose && $default_queue->Description) {
- (<%$default_queue->Description%>)\
-% }
-</option>
-%}
+%     }
 %     for my $queue (@{$session{$cache_key}{queues}}) {
-  <option value="<% ($NamedValues ? $queue->{Name} : $queue->{Id}) %>"><%$queue->{Name}%>\
+  <option value="<% ($NamedValues ? $queue->{Name} : $queue->{Id}) %>"\
+% if ($queue->{Id} eq ($Default||'') || $queue->{Name} eq ($Default||'')) {
+ selected="selected"\
+% }
+><%$queue->{Name}%>\
 %             if ($Verbose and $queue->{Description}) {
  (<%$queue->{Description}%>)\
 %             }
@@ -113,9 +111,4 @@ if ( not defined $session{$cache_key} and not $Lite ) {
     }
     $session{$cache_key}{lastupdated} = time();
 }
-
-my $default_queue = RT::Queue->new($session{CurrentUser});
-if ($Default) {
-    $default_queue->Load($Default);
-}
 </%init>

commit fabd3be5a5ede720e4fde0ffea6d56d2ff10c639
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Dec 21 20:13:12 2010 -0500

    Revert "Remove the submit button we don't need for the create ticket widget"
    
    This reverts commit a3b14f9764567cde477e727515353567a20dfac1.

diff --git a/share/html/Elements/CreateTicket b/share/html/Elements/CreateTicket
index 36f13aa..f14e837 100755
--- a/share/html/Elements/CreateTicket
+++ b/share/html/Elements/CreateTicket
@@ -50,11 +50,6 @@
 >
 <&|/l, $m->scomp('/Elements/SelectNewTicketQueue', OnChange => 'document.CreateTicketInQueue.submit()', SendTo => $SendTo ) &><input type="submit" class="button" value="New ticket in" />&nbsp;[_1]</&>
 % $m->callback(CallbackName => 'BeforeFormEnd');
-<script>
-jQuery('#CreateTicketInQueue select').prepend('<option value=""><%loc('Create ticket...')%></option>');
-jQuery('#CreateTicketInQueue input').remove();
-
-</script>
 </form>
 <%ARGS>
 $SendTo => '/Ticket/Create.html',

commit 2e4d4af146c3f1e844c68a67b70539a6cb4b9983
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Dec 22 10:48:57 2010 -0500

    Remove the ...'s sprinkled in the menus

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index 3a1c82a..b2557df 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -79,11 +79,11 @@ my $build_main_nav = sub {
                        path => '/Dashboards/' . $dash->id . '/' . $dash->Name,);
         }
 
-        $dashes->child( more => title => loc('All Dashboards...'), path  => 'Dashboards/index.html' );
+        $dashes->child( more => title => loc('All Dashboards'), path  => 'Dashboards/index.html' );
     }
     my $dashboard = RT::Dashboard->new( $session{CurrentUser} );
     if ( $dashboard->CurrentUserCanCreateAny ) {
-        $dashes->child('dashboard_create' => title => loc('New Dashboard...') => path => "/Dashboards/Modify.html?Create=1" );
+        $dashes->child('dashboard_create' => title => loc('New Dashboard') => path => "/Dashboards/Modify.html?Create=1" );
     }
 
     my $tickets = Menu->child( search => title => loc('Tickets'), path => '/Search/Build.html' );
@@ -433,7 +433,7 @@ my $build_admin_menu = sub {
             my $obj = RT::Ticket->new( $session{'CurrentUser'} );
             $obj->Load($id);
 
-            my $actions = PageMenu()->child( actions => title => loc('Actions...'), sort_order  => 95 );
+            my $actions = PageMenu()->child( actions => title => loc('Actions'), sort_order  => 95 );
             my $tabs = PageMenu();
             $tabs->child( bookmark => raw_html => $m->scomp( '/Ticket/Elements/Bookmark', id => $id ),
                 sort_order => 99
@@ -611,7 +611,7 @@ my $build_admin_menu = sub {
             $current_search_menu->child( chart => title => loc('Chart'),
                                          path => "/Search/Chart.html$args" );
 
-            my $more = $current_search_menu->child( more => title => loc('Feeds...') );
+            my $more = $current_search_menu->child( more => title => loc('Feeds') );
             
             $more->child(
                                    spreadsheet => title => loc('Spreadsheet'),

commit 9e1a6c9f308d4076b6b3a2537605dfd7777210bf
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Dec 22 10:49:27 2010 -0500

    Standardize on submenu indicators

diff --git a/share/html/NoAuth/css/aileron/InHeader b/share/html/NoAuth/css/aileron/InHeader
index 4dba1de..e53d203 100644
--- a/share/html/NoAuth/css/aileron/InHeader
+++ b/share/html/NoAuth/css/aileron/InHeader
@@ -64,6 +64,6 @@ jQuery(document).ready(function(){
     };
 
     jQuery("#app-nav.toplevel").addClass('sf-menu sf-js-enabled sf-shadow').supersubs().superfish();
-    jQuery("#page-menu.toplevel").addClass('sf-menu sf-js-enabled sf-shadow').supersubs().superfish({ autoArrows:  false, dropShadows: false }).supposition();
+    jQuery("#page-menu.toplevel").addClass('sf-menu sf-js-enabled').supersubs().superfish({ dropShadows: false }).supposition();
 });
 </script>
diff --git a/share/html/NoAuth/css/aileron/nav.css b/share/html/NoAuth/css/aileron/nav.css
index 23ef731..d4cd861 100644
--- a/share/html/NoAuth/css/aileron/nav.css
+++ b/share/html/NoAuth/css/aileron/nav.css
@@ -65,6 +65,18 @@
     margin-top: -3px;
 }
 
+#page-menu.sf-menu li .sf-sub-indicator {
+    top: 0.7em;
+}
+
+#page-menu.sf-menu li:hover ul, #page-menu.sf-menu li.sfHover ul {
+    top: 2.5em;
+}
+
+#page-menu.sf-menu li ul {
+    border-bottom: 2px solid #ccc;
+}
+
 #main-navigation {
     position: absolute;
     top: 1px;
diff --git a/share/html/NoAuth/css/web2/InHeader b/share/html/NoAuth/css/web2/InHeader
index d756953..c05a03c 100644
--- a/share/html/NoAuth/css/web2/InHeader
+++ b/share/html/NoAuth/css/web2/InHeader
@@ -69,7 +69,7 @@ jQuery(document).ready(function(){
         extraWidth: 2
     };
 
-    jQuery("#page-menu.toplevel").addClass("sf-menu sf-js-enabled").supersubs().superfish().supposition();
+    jQuery("#page-menu.toplevel").addClass("sf-menu sf-js-enabled").supersubs().superfish({ dropShadows: false }).supposition();
     jQuery("#app-nav.toplevel").addClass("sf-menu sf-vertical sf-js-enabled").supersubs().superfish().supposition();
     jQuery("#prefs-menu").addClass("sf-menu sf-js-enabled").supersubs().superfish().supposition();
 });
diff --git a/share/html/NoAuth/css/web2/nav.css b/share/html/NoAuth/css/web2/nav.css
index a85d33d..1858bcc 100644
--- a/share/html/NoAuth/css/web2/nav.css
+++ b/share/html/NoAuth/css/web2/nav.css
@@ -64,7 +64,7 @@
     padding-left: 0.5em;
 }
 
-#app-nav .sf-sub-indicator {
+.sf-sub-indicator {
     background-image: url(../images/arrows-grey.png);
     margin-top: -3px;
 }
@@ -100,6 +100,7 @@
 
 #prefs-menu .sf-sub-indicator {
     background-image: url(../images/arrows-grey.png);
+    margin-top: 0;
 }
 
 #main-navigation ul li {
@@ -195,21 +196,32 @@
 
 
 #page-navigation .sf-menu ul {
-    background: #eee;
+    background: white;
+    border-bottom: 2px solid #ccc;
 }
 
 
 #page-navigation .sf-menu li:hover, #page-navigation .sf-menu li.sfHover, #page-navigation .sf-menu a:focus, #page-navigation .sf-menu a:hover, #page-navigation .sf-menu a:active {
     background: none;
-
 }
 
 #page-navigation .sf-menu a:visited, #page-navigation .sf-menu a {
     border: none;
-    padding: 0.25em;
     color: #000;
 }
 
+#page-navigation .sf-menu a {
+    padding: 0.25em;
+}
+
+#page-navigation .sf-menu a.sf-with-ul {
+    /* allow space for the submenu indicator */
+    padding-right: 2em;
+}
+
+#page-menu.sf-menu li .sf-sub-indicator {
+    top: 0.7em;
+}
 
 
 #page-actions {

commit 1a26e2962c92afc20781cd7b35eaec504777c83c
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Dec 22 10:52:55 2010 -0500

    Fix indenting

diff --git a/share/html/Elements/Tabs b/share/html/Elements/Tabs
index b2557df..12617cd 100755
--- a/share/html/Elements/Tabs
+++ b/share/html/Elements/Tabs
@@ -546,17 +546,17 @@ my $build_admin_menu = sub {
                 my $search = Menu()->child('search');
                 # Don't display prev links if we're on the first ticket
                 if ( $item_map->{$id}->{prev} ) {
-                    $search->child( 'first', title => '<< ' . loc('First') => class => "nav",
-                              path => "/Ticket/Display.html?id=" . $item_map->{first});
+                    $search->child( 'first', title => ' ' . loc('First'), escape_title => 0, class => "nav",
+                                    path => "/Ticket/Display.html?id=" . $item_map->{first});
                     $search->child( prev => title => '< ' . loc('Prev') => class => "nav",
-                        path => "/Ticket/Display.html?id=" . $item_map->{$id}->{prev});
+                                    path => "/Ticket/Display.html?id=" . $item_map->{$id}->{prev});
                 }
-                    # Don't display next links if we're on the last ticket
-                    if ( $item_map->{$id}->{next} ) {
-                        $search->child( next       => title => loc('Next') . ' >' => class => "nav",
-                                        path => "/Ticket/Display.html?id=" . $item_map->{$id}->{next});
-                        $search->child( last        => title => loc('Last') . ' >>' => class => "nav",
-                                        path => "/Ticket/Display.html?id=" . $item_map->{last});
+                # Don't display next links if we're on the last ticket
+                if ( $item_map->{$id}->{next} ) {
+                    $search->child( next       => title => loc('Next') . ' >' => class => "nav",
+                                    path => "/Ticket/Display.html?id=" . $item_map->{$id}->{next});
+                    $search->child( last        => title => loc('Last') . ' >>' => class => "nav",
+                                    path => "/Ticket/Display.html?id=" . $item_map->{last});
                 }
             }
         }

commit 4a8d4daff7142e466552617122c7e958d6d28edf
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Dec 22 12:37:55 2010 -0500

    Nested comments aren't allowed, so use a compound condition

diff --git a/share/html/NoAuth/css/aileron/InHeader b/share/html/NoAuth/css/aileron/InHeader
index e53d203..62c43ea 100644
--- a/share/html/NoAuth/css/aileron/InHeader
+++ b/share/html/NoAuth/css/aileron/InHeader
@@ -45,11 +45,9 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<!--[if lt IE 9]>
-<!--[if gt IE 6]>
+<!--[if (lt IE 9)&(gt IE 6)]>
 <link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/aileron/msie-pie.css" type="text/css" media="all" />
 <![endif]-->
-<![endif]-->
 <!--[if lt IE 8]>
 <link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/aileron/msie.css" type="text/css" media="all" />
 <![endif]-->
diff --git a/share/html/NoAuth/css/web2/InHeader b/share/html/NoAuth/css/web2/InHeader
index c05a03c..43f3eb6 100644
--- a/share/html/NoAuth/css/web2/InHeader
+++ b/share/html/NoAuth/css/web2/InHeader
@@ -74,8 +74,6 @@ jQuery(document).ready(function(){
     jQuery("#prefs-menu").addClass("sf-menu sf-js-enabled").supersubs().superfish().supposition();
 });
 </script>
-<!--[if lt IE 9]>
-<!--[if gt IE 6]>
+<!--[if (lt IE 9)&(gt IE 6)]>
 <link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/web2/msie-pie.css" type="text/css" media="all" />
 <![endif]-->
-<![endif]-->

commit 2ee57979c855b8aec1cfa518412db749d95f1229
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Dec 22 12:49:15 2010 -0500

    Use a more generous bottom: positioning

diff --git a/share/html/NoAuth/css/base/admin.css b/share/html/NoAuth/css/base/admin.css
index 2d03ace..0aee9cc 100644
--- a/share/html/NoAuth/css/base/admin.css
+++ b/share/html/NoAuth/css/base/admin.css
@@ -78,9 +78,9 @@ ul.list-menu ul li {
 
 #rt-portal .titlebox {
     position: absolute;
-    top: 1em;;
+    top: 1em;
     right: 1em;
-    bottom: 0em;
+    bottom: 3em;
     width: 45%;
     padding-bottom: 1em;
 }

commit 42c487b8f36d1af80563fa84b565963f974cb946
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Dec 22 12:49:32 2010 -0500

    Tidy up some padding in the index page menus

diff --git a/share/html/NoAuth/css/base/admin.css b/share/html/NoAuth/css/base/admin.css
index 0aee9cc..174a9b5 100644
--- a/share/html/NoAuth/css/base/admin.css
+++ b/share/html/NoAuth/css/base/admin.css
@@ -58,7 +58,7 @@ ul.list-menu > li {
 ul.list-menu .description {
  font-style: italic;
  display: block;
- padding: 0.5em 0 0 1em;
+ padding: 0.2em 0 0 1em;
 }
 
 ul.list-menu ul {

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


More information about the Rt-commit mailing list