Index: timingandestimationplugin/htdocs/ticket.js
===================================================================
--- timingandestimationplugin/htdocs/ticket.js	(revision 0)
+++ timingandestimationplugin/htdocs/ticket.js	(revision 0)
@@ -0,0 +1,181 @@
+function teAddEventListener(elem, evt, func, capture)
+{
+  capture = capture || false;
+  if (elem.addEventListener) elem.addEventListener(evt, func, capture);
+  else elem.attachEvent('on'+evt, func);
+  return func;
+}
+
+// Function from: http://www.robertnyman.com/index.php?p=256
+function getElementsByClassName(className, tag, elm)
+{
+  var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
+  var tag = tag || "*";
+  var elm = elm || document;
+  var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag);
+  var returnElements = [];
+  var current;
+  var length = elements.length;
+  for (var i=0; i<length; i++)
+  {
+    current = elements[i];
+    if(testClass.test(current.className))
+    {
+      returnElements.push(current);
+    }
+  }
+  return returnElements;
+}
+
+
+function FloatToHoursMins(hours)
+{
+  if (0 == hours) return hours;
+  mins = Math.floor((hours - Math.floor(hours)) * 60)
+  str = '';
+  if (hours) str += Math.floor(hours) + 'h';
+  if (mins)
+  {
+    if (str) str += ' ';
+    str += mins + 'm';
+  }
+  return str;
+}
+
+function IntToYesNo(boolflag)
+{
+  if (boolflag == '1')
+    return 'Yes';
+  
+  if (boolflag == '0')
+    return 'No';
+  
+  return boolflag;
+}
+
+
+InitBilling = function(){
+  // Convert totalhours field to non-editable
+  try
+  {
+    var x = document.getElementById('totalhours');
+    x = x || document.getElementById('field-totalhours');
+    if (x)
+    {
+      var p = x.parentNode;
+      var n = document.createElement('span')
+      n.id = x.id;
+      n.appendChild(document.createTextNode(x.value));
+      p.removeChild(x);
+      p.appendChild(n);
+    }
+  }
+  catch (er) {}
+  
+  // Display yes/no in the summary
+  // if we fail, then no harm done.
+  try
+  {
+    var b = document.getElementById('h_billable');
+    while (b)
+    {
+      if (!b.nextSibling) break;
+      b = b.nextSibling;
+      if (b.nodeName == 'TD')
+      {
+        b.innerHTML = IntToYesNo(b.innerHTML);
+        break;
+      }
+    }
+  }
+  catch (er) {}
+  
+  
+  // Hide the Add Hours in the title table
+  // if we fail, then no harm done.
+  try
+  {
+    var b = document.getElementById('h_hours');
+    b.firstChild.nodeValue = '';
+    b.nextSibling.nextSibling.firstChild.nodeValue = '';
+  }
+  catch (er) {}
+  
+  
+  // Convert hours from float to hours minutes seconds
+  // if we fail, then no harm done.
+  try
+  {
+    fields = Array('estimatedhours', 'totalhours');
+    for (i=0; i < 2; ++i) 
+    {
+      var b = document.getElementById('h_' + fields[i]);
+      while (b)
+      {
+        if (!b.nextSibling) break;
+        b = b.nextSibling;
+        if (b.nodeName == 'TD')
+        {
+          b.innerHTML = FloatToHoursMins(b.innerHTML);
+          break;
+        }
+      }
+    }
+  }
+  catch (er) {}
+  
+  // Convert all relevent ticket changes to hours/minutes
+  // if we fail, then no harm done.
+  try
+  {
+    changes = getElementsByClassName('changes', 'ul', document.getElementById('changelog'));
+    for (i=0; i < changes.length; ++i)
+    {
+      change = changes[i];
+      for (j=0; j < change.childNodes.length; ++j)
+      {
+        li = change.childNodes[j];
+        if (li.nodeName != 'LI') continue;
+        // We look for a STRONG childNode
+        if (!li.firstChild 
+            || li.firstChild.nodeName != 'STRONG'
+            || !li.firstChild.firstChild
+            || li.firstChild.firstChild.nodeName != '#text')
+        {
+          continue;
+        }
+        
+        field = li.firstChild.firstChild.nodeValue;
+        if (field == 'billable')
+        {
+          for (k=1; k < li.childNodes.length; ++k)
+          {
+            if (li.childNodes[k].nodeName != 'EM'
+                || !li.childNodes[k].firstChild
+                || li.childNodes[k].firstChild.nodeName != '#text')
+            {
+              continue;
+            }
+            li.childNodes[k].firstChild.nodeValue = IntToYesNo(li.childNodes[k].firstChild.nodeValue);
+          }
+        }
+        else if (field == 'hours'
+                || field == 'estimatedhours'
+                || field == 'totalhours')
+        {
+          for (k=1; k < li.childNodes.length; ++k)
+          {
+            if (li.childNodes[k].nodeName != 'EM'
+                || !li.childNodes[k].firstChild
+                || li.childNodes[k].firstChild.nodeName != '#text')
+            {
+              continue;
+            }
+            li.childNodes[k].firstChild.nodeValue = FloatToHoursMins(li.childNodes[k].firstChild.nodeValue);
+          }
+        }
+      }
+    }
+  }
+  catch (er) {}
+}

