diff options
author | Ivan Kohler <ivan@freeside.biz> | 2015-07-27 02:28:20 -0700 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2015-07-27 02:28:20 -0700 |
commit | 09ae66f29fc7cbd46c13ae1f9361713cbce54153 (patch) | |
tree | 88b2f0d09f088d3d728aacd6ac9ae5939bb6be51 /rt | |
parent | 9aee669886202be7035e6c6049fc71bc99dd3013 (diff) |
appointment drag and drop, RT#34237
Diffstat (limited to 'rt')
-rw-r--r-- | rt/share/html/Elements/CalendarSlotSchedule | 132 | ||||
-rw-r--r-- | rt/share/html/Search/Calendar.html | 2 | ||||
-rw-r--r-- | rt/share/html/Search/Schedule.html | 174 | ||||
-rw-r--r-- | rt/share/static/css/calendar.css | 4 |
4 files changed, 259 insertions, 53 deletions
diff --git a/rt/share/html/Elements/CalendarSlotSchedule b/rt/share/html/Elements/CalendarSlotSchedule index ff3e634..045d6e4 100644 --- a/rt/share/html/Elements/CalendarSlotSchedule +++ b/rt/share/html/Elements/CalendarSlotSchedule @@ -20,6 +20,10 @@ % my $bgcolor = '666666;border-color:#555555'; % my $content = ''; % my $selectable = 0; +% my $draggable_ticketid = 0; +% my $draggable_length = 0; +% my $droppable = 0; +% my $cells = 0; % % #white out available times % foreach my $avail ( @{ $schedule{'avail'} } ) { @@ -44,58 +48,104 @@ % $selectable = 0; % % if ( $starts >= $tod_row ) { #first row -% $content .= ($content?', ':''). $id. -% ': '. FS::sched_avail::pretty_time($starts). '-'. -% FS::sched_avail::pretty_time($due); +% $content .= ($content?', ':''). #$id. ': '. +% #false laziness w/xmlhttp-ticket-update.html +% FS::sched_avail::pretty_time($starts). '-'. +% FS::sched_avail::pretty_time($due); % #'install for custname XX miles away'; #XXX placeholder/more +% $draggable_ticketid = $id; +% $draggable_length = $due - $starts; +% +% $cells = int( ($due-$starts) / $timestep ); +% $cells++ if ($due-$starts) % $timestep; +% % #} else { % # $content .= ($content?', ':''). $id; % } % } +% +% my $td_id = 'td_'. $Date->epoch. '_'. $tod_row. '_'. $username; - <td style="background:#<%$bgcolor%>" - class="<% $selectable ? 'weeklyselectable' : 'weekly' %>" -%# <% $is_today ? 'today' -%# : $is_yesterday ? 'yesterday' -%# : $is_aweekago ? 'aweekago' -%# : '' -%# %>" + <td style = "background-color:#<%$bgcolor%>" + ID="<% $td_id %>" + class = "<% ($selectable && $custnum && $LengthMin) ? 'weeklyselectable' : 'weekly' %>" +%# <% $is_today ? 'today' +%# : $is_yesterday ? 'yesterday' +%# : $is_aweekago ? 'aweekago' +%# : '' +%# %>" % if ( $selectable ) { % -% #XXX for now, construct a ticket creation URL -% # eventually, do much the same, but say "appointment made", show time -% # and date, have # options to do things with it? etc. -% # then redir back to customer/appointment view i guess -% -% #abstraction is leaking like a sieve... linking back to freeside cust -% # (XXX and eventually, package) -% my $cust_main = qsearchs('cust_main', { custnum=>$custnum } ) -% or die "unknown custnum $custnum"; -% my $Queue = $cust_main->agent->ticketing_queueid || 1; # || $default_queueid;#XXX really, pick pkg_category queue -% my $member = "freeside://freeside/cust_main/$custnum"; -% -%warn my $Starts = int($tod_row/60). ':'. sprintf('%02d',$tod_row%60). ':00'; -%warn my $Due = int(($tod_row+$LengthMin)/60). ':'. -% sprintf('%02d',($tod_row+$LengthMin)%60). ':00'; -% -% my $url = $RT::WebPath. '/Ticket/Display.html?id=new'. -% "&Queue=$Queue". -% "&Owner=$username". -% '&Starts='. $Date->strftime('%F').'%20'. $Starts. -% '&Due='. $Date->strftime('%F').'%20'. $Due. -% '&new-MemberOf='. $member. #XXX uri_escape? -% '&Status=new'; -% #'&Requestors='. #XXX Freeside customer requestor(s) (package? +% if ( $custnum && $LengthMin ) { +% +% #XXX for now, construct a ticket creation URL +% # eventually, do much the same, but say "appointment made", show time +% # and date, have # options to do things with it? etc. +% # then redir back to customer/appointment view i guess +% +% #abstraction is leaking like a sieve... linking back to freeside cust +% # (XXX and eventually, package) +% my $cust_main = qsearchs('cust_main', { custnum=>$custnum } ) +% or die "unknown custnum $custnum"; +% my $Queue = $cust_main->agent->ticketing_queueid || 1; # || $default_queueid;#XXX really, pick pkg_category queue +% my $member = "freeside://freeside/cust_main/$custnum"; +% +%warn my $Starts = int($tod_row/60). ':'. sprintf('%02d',$tod_row%60). ':00'; +%warn my $Due = int(($tod_row+$LengthMin)/60). ':'. +% sprintf('%02d',($tod_row+$LengthMin)%60). ':00'; +% +% my $url = $RT::WebPath. '/Ticket/Display.html?id=new'. +% "&Queue=$Queue". +% "&Owner=$username". +% '&Starts='. $Date->strftime('%F').'%20'. $Starts. +% '&Due='. $Date->strftime('%F').'%20'. $Due. +% '&new-MemberOf='. $member. #XXX uri_escape? +% '&Status=new'; +% #'&Requestors='. #XXX Freeside customer requestor(s) (package? - onmouseover = "boxon(this);" - onmouseout = "boxoff(this);" - title = "<% 'Make appointment for '. - FS::sched_avail::pretty_time($tod_row). '-'. - FS::sched_avail::pretty_time($tod_row+$LengthMin) - %>" - onclick = "window.location.href = '<% $url %>'" + onmouseover = "boxon(this);" + onmouseout = "boxoff(this);" + title = "<% 'Make appointment for '. + FS::sched_avail::pretty_time($tod_row). '-'. + FS::sched_avail::pretty_time($tod_row+$LengthMin) + %>" + onclick = "window.location.href = '<% $url %>'" +% +% } else { +% $droppable = 1; +% } +% % } ><% $content %></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 %>); + +% if ( $droppable ) { + $('#<% $td_id %>').droppable({ + over: boxon_drop, + drop: reschedule_appointment, + tolerance: 'pointer' + }); +% } + +% if ( $draggable_ticketid ) { + $('#<% $td_id %>').draggable({ + containment: '.titlebox-content', +%# revert: 'invalid', + revert: true, + revertDuration: 0, + }); + $('#<% $td_id %>').data('ticketid', <% $draggable_ticketid %>); + $('#<% $td_id %>').data('length', <% $draggable_length * 60 %>); + $('#<% $td_id %>').data('cells', <% $cells %>); + $('#<% $td_id %>').data('bgcolor', "#<% $bgcolor %>"); +% } + + </SCRIPT> % } <%ONCE> my $default_slots = RT->Config->Get('CalendarWeeklySlots') || 5; diff --git a/rt/share/html/Search/Calendar.html b/rt/share/html/Search/Calendar.html index 092f6a5..2c19296 100644 --- a/rt/share/html/Search/Calendar.html +++ b/rt/share/html/Search/Calendar.html @@ -78,7 +78,7 @@ $DimPast => 0 </table> % } -<table class="rtxcalendar"> +<table class="<% $WeekDay ? 'rtxweeklycalendar' : 'rtxcalendar' %>"> <thead> diff --git a/rt/share/html/Search/Schedule.html b/rt/share/html/Search/Schedule.html index 34ba142..be5a140 100644 --- a/rt/share/html/Search/Schedule.html +++ b/rt/share/html/Search/Schedule.html @@ -1,14 +1,9 @@ -<& /Elements/Header, Title => 'Schedule' &> - -%#init_overlib.html -%foreach my $file (@files) { -<SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/<%$file%>.js"></SCRIPT> -%} - -<SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/jquery.js"></SCRIPT> +<& /Elements/Header, Title => 'Schedule', JavaScript => 0 &> <SCRIPT TYPE="text/javascript"> +% if ( $cells ) { + function boxon(what) { var $this = $(what); for ( var c=0; c < <%$cells%>; c++) { @@ -48,6 +43,159 @@ } } + +% } + + var drag_cells = 0; + var drag_hi; + function boxon_drop(event, ui) { + //var $this = $(what); + var $this = $(this); + + drag_cells = ui.draggable.data('cells'); + + if ( drag_hi ) { + boxoff_do(drag_hi); + } + 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'); + } + + 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); + } + + + } + + 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 + + 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); + } + } + + function reschedule_appointment( event, ui ) { + +% #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'); + +% #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 }, 1000 ); + +% #tell the backend to reschedule it + var url = "<% popurl(3) %>misc/xmlhttp-ticket-update.html?" + + "id=" + ticketid + ";starts=" + starts + ";due=" + due + + ";username=" + username; + + $.getJSON( url, function( data ) { + 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 ); + + 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'); + 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' + }); + } + +% #maybe use that animation which shows the box from point A to B + + if ( drag_hi ) { + boxoff_do(drag_hi); + } + 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 ) { + $('#'+n_td_id).text(label); +% #(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, + }); + $('#'+n_td_id).data('ticketid', ticketid ); + $('#'+n_td_id).data('length', length ); + $('#'+n_td_id).data('cells', cells ); + $('#'+n_td_id).data('bgcolor', bgcolor ); + } + } + + } + + }); + + } + </SCRIPT> <& /Search/Calendar.html, @@ -86,9 +234,13 @@ if ( ref($ARGS{username}) ) { } elsif ( $ARGS{username} ) { @usernames = ( $ARGS{username} ); } else { - #XXX shouldn't even get offered the link in the first place rather than perl - # barf, but this is better than erroring out later or empty @username - die "Can't schedule an appointment - no employees are configured as installers"; + #look them up ourslves... again, more FS abstraction-leaking, but + # we want to link to the schedule view, and better than doing this every + # menu render + use FS::Record qw( qsearch ); + use FS::sched_item; + my @sched_item = qsearch('sched_item', { 'disabled' => '', }); + @usernames = map $_->access_user->username, @sched_item; } ( my $LengthMin = $ARGS{LengthMin} ) =~ /^\d+$/ or die 'non-numeric LengthMin'; diff --git a/rt/share/static/css/calendar.css b/rt/share/static/css/calendar.css index a91917c..566f969 100644 --- a/rt/share/static/css/calendar.css +++ b/rt/share/static/css/calendar.css @@ -201,3 +201,7 @@ table.rtxweeklycalendar td.labels { border-bottom: 1px solid #eeeeee; } +.ui-effects-transfer { + border: 1px solid black; +} + |