[freeside-commits] branch FREESIDE_3_BRANCH updated. 4b39a40f110de90403417bc75a40f35a2861126c

Jonathan Prykop jonathan at 420.am
Tue Apr 5 01:45:15 PDT 2016


The branch, FREESIDE_3_BRANCH has been updated
       via  4b39a40f110de90403417bc75a40f35a2861126c (commit)
       via  8addc352aa40a2fde9f1dd221de43371141bf7b9 (commit)
       via  e0f4fd43049197e071193762d92f5db9462fe7e4 (commit)
       via  b3ecf9c3a19f00676ff9091602be6d793748b756 (commit)
       via  653545aa57687de24286d0955a047cb20f6e0c54 (commit)
       via  378ea151268f53f875256cdbc4eb52fbee141243 (commit)
      from  a1c29e7275ec9b555667d982395c2403d67e81fb (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 4b39a40f110de90403417bc75a40f35a2861126c
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Tue Apr 5 03:44:32 2016 -0500

    RT#34237: installer scheduling [v3 only, fix to ModifyCustomFieldsPopup.html for earlier RT version]

diff --git a/rt/share/html/Ticket/ModifyCustomFieldsPopup.html b/rt/share/html/Ticket/ModifyCustomFieldsPopup.html
index 29aa989..4084f68 100755
--- a/rt/share/html/Ticket/ModifyCustomFieldsPopup.html
+++ b/rt/share/html/Ticket/ModifyCustomFieldsPopup.html
@@ -58,7 +58,7 @@
 % $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS );
 <input type="hidden" class="hidden" name="id" value="<% $TicketObj->Id %>" />
 
-<& /Elements/EditCustomFieldCustomGroupings, Object => $TicketObj &>
+<& Elements/EditCustomFields, TicketObj => $TicketObj, AsTable => 1 &>
 
 %# <& /Elements/Submit, Name => 'SubmitTicket', Label => loc('Save Changes'), Caption => loc("If you've updated anything above, be sure to"), color => "#993333" &>
   <div class="submit">

commit 8addc352aa40a2fde9f1dd221de43371141bf7b9
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Thu Mar 31 21:35:14 2016 -0500

    RT#34237: installer scheduling [draggable divs]

diff --git a/rt/share/html/Search/Schedule.html b/rt/share/html/Search/Schedule.html
index cfa4558..6a62c27 100644
--- a/rt/share/html/Search/Schedule.html
+++ b/rt/share/html/Search/Schedule.html
@@ -2,11 +2,26 @@
 
 <SCRIPT TYPE="text/javascript">
 
+  // sets cell content and bgcolor in a div, for use as a draggable
+  //   (draggable tds have border problems on FF/IE)
+  function set_cell_div ($cell,content,bgcolor) {
+    var $div = $cell.data('div');
+    if (!$div) {
+      $div = $(document.createElement('div'));
+      $div.data('cell',$cell);
+      $cell.data('div',$div);
+      $cell.append($div);
+    }
+    $div.css('width','100%');
+    $div.css('background-color', bgcolor);
+    $div.html(content || ' ');
+  }
+
   // gives cell the appearance dictated by its data
   function set_data_cell ($cell) {
     $cell.css('border',  '1px solid #D7D7D7' );
     $cell.css('background-color', $cell.data('bgcolor'));
-    $cell.html($cell.data('content'));
+    set_cell_div($cell,$cell.data('content'),$cell.data('bgcolor'));
   }
 
   // sets cell data and appearance to schedulable