Property changes on: timingandestimationplugin/htdocs/ticket.js
___________________________________________________________________
Name: svn:mime-type
   + text/javascript
Name: svn:eol-style
   + native

Index: timingandestimationplugin/reports.py
===================================================================
--- timingandestimationplugin/reports.py	(revision 2430)
+++ timingandestimationplugin/reports.py	(working copy)
@@ -8,7 +8,6 @@
         {
     "uuid":"b24f08c0-d41f-4c63-93a5-25e18a8513c2",
     "title":"Ticket Work Summary",
-    "reportnumber":None,
     "version":14,
     "sql":"""
 SELECT __ticket__ as __group__, __style__, __ticket__,
@@ -50,7 +49,6 @@
         {
     "uuid":"af13564f-0e36-4a17-96c0-632dc68d8d14",
     "title":"Milestone Work Summary",
-    "reportnumber":None,
     "version":13,
     "sql":"""
 
@@ -98,7 +96,6 @@
     {
     "uuid":"7bd4b0ce-da6d-4b11-8be3-07e65b540d99",
     "title":"Developer Work Summary",
-    "reportnumber":None,
     "version":13,
     "sql":"""
 SELECT author as __group__,__style__, ticket,
@@ -140,7 +137,6 @@
 {
     "uuid":"8d785cdb-dcf5-43c9-b2a6-216997b0011a",
     "title": "Ticket Hours",
-    "reportnumber": None,
     "version":10,
     "sql": """
 SELECT __color__, __style__, ticket, summary, component ,version, severity,
@@ -210,7 +206,6 @@
 {
     "uuid":"71e7c36d-e512-4d0b-b499-087d4d20ff0b",
     "title": "Ticket Hours with Description",
-    "reportnumber": None,
     "version":11,
     "sql": """
 SELECT __color__,  __style__,  ticket, summary, component ,version, severity,
@@ -289,7 +284,6 @@
     {
     "uuid":"5f33b102-e6a6-47e8-976c-ac7a6794a909",
     "title":"Ticket Hours Grouped By Component",
-    "reportnumber":None,
     "version":10,
     "sql": """
 SELECT __color__, __group__, __style__, ticket, summary, __component__ ,version,
@@ -370,7 +364,6 @@
     {
     "uuid":"7816f034-a174-4a94-aed6-358fb648b2fc",
     "title":"Ticket Hours Grouped By Component with Description",
-    "reportnumber":None,
     "version":9,
     "sql": """
 SELECT __color__, __group__, __style__,  ticket, summary, __component__ ,
@@ -446,7 +439,6 @@
     {
     "uuid":"03815803-7688-4f3a-8e65-8d254cc1d1fb",
     "title":"Ticket Hours Grouped By Milestone",
-    "reportnumber":None,
     "version":10,
     "sql": """
 SELECT __color__, __group__, __style__,  ticket, summary, component ,version,
@@ -523,7 +515,6 @@
         {
     "uuid":"040c9025-7641-4d18-96ad-2b26b4095566",
     "title":"Ticket Hours Grouped By MileStone with Description",
-    "reportnumber":None,
     "version":10,
     "sql": """
 SELECT __color__, __group__, __style__,  ticket, summary, component ,version, severity,
Index: timingandestimationplugin/ticket_webui.py
===================================================================
--- timingandestimationplugin/ticket_webui.py	(revision 2430)
+++ timingandestimationplugin/ticket_webui.py	(working copy)
@@ -23,25 +23,8 @@
 
     def get_navigation_items(self, req):
         if re.search('ticket', req.path_info):
+            add_script(req, 'Billing/ticket.js')
             yield 'mainnav', "ticket-addon", \
                   Markup("""<script language="javascript" type="text/javascript">
-                  function AddEventListener( elem, evt, func, capture){
-                    capture = capture || false;
-                    if(elem.addEventListener) elem.addEventListener( evt, func, capture);
-                    else elem.attachEvent('on'+evt, func);
-                    return func;
-                  };
-                  InitBilling = function(){
-                    var x = document.getElementById('totalhours');
-                    x = x || document.getElementById('field-totalhours');
-                    if(x){
-                      var p = x.parentNode;
-                      var n = document.createElement('span')
-                      n.id = x.id;
-                      n.innerHTML = x.value
-                      p.removeChild(x);
-                      p.appendChild(n);
-                    }
-                  }
-                  AddEventListener(window, 'load', InitBilling)
+                  teAddEventListener(window, 'load', InitBilling)
                   </script>""")