@@ -56,6 +71,7 @@
     for ( var c=0; c < <%$cells%>; c++) {
 
       $this.css('background-color', '#ffffdd');
+      set_cell_div($this,'','#ffffdd');
       if ( c == 0 ) {
         $this.css('border-top', '1px double black');
       }
@@ -75,6 +91,7 @@
     var $this = $(what);
     for ( var c=0; c < <%$cells%>; c++) {
       $this.css('background-color', '#ffffff');
+      set_cell_div($this,'','#ffffff');
       $this.css('border', '1px solid #D7D7D7'); //watch out in IE8 woes, empty string removes cell borders
       var rownum = $this.parent().prevAll('tr').length;
       var colnum = $this.prevAll('td').length;
@@ -90,14 +107,19 @@
   // ticket-dependant test if we can drop here
   // prevent overlap with other appointments, while allowing appointment to overlap itself
   function can_drop ($where, ui) {
-    var cells = ui.draggable.data('cells');
-    var ticketid = ui.draggable.data('ticketid');
+    var cells = ui.draggable.data('cell').data('cells');
+    var ticketid = ui.draggable.data('cell').data('ticketid');
     for (var c=0; c < cells; c++) {
       if (!$where.is('.ui-droppable')) {
         return false;
       }
-      if ($where.data('ticketid') && ($where.data('ticketid') != ticketid)) {
-        return false;
+      if ($where.data('ticketid')) {
+        if ($where.data('ticketid') != ticketid) {
+          return false;
+        }
+        if ($where.data('offset') == c) { // don't reschedule in the same slot
+          return false;
+        }
       }
       var rownum = $where.parent().prevAll('tr').length;
       var colnum = $where.prevAll('td').length;
@@ -117,12 +139,14 @@
 
   // makes cell draggable (able to be rescheduled)
   function set_draggable_cell ($cell) {
-    $cell.draggable({
+    var $div = $cell.data('div');
+    $div.draggable({
       containment: '.titlebox-content',
       revert: true,
       revertDuration: 0,
       start: appointment_drag_start,
       stop: appointment_drag_stop,
+      zIndex: 10,
     });
   }
 
@@ -130,7 +154,7 @@
   function set_white_cell ($cell) {
     $cell.css('border',  '1px solid #D7D7D7' );
     $cell.css('background-color', '#FFFFFF');
-    $cell.html('');
+    set_cell_div($cell,'','#FFFFFF');
   }
 
   // track drag highlighting
@@ -142,6 +166,7 @@
       for ( var c=0; c < cells; c++) {
         if (drag_hi.data('isdragging')) {
           drag_hi.css('border',  '1px solid #D7D7D7' );
+          drag_hi.css('background-color',  '#FFFFFF' );
         } else {
           set_white_cell(drag_hi);
         }
@@ -156,9 +181,9 @@
   // drag start event
   function appointment_drag_start(event, ui) {
     var $this = $(this);
-    // cell that's actually dragging
-    $this.html($this.data('label'));
-    $this.css('z-index',10);
+    // cell that's dragging
+    $this = $this.data('cell');
+    set_cell_div($this,$this.data('label'),$this.data('bgcolor'));
     $this.data('isdragging',true);
     var offset = $this.data('offset');
     var cells  = $this.data('cells');
@@ -168,7 +193,11 @@
     $this = $this.parent().parent().children('tr').eq(rownum-offset).children('td').eq(colnum);
     // loop through all cells in appointment
     for ( var c=0; c < cells; c++) {
-      if (c != offset) set_white_cell($this);
+      if ($this.data('isdragging')) {
+        $this.css('background-color', '#FFFFFF');
+      } else {
+        set_white_cell($this);
+      }
       var rownum = $this.parent().prevAll('tr').length;
       var colnum = $this.prevAll('td').length;
       $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
@@ -178,10 +207,10 @@
   // drag stop event
   function appointment_drag_stop(event, ui) {
     var $this = $(this);
-    // the cell that was dragging
+    // cell that's dragging
+    $this = $this.data('cell');
     var cells = $this.data('cells');
     clear_drag_hi(cells);
-    $this.css('z-index','initial');
     $this.data('isdragging',false);
     var offset = $this.data('offset');
     // jump to first cell in appointment
@@ -199,17 +228,20 @@
 
   // drag over event
   function appointment_drag_over(event, ui) {
-    // the cell that is dragging
-    var cells = ui.draggable.data('cells');
-	// the droppable cell that you're over
+    // the cell that's dragging
+    var cells = ui.draggable.data('cell').data('cells');
+    // the droppable cell that you're over
     var $this = $(this);
     clear_drag_hi(cells);
     if (!can_drop($this, ui)) return;
     drag_hi = $this;
     // loop through potential appointment cells
     for ( var c=0; c < cells; c++) {
+      $this.css('background-color', '#ffffdd');
       if ( !$this.data('isdragging')) {
-        $this.css('background-color', '#ffffdd');
+        set_cell_div($this,'','#ffffdd');
+      } else {
+        $this.css('background-color','#ffffdd');
       }
       if ( c == 0 ) {
         $this.css('border-top', '1px double black');
@@ -228,16 +260,17 @@
   // drop event
   function reschedule_appointment( event, ui ) {
 
+	// the droppable cell that you're over
     var $this = $(this);
 
     if (!can_drop($this, ui)) return;
 
 %   #get the ticket number and appointment length (from the draggable object)
-    var draggable = ui.draggable;
-    var ticketid = draggable.data('ticketid');
-    var length   = draggable.data('length');
-    var bgcolor  = draggable.data('bgcolor');
-    var offset   = draggable.data('offset');
+    var dragcell = ui.draggable.data('cell');
+    var ticketid = dragcell.data('ticketid');
+    var length   = dragcell.data('length');
+    var bgcolor  = dragcell.data('bgcolor');
+    var offset   = dragcell.data('offset');
 
 %   #and.. the new date and time, and username (from the droppable object)
     var starts   = $this.data('starts');
@@ -247,7 +280,7 @@
     var n_st_tod_row   = $this.data('tod_row');
 
     var droppable = $this;
-    draggable.effect( "transfer", { to: droppable }, 420 );
+    ui.draggable.effect( "transfer", { to: droppable }, 420 );
 
 %   #tell the backend to reschedule it
     var url = "<% popurl(3) %>misc/xmlhttp-ticket-update.html?" +
@@ -264,23 +297,23 @@
         var label = data.sched_label;
 
         // jump to first cell in appointment
-        var rownum = draggable.parent().prevAll('tr').length;
-        var colnum = draggable.prevAll('td').length;
-        draggable = draggable.parent().parent().children('tr').eq(rownum-offset).children('td').eq(colnum);
+        var rownum = dragcell.parent().prevAll('tr').length;
+        var colnum = dragcell.prevAll('td').length;
+        dragcell = dragcell.parent().parent().children('tr').eq(rownum-offset).children('td').eq(colnum);
 
         // remove old appointment entirely
-        var epoch        = draggable.data('epoch');
-        var st_tod_row   = draggable.data('tod_row');
-        var old_username = draggable.data('username');
-        var cells        = draggable.data('cells');
+        var epoch        = dragcell.data('epoch');
+        var st_tod_row   = dragcell.data('tod_row');
+        var old_username = dragcell.data('username');
+        var cells        = dragcell.data('cells');
         for ( var c=0; c < cells; c++) {
           var tod_row = parseInt(st_tod_row) + (c * <%$timestep%>);
           var td_id = 'td_' + epoch +
                       '_' + String( tod_row ) +
                       '_' + old_username;
           var $cell = $('#'+td_id);
+          $cell.data('div').draggable('destroy');
           set_schedulable_cell($cell);
-          $cell.draggable('destroy');
           set_droppable_cell($cell);
         }
 

commit e0f4fd43049197e071193762d92f5db9462fe7e4
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Thu Mar 31 18:10:41 2016 -0500

    RT#34237: installer scheduling [SetOwner not necessarily a Steal]

diff --git a/httemplate/misc/xmlhttp-ticket-update.html b/httemplate/misc/xmlhttp-ticket-update.html
index bd58b95..e81e353 100644
--- a/httemplate/misc/xmlhttp-ticket-update.html
+++ b/httemplate/misc/xmlhttp-ticket-update.html
@@ -8,14 +8,12 @@ my $username = $cgi->param('username');
 
 my $ticket = FS::TicketSystem->get_ticket_object( \%session, ticket_id=>$id );
 
-#hmm, this should happen in a single transaction and either commit or rollback,
-# but in reality failures "Don't Happen" so its not like a ticket gets
-# half changed
+#hmm, this should happen in a single transaction and either commit or rollback
 
 my $return;
 if ( $ticket ) {
 
-  my($orv, $omsg) = $ticket->SetOwner( $username, 'Steal' );
+  my($orv, $omsg) = $ticket->SetOwner( $username );
   $orv = 1 if ! $orv && $omsg =~ /already own/i;
 
   if ( $orv ) {

commit b3ecf9c3a19f00676ff9091602be6d793748b756
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Thu Mar 31 18:08:37 2016 -0500

    RT#34237: installer scheduling [bug fixes for refactor]

diff --git a/rt/share/html/Elements/CalendarSlotSchedule b/rt/share/html/Elements/CalendarSlotSchedule
index c8d3bfa..b5c08d6 100644
--- a/rt/share/html/Elements/CalendarSlotSchedule
+++ b/rt/share/html/Elements/CalendarSlotSchedule
@@ -21,7 +21,7 @@
 %
 %   my $bgcolor = '#666666';
 %   my $border = '1px solid #555555';
-%   my $content = '';
+%   my $label = '';
 %   my $selectable = 0; # can we schedule a new appointment
 %   my $ticketid = 0;
 %   my $draggable_length = 0;
@@ -42,13 +42,20 @@
 %   }
 %
 %   #block out / show / color code existing appointments
+%   my $maxstarts = 0;
 %   foreach my $id ( keys %{ $schedule{'scheduled'} } ) {
 %
 %     my( $starts, $due, $col, $t ) = @{ $schedule{'scheduled'}->{$id} };
 %
-%     # misleading loop--at most one id will pass this test
+%     # misleading loop--at most one id should pass this test
 %     next if $starts >= ($tod_row+$timestep) || $due <= $tod_row;
 %
+%     # but, if for any reason a scheduling conflict occurs, 
+%     # use the later starting one to minimize UI conflicts--
+%     #   not to imply that this scenario has been tested or should ever happen!!!
+%     next if $starts < $maxstarts;
+%     $maxstarts = $starts;
+%
 %     $ticketid = $id;
 %     $bgcolor = '#'.$col;
 %     $border = '1px solid #D7D7D7';
@@ -60,22 +67,18 @@
 %     $cells = int( ($due-$starts) / $timestep );
 %     $cells++ if ($due-$starts) % $timestep;
 %
-%     if ( $starts >= $tod_row ) { #first row
-%
-%       #false laziness w/misc/xmlhttp-ticket-update.html & CalendarDaySchedule
-%       my %hash = $m->comp('/Ticket/Elements/Customers', Ticket => $t);
-%       my @cust_main = values( %{$hash{cust_main}} );
+%     #false laziness w/misc/xmlhttp-ticket-update.html & CalendarDaySchedule
+%     my %hash = $m->comp('/Ticket/Elements/Customers', Ticket => $t);
+%     my @cust_main = values( %{$hash{cust_main}} );
 %
-%       #false laziness w/xmlhttp-ticket-update.html
-%       $content .= FS::sched_avail::pretty_time($starts). '-'.
-%                   FS::sched_avail::pretty_time($due).
-%                   ': '. $cust_main[0]->_FreesideURILabel;
-%                   #'install for custname XX miles away'; #XXX placeholder/more
+%     #false laziness w/xmlhttp-ticket-update.html
+%     $label .= FS::sched_avail::pretty_time($starts). '-'.
+%               FS::sched_avail::pretty_time($due).
+%               ': '. $cust_main[0]->_FreesideURILabel;
+%               #'install for custname XX miles away'; #XXX placeholder/more
 %
-%     } else {
-%       $offset = int( ($tod_row - $starts) / $timestep );
-%       $offset++ if ($tod_row - $starts) % $timestep;
-%     }
+%     $offset = int( ($tod_row - $starts) / $timestep );
+%     $offset++ if ($tod_row - $starts) % $timestep;
 %   }
 %
 %   my $td_id = 'td_'. $Date->epoch. '_'. $tod_row. '_'. $username;
@@ -137,7 +140,7 @@
 %       }
 %
 %     }
-    ><% $content |h %></td>
+    ></td>
     <SCRIPT TYPE="text/javascript">
 
       var $cell_<% $td_id %> = $('#<% $td_id %>');
@@ -155,7 +158,7 @@
         $cell_<% $td_id %>,
         <% $ticketid |js_string %>,
         <% $bgcolor |n,js_string %>,
-        <% $content |n,js_string %>,
+        <% $label |n,js_string %>,
         <% $draggable_length * 60 %>,
         <% $cells %>,
         <% $offset %>
diff --git a/rt/share/html/Search/Schedule.html b/rt/share/html/Search/Schedule.html
index b16f609..cfa4558 100644
--- a/rt/share/html/Search/Schedule.html
+++ b/rt/share/html/Search/Schedule.html
@@ -24,8 +24,6 @@
   // sets cell data and appearance as an appointment
   function set_appointment_cell ($cell,ticketid,bgcolor,label,length,cells,offset) {
     $cell.data('bgcolor',  bgcolor );
-    $cell.css('background-color', bgcolor);
-    $cell.css('border',  '1px solid #D7D7D7' );
     $cell.data('ticketid', ticketid );
     $cell.data('length',   length );
     $cell.data('cells',    cells );

commit 653545aa57687de24286d0955a047cb20f6e0c54
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Wed Mar 30 07:41:51 2016 -0500

    RT#34237: installer scheduling [major refactor, many bugs fixed]

diff --git a/rt/share/html/Elements/CalendarSlotSchedule b/rt/share/html/Elements/CalendarSlotSchedule
index b82997b..c8d3bfa 100644
--- a/rt/share/html/Elements/CalendarSlotSchedule
+++ b/rt/share/html/Elements/CalendarSlotSchedule
@@ -11,6 +11,7 @@
   $pkgnum    => undef
   $RedirectToBasics => 0
 </%ARGS>
+% my $scheduling = ($custnum && $LengthMin) ? 1 : 0;
 % foreach my $username ( @username ) {
 %
 %   my %schedule = UserDaySchedule( username => $username,
@@ -18,20 +19,22 @@
 %                                   Tickets  => \@Tickets,
 %                                 );
 %
-%   my $bgcolor = '666666;border-color:#555555';
+%   my $bgcolor = '#666666';
+%   my $border = '1px solid #555555';
 %   my $content = '';
-%   my $link = '';
-%   my $selectable = 0;
-%   my $draggable_ticketid = 0;
+%   my $selectable = 0; # can we schedule a new appointment
+%   my $ticketid = 0;
 %   my $draggable_length = 0;
-%   my $droppable = 0;
-%   my $cells = 0;
+%   my $droppable = 0; # can we reschedule an appointment here
+%   my $cells = 0; # total cell count for appointment
+%   my $offset = 0; # position of cell in appointment
 %
 %   #white out available times
 %   foreach my $avail ( @{ $schedule{'avail'} } ) {
 %     my( $start, $end ) = @$avail;
 %     next if $start >= ($tod_row+$timestep) || $end <= $tod_row;
-%     $bgcolor = 'FFFFFF';
+%     $bgcolor = '#FFFFFF';
+%     $border = '1px solid #D7D7D7';
 %     $selectable = 1
 %       if $LengthMin <= $end - $tod_row  #the slot is long enough
 %       && ! grep { $_ > $tod_row && $LengthMin > $_ - $tod_row }
@@ -39,15 +42,23 @@
 %   }
 %
 %   #block out / show / color code existing appointments
-%   #my %line = ();
 %   foreach my $id ( keys %{ $schedule{'scheduled'} } ) {
 %
 %     my( $starts, $due, $col, $t ) = @{ $schedule{'scheduled'}->{$id} };
 %
+%     # misleading loop--at most one id will pass this test
 %     next if $starts >= ($tod_row+$timestep) || $due <= $tod_row;
 %
-%     $bgcolor = $col;
+%     $ticketid = $id;
+%     $bgcolor = '#'.$col;
+%     $border = '1px solid #D7D7D7';
+%     # can't schedule a new appointment
 %     $selectable = 0;
+%     # but can reschedule a ticket overlapping its old slot (filtered by can_drop)
+%     $droppable = 1 unless $scheduling;
+%     $draggable_length = $due - $starts;
+%     $cells = int( ($due-$starts) / $timestep );
+%     $cells++ if ($due-$starts) % $timestep;
 %
 %     if ( $starts >= $tod_row ) { #first row
 %
@@ -55,35 +66,23 @@
 %       my %hash = $m->comp('/Ticket/Elements/Customers', Ticket => $t);
 %       my @cust_main = values( %{$hash{cust_main}} );
 %
-%       $content .= ($content?', ':''). #$id. ': '.
-%                   #false laziness w/xmlhttp-ticket-update.html
-%                   FS::sched_avail::pretty_time($starts). '-'.
+%       #false laziness w/xmlhttp-ticket-update.html
+%       $content .= FS::sched_avail::pretty_time($starts). '-'.
 %                   FS::sched_avail::pretty_time($due).
 %                   ': '. $cust_main[0]->_FreesideURILabel;
 %                   #'install for custname XX miles away'; #XXX placeholder/more
-%       $link = qq( <A HREF="$RT::WebPath/Ticket/Display.html?id=$id" target="_blank">view</A> ).
-%               include('/elements/popup_link.html',
-%                         action=>$RT::WebPath.'/Ticket/ModifyCustomFieldsPopup.html?id='.$id,
-%                         label =>'edit',
-%                         actionlabel => 'Edit appointment',
-%                         height      => 436, # better: A + B * (num_custom_fields)
-%                      );
-%       $draggable_ticketid = $id;
-%       $draggable_length = $due - $starts;
-%
-%       $cells = int( ($due-$starts) / $timestep );
-%       $cells++ if ($due-$starts) % $timestep;
-%       
-%     #} else {
-%     #  $content .= ($content?', ':''). $id;
+%
+%     } else {
+%       $offset = int( ($tod_row - $starts) / $timestep );
+%       $offset++ if ($tod_row - $starts) % $timestep;
 %     }
 %   }
 %
 %   my $td_id = 'td_'. $Date->epoch. '_'. $tod_row. '_'. $username;
 
-    <td style = "background-color:#<%$bgcolor%>"
+    <td style = "background-color: <% $bgcolor %>; border: <% $border %>"
           ID="<% $td_id %>"
-        class = "<% ($selectable && $custnum && $LengthMin) ? 'weeklyselectable' : 'weekly' %>"
+        class = "<% ($selectable && $scheduling) ? 'weeklyselectable' : 'weekly' %>"
 %#                 <%   $is_today     ? 'today'
 %#                    : $is_yesterday ? 'yesterday'
 %#                    : $is_aweekago  ? 'aweekago'
@@ -91,7 +90,8 @@
 %#                 %>"
 %     if ( $selectable ) {
 %
-%       if ( $custnum && $LengthMin ) {
+%       # Scheduling a new appointment
+%       if ( $scheduling ) {
 %
 %         #XXX for now, construct a ticket creation URL
 %         # eventually, do much the same, but say "appointment made", show time
@@ -131,39 +131,41 @@
                         %>"
           onclick     = "window.location.href = '<% $url %>'"
 %
+%       # If not scheduling, allow drag-and-drop rescheduling
 %       } else {
 %         $droppable = 1;
 %       }
 %
 %     }
-    ><% $content |h %><% $link |n %></td>
+    ><% $content |h %></td>
     <SCRIPT TYPE="text/javascript">
 
-      $('#<% $td_id %>').data('username', "<% $username %>");
-      $('#<% $td_id %>').data('starts',   <% $Date->epoch + $tod_row*60 %>);
-      $('#<% $td_id %>').data('epoch',    <% $Date->epoch %>);
-      $('#<% $td_id %>').data('tod_row',  <% $tod_row %>);
+      var $cell_<% $td_id %> = $('#<% $td_id %>');
+      $cell_<% $td_id %>.data('username', "<% $username %>");
+      $cell_<% $td_id %>.data('starts',   <% $Date->epoch + $tod_row*60 %>);
+      $cell_<% $td_id %>.data('epoch',    <% $Date->epoch %>);
+      $cell_<% $td_id %>.data('tod_row',  <% $tod_row %>);
 
-%     if ( $droppable ) {
-        $('#<% $td_id %>').droppable({
-          over: boxon_drop,
-          drop: reschedule_appointment,
-          tolerance: 'pointer'
-        });
+%     if ($selectable) {
+      set_schedulable_cell($cell_<% $td_id %>);
 %     }
 
-%     if ( $draggable_ticketid ) {
-        $('#<% $td_id %>').draggable({
-          containment: '.titlebox-content',
-%#          revert:      'invalid',
-          revert: true,
-          revertDuration: 0,
-          stop: clear_drag_hi,
-        });
-        $('#<% $td_id %>').data('ticketid', <% $draggable_ticketid %>);
-        $('#<% $td_id %>').data('length',   <% $draggable_length * 60 %>);
-        $('#<% $td_id %>').data('cells',    <% $cells %>);
-        $('#<% $td_id %>').data('bgcolor',  "#<% $bgcolor %>");
+%     if ($ticketid) {
+      set_appointment_cell(
+        $cell_<% $td_id %>,
+        <% $ticketid |js_string %>,
+        <% $bgcolor |n,js_string %>,
+        <% $content |n,js_string %>,
+        <% $draggable_length * 60 %>,
+        <% $cells %>,
+        <% $offset %>
+      );
+%     }
+%     if ( $droppable ) {
+%       if ( $draggable_length ) {
+      set_draggable_cell($cell_<% $td_id %>);
+%       }
+      set_droppable_cell($cell_<% $td_id %>);
 %     }
 
     </SCRIPT>
diff --git a/rt/share/html/Search/Schedule.html b/rt/share/html/Search/Schedule.html
index 0dbe8c3..b16f609 100644
--- a/rt/share/html/Search/Schedule.html
+++ b/rt/share/html/Search/Schedule.html
@@ -2,8 +2,57 @@
 
 <SCRIPT TYPE="text/javascript">
 
+  // gives cell the appearance dictated by its data
+  function set_data_cell ($cell) {
+    $cell.css('border',  '1px solid #D7D7D7' );
+    $cell.css('background-color', $cell.data('bgcolor'));
+    $cell.html($cell.data('content'));
+  }
+
+  // sets cell data and appearance to schedulable
+  function set_schedulable_cell ($cell) {
+    $cell.data('bgcolor',  '#FFFFFF' );
+    $cell.data('ticketid', 0 );
+    $cell.data('length',   0 );
+    $cell.data('cells',    0 );
+    $cell.data('offset',   0 );
+    $cell.data('label',    '' );
+    $cell.data('content',  '' );
+    set_data_cell($cell);
+  }
+
+  // sets cell data and appearance as an appointment
+  function set_appointment_cell ($cell,ticketid,bgcolor,label,length,cells,offset) {
+    $cell.data('bgcolor',  bgcolor );
+    $cell.css('background-color', bgcolor);
+    $cell.css('border',  '1px solid #D7D7D7' );
+    $cell.data('ticketid', ticketid );
+    $cell.data('length',   length );
+    $cell.data('cells',    cells );
+    $cell.data('offset',   offset );
+    $cell.data('label',  label );
+    $cell.data('content', '');
+    if ( offset == 0 ) { // first row
+      var title = 
+        label +
+        ' <A HREF="<%$RT::WebPath%>/Ticket/Display.html?id=' + ticketid + '" target="_blank">view</A> ' +
+        <% include('/elements/popup_link.html',
+             action=>$RT::WebPath.'/Ticket/ModifyCustomFieldsPopup.html?id=__MAGIC_TICKET_ID__',
+             label =>'edit',
+             actionlabel => 'Edit appointment',
+             height      => 436, # better: A + B * (num_custom_fields)
+          ) |n,js_string
+        %>;
+      title = title.replace( /__MAGIC_TICKET_ID__/, ticketid );
+      $cell.data('content', title);
+    }
+    set_data_cell($cell);
+  }
+
 % if ( $cells ) {
 
+  // hover effects for scheduling new appointment
+
   function boxon(what) {
     var $this = $(what);
     for ( var c=0; c < <%$cells%>; c++) {
@@ -11,16 +60,12 @@
       $this.css('background-color', '#ffffdd');
       if ( c == 0 ) {
         $this.css('border-top', '1px double black');
-        $this.css('border-left', '1px double black');
-        $this.css('border-right', '1px solid black');
-      } else if ( c == <%$cells-1%> ) {
-        $this.css('border-left', '1px double black');
-        $this.css('border-right', '1px solid black');
+      }
+      if ( c == <%$cells-1%> ) {
         $this.css('border-bottom', '1px solid black');
-      } else {
-        $this.css('border-left', '1px double black');
-        $this.css('border-right', '1px solid black');
       }
+      $this.css('border-left', '1px double black');
+      $this.css('border-right', '1px solid black');
 
       var rownum = $this.parent().prevAll('tr').length;
       var colnum = $this.prevAll('td').length;
@@ -31,12 +76,8 @@
   function boxoff(what) {
     var $this = $(what);
     for ( var c=0; c < <%$cells%>; c++) {
-
-      //$this.css('background-color', '');
-      //$this.css('border', ''); //IE8 woes, removes cell borders
-      $this.removeAttr('style'); //slightly "flashy" on cell changes under IE8
-                                 //but at least it doesn't remove cell borders
-
+      $this.css('background-color', '#ffffff');
+      $this.css('border', '1px solid #D7D7D7'); //watch out in IE8 woes, empty string removes cell borders
       var rownum = $this.parent().prevAll('tr').length;
       var colnum = $this.prevAll('td').length;
       $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
@@ -44,14 +85,22 @@
   }
 
 
-% }
+% } else {
+
+  // functions for drag-and-drop rescheduling
 
-% # it would be better if we had draggable-specific droppables, but this will prevent overlap for now...
-  function can_drop ($where, cells) {
+  // ticket-dependant test if we can drop here
+  // prevent overlap with other appointments, while allowing appointment to overlap itself
+  function can_drop ($where, ui) {
+    var cells = ui.draggable.data('cells');
+    var ticketid = ui.draggable.data('ticketid');
     for (var c=0; c < cells; c++) {
       if (!$where.is('.ui-droppable')) {
         return false;
       }
+      if ($where.data('ticketid') && ($where.data('ticketid') != ticketid)) {
+        return false;
+      }
       var rownum = $where.parent().prevAll('tr').length;
       var colnum = $where.prevAll('td').length;
       $where = $where.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
@@ -59,71 +108,119 @@
     return true;
   }
 
-  var drag_cells = 0;
+  // makes cell droppable (can reschedule here, subject to can_drop)
+  function set_droppable_cell ($cell) {
+    $cell.droppable({
+      over: appointment_drag_over,
+      drop: reschedule_appointment,
+      tolerance: 'pointer'
+    });
+  }
+
+  // makes cell draggable (able to be rescheduled)
+  function set_draggable_cell ($cell) {
+    $cell.draggable({
+      containment: '.titlebox-content',
+      revert: true,
+      revertDuration: 0,
+      start: appointment_drag_start,
+      stop: appointment_drag_stop,
+    });
+  }
+
+  // gives cell a white (schedulable) appearance, without changing cell data
+  function set_white_cell ($cell) {
+    $cell.css('border',  '1px solid #D7D7D7' );
+    $cell.css('background-color', '#FFFFFF');
+    $cell.html('');
+  }
+
+  // track drag highlighting
   var drag_hi;
 
-  // on drag stop (regardless of if it was dropped)
-  function clear_drag_hi () {
+  // clear drag highlighting
+  function clear_drag_hi (cells) {
     if ( drag_hi ) {
-      boxoff_do(drag_hi);
+      for ( var c=0; c < cells; c++) {
+        if (drag_hi.data('isdragging')) {
+          drag_hi.css('border',  '1px solid #D7D7D7' );
+        } else {
+          set_white_cell(drag_hi);
+        }
+        var rownum = drag_hi.parent().prevAll('tr').length;
+        var colnum = drag_hi.prevAll('td').length;
+        drag_hi = drag_hi.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
+      }
       drag_hi = undefined;
     }
   }
 
-  // on drag over
-  function boxon_drop(event, ui) {
-    //var $this = $(what);
+  // drag start event
+  function appointment_drag_start(event, ui) {
     var $this = $(this);
-
-    drag_cells = ui.draggable.data('cells');
-
-    clear_drag_hi();
-
-    if (!can_drop($this, drag_cells)) return;
-
-    drag_hi = $this;
-
-    for ( var c=0; c < drag_cells; c++) {
-
-      /* well, its not exactly what i want, would prefer if it could properly
-         mouse in-out, but this sorta helps for now?
-         revisit when everthing else is working */
-/*      $this.effect("highlight", {}, 1500); */
-
-      $this.css('background-color', '#ffffdd');
-      if ( c == 0 ) {
-        $this.css('border-top', '1px double black');
-        $this.css('border-left', '1px double black');
-        $this.css('border-right', '1px solid black');
-      } else if ( c == (drag_cells-1) ) {
-        $this.css('border-left', '1px double black');
-        $this.css('border-right', '1px solid black');
-        $this.css('border-bottom', '1px solid black');
-      } else {
-        $this.css('border-left', '1px double black');
-        $this.css('border-right', '1px solid black');
-      }
-
+    // cell that's actually dragging
+    $this.html($this.data('label'));
+    $this.css('z-index',10);
+    $this.data('isdragging',true);
+    var offset = $this.data('offset');
+    var cells  = $this.data('cells');
+    // jump to first cell in appointment
+    var rownum = $this.parent().prevAll('tr').length;
+    var colnum = $this.prevAll('td').length;
+    $this = $this.parent().parent().children('tr').eq(rownum-offset).children('td').eq(colnum);
+    // loop through all cells in appointment
+    for ( var c=0; c < cells; c++) {
+      if (c != offset) set_white_cell($this);
       var rownum = $this.parent().prevAll('tr').length;
       var colnum = $this.prevAll('td').length;
       $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
     }
-
-
   }
 
-  // clears highlighted box, used by clear_hi_drag (drag stop event)
-  function boxoff_do(what) {
-
-    var $this = what;
-
-    for ( var c=0; c < drag_cells; c++) {
-
-      //$this.css('background-color', '');
-      //$this.css('border', ''); //IE8 woes, removes cell borders
-      $this.removeAttr('style'); //slightly "flashy" on cell changes under IE8
-                                 //but at least it doesn't remove cell borders
+  // drag stop event
+  function appointment_drag_stop(event, ui) {
+    var $this = $(this);
+    // the cell that was dragging
+    var cells = $this.data('cells');
+    clear_drag_hi(cells);
+    $this.css('z-index','initial');
+    $this.data('isdragging',false);
+    var offset = $this.data('offset');
+    // jump to first cell in appointment
+    var rownum = $this.parent().prevAll('tr').length;
+    var colnum = $this.prevAll('td').length;
+    $this = $this.parent().parent().children('tr').eq(rownum-offset).children('td').eq(colnum);
+    // loop through all cells in appointment
+    for ( var c=0; c < cells; c++) {
+      set_data_cell($this);
+      var rownum = $this.parent().prevAll('tr').length;
+      var colnum = $this.prevAll('td').length;
+      $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
+    }
+  }
 
+  // drag over event
+  function appointment_drag_over(event, ui) {
+    // the cell that is dragging
+    var cells = ui.draggable.data('cells');
+	// the droppable cell that you're over
+    var $this = $(this);
+    clear_drag_hi(cells);
+    if (!can_drop($this, ui)) return;
+    drag_hi = $this;
+    // loop through potential appointment cells
+    for ( var c=0; c < cells; c++) {
+      if ( !$this.data('isdragging')) {
+        $this.css('background-color', '#ffffdd');
+      }
+      if ( c == 0 ) {
+        $this.css('border-top', '1px double black');
+      }
+      if ( c == (cells-1) ) {
+        $this.css('border-bottom', '1px solid black');
+      }
+      $this.css('border-left', '1px double black');
+      $this.css('border-right', '1px solid black');
       var rownum = $this.parent().prevAll('tr').length;
       var colnum = $this.prevAll('td').length;
       $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
@@ -135,23 +232,22 @@
 
     var $this = $(this);
 
-    if (!can_drop($this, ui.draggable.data('cells'))) return;
+    if (!can_drop($this, ui)) return;
 
 %   #get the ticket number and appointment length (from the draggable object)
-    var ticketid = ui.draggable.data('ticketid');
-    var length   = ui.draggable.data('length');
-    var bgcolor  = ui.draggable.data('bgcolor');
+    var draggable = ui.draggable;
+    var ticketid = draggable.data('ticketid');
+    var length   = draggable.data('length');
+    var bgcolor  = draggable.data('bgcolor');
+    var offset   = draggable.data('offset');
 
 %   #and.. the new date and time, and username (from the droppable object)
     var starts   = $this.data('starts');
     var username = $this.data('username');
-
     var due = parseInt(starts) + parseInt(length);
-
     var n_epoch        = $this.data('epoch');
     var n_st_tod_row   = $this.data('tod_row');
 
-    var draggable = ui.draggable;
     var droppable = $this;
     draggable.effect( "transfer", { to: droppable }, 420 );
 
@@ -164,78 +260,50 @@
       if ( data.error && data.error.length ) {
 %       #error?  "that shouldn't happen" but should display 
         alert(data.error);
-%       #XX and should revert the dragable...
-      } else {
 
-        //draggable.effect( "transfer", { to: droppable }, 1000 );
+      } else {
 
         var label = data.sched_label;
 
-%       #remove the old appointment entirely
-        var epoch        = ui.draggable.data('epoch');
-        var st_tod_row   = ui.draggable.data('tod_row');
-        var old_username = ui.draggable.data('username');
-        var cells        = ui.draggable.data('cells');
+        // jump to first cell in appointment
+        var rownum = draggable.parent().prevAll('tr').length;
+        var colnum = draggable.prevAll('td').length;
+        draggable = draggable.parent().parent().children('tr').eq(rownum-offset).children('td').eq(colnum);
+
+        // remove old appointment entirely
+        var epoch        = draggable.data('epoch');
+        var st_tod_row   = draggable.data('tod_row');
+        var old_username = draggable.data('username');
+        var cells        = draggable.data('cells');
         for ( var c=0; c < cells; c++) {
           var tod_row = parseInt(st_tod_row) + (c * <%$timestep%>);
           var td_id = 'td_' + epoch +
                       '_' + String( tod_row ) +
                       '_' + old_username;
-          $('#'+td_id).css('background-color', '#FFFFFF');
-          $('#'+td_id).text('');
-%         #(and make those boxes droppable)
-          $('#'+td_id).droppable({
-            over: boxon_drop,
-            drop: reschedule_appointment,
-            tolerance: 'pointer'
-          });
+          var $cell = $('#'+td_id);
+          set_schedulable_cell($cell);
+          $cell.draggable('destroy');
+          set_droppable_cell($cell);
         }
 
-%       #maybe use that animation which shows the box from point A to B
-
-        clear_drag_hi();
+        // set appointment in new position
+        clear_drag_hi(cells);
         for ( var d=0; d < cells; d++) {
           var n_tod_row = parseInt(n_st_tod_row) + (d * <%$timestep%>);
           var n_td_id = 'td_' + n_epoch +
                         '_' + String( n_tod_row ) +
                         '_' + username;
-          $('#'+n_td_id).css('background-color', bgcolor);
-%         #remove their droppable
-          $('#'+n_td_id).droppable('destroy');
-          if ( d == 0 ) {
-            var title = 
-              label +
-              ' <A HREF="<%$RT::WebPath%>/Ticket/Display.html?id=' + ticketid + '" target="_blank">view</A> ' +
-              <% include('/elements/popup_link.html',
-                   action=>$RT::WebPath.'/Ticket/ModifyCustomFieldsPopup.html?id=__MAGIC_TICKET_ID__',
-                   label =>'edit',
-                   actionlabel => 'Edit appointment',
-                   height      => 436, # better: A + B * (num_custom_fields)
-                 ) |n,js_string
-              %>;
-            title = title.replace( /__MAGIC_TICKET_ID__/, ticketid );
-            $('#'+n_td_id).html( title );
-%           #(and make the top draggable, so we could do it all over again)
-            $('#'+n_td_id).draggable({
-              containment: '.titlebox-content',
-%#              revert:      'invalid',
-              revert: true,
-              revertDuration: 0,
-              stop: clear_drag_hi,
-            });
-            $('#'+n_td_id).data('ticketid', ticketid );
-            $('#'+n_td_id).data('length',   length );
-            $('#'+n_td_id).data('cells',    cells );
-            $('#'+n_td_id).data('bgcolor',  bgcolor );
-          }
+          var $cell = $('#'+n_td_id);
+          set_appointment_cell($cell,ticketid,bgcolor,label,length,cells,d);
+          set_draggable_cell($cell);
+          set_droppable_cell($cell);
         }
-
       }
-
     });
-
   }
 
+% } # end of rescheduling functions
+
 </SCRIPT>
 
 <& /Search/Calendar.html,

commit 378ea151268f53f875256cdbc4eb52fbee141243
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Tue Apr 5 03:21:21 2016 -0500

    Revert "RT#34237: installer scheduling [removed edit links, v3 only]"
    
    This reverts commit 22f83589b4a605b40fd8107ee949e4921c130797.

diff --git a/rt/share/html/Elements/CalendarSlotSchedule b/rt/share/html/Elements/CalendarSlotSchedule
index 8aadf0a..b82997b 100644
--- a/rt/share/html/Elements/CalendarSlotSchedule
+++ b/rt/share/html/Elements/CalendarSlotSchedule
@@ -61,14 +61,13 @@
 %                   FS::sched_avail::pretty_time($due).
 %                   ': '. $cust_main[0]->_FreesideURILabel;
 %                   #'install for custname XX miles away'; #XXX placeholder/more
-%       $link = qq( <A HREF="$RT::WebPath/Ticket/Display.html?id=$id" target="_blank">view</A> );
-%#needs higher version of rt
-%#             . include('/elements/popup_link.html',
-%#                         action=>$RT::WebPath.'/Ticket/ModifyCustomFieldsPopup.html?id='.$id,
-%#                         label =>'edit',
-%#                         actionlabel => 'Edit appointment',
-%#                         height      => 436, # better: A + B * (num_custom_fields)
-%#                      );
+%       $link = qq( <A HREF="$RT::WebPath/Ticket/Display.html?id=$id" target="_blank">view</A> ).
+%               include('/elements/popup_link.html',
+%                         action=>$RT::WebPath.'/Ticket/ModifyCustomFieldsPopup.html?id='.$id,
+%                         label =>'edit',
+%                         actionlabel => 'Edit appointment',
+%                         height      => 436, # better: A + B * (num_custom_fields)
+%                      );
 %       $draggable_ticketid = $id;
 %       $draggable_length = $due - $starts;
 %
diff --git a/rt/share/html/Search/Schedule.html b/rt/share/html/Search/Schedule.html
index 89e7cc5..0dbe8c3 100644
--- a/rt/share/html/Search/Schedule.html
+++ b/rt/share/html/Search/Schedule.html
@@ -205,15 +205,14 @@
           if ( d == 0 ) {
             var title = 
               label +
-              ' <A HREF="<%$RT::WebPath%>/Ticket/Display.html?id=' + ticketid + '" target="_blank">view</A> ';
-%#needs higher version of RT
-%#          + <% include('/elements/popup_link.html',
-%#                   action=>$RT::WebPath.'/Ticket/ModifyCustomFieldsPopup.html?id=__MAGIC_TICKET_ID__',
-%#                   label =>'edit',
-%#                   actionlabel => 'Edit appointment',
-%#                   height      => 436, # better: A + B * (num_custom_fields)
-%#                 ) |n,js_string
-%#              %>;
+              ' <A HREF="<%$RT::WebPath%>/Ticket/Display.html?id=' + ticketid + '" target="_blank">view</A> ' +
+              <% include('/elements/popup_link.html',
+                   action=>$RT::WebPath.'/Ticket/ModifyCustomFieldsPopup.html?id=__MAGIC_TICKET_ID__',
+                   label =>'edit',
+                   actionlabel => 'Edit appointment',
+                   height      => 436, # better: A + B * (num_custom_fields)
+                 ) |n,js_string
+              %>;
             title = title.replace( /__MAGIC_TICKET_ID__/, ticketid );
             $('#'+n_td_id).html( title );
 %           #(and make the top draggable, so we could do it all over again)

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

Summary of changes:
 httemplate/misc/xmlhttp-ticket-update.html        |    6 +-
 rt/share/html/Elements/CalendarSlotSchedule       |  136 ++++----
 rt/share/html/Search/Schedule.html                |  348 +++++++++++++--------
 rt/share/html/Ticket/ModifyCustomFieldsPopup.html |    2 +-
 4 files changed, 296 insertions(+), 196 deletions(-)




More information about the freeside-commits mailing list