1 <& /Elements/Header, Title => 'Schedule', JavaScript => 0 &>
3 <SCRIPT TYPE="text/javascript">
9 for ( var c=0; c < <%$cells%>; c++) {
11 $this.css('background-color', '#ffffdd');
13 $this.css('border-top', '1px double black');
14 $this.css('border-left', '1px double black');
15 $this.css('border-right', '1px solid black');
16 } else if ( c == <%$cells-1%> ) {
17 $this.css('border-left', '1px double black');
18 $this.css('border-right', '1px solid black');
19 $this.css('border-bottom', '1px solid black');
21 $this.css('border-left', '1px double black');
22 $this.css('border-right', '1px solid black');
25 var rownum = $this.parent().prevAll('tr').length;
26 var colnum = $this.prevAll('td').length;
27 $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
31 function boxoff(what) {
33 for ( var c=0; c < <%$cells%>; c++) {
35 //$this.css('background-color', '');
36 //$this.css('border', ''); //IE8 woes, removes cell borders
37 $this.removeAttr('style'); //slightly "flashy" on cell changes under IE8
38 //but at least it doesn't remove cell borders
40 var rownum = $this.parent().prevAll('tr').length;
41 var colnum = $this.prevAll('td').length;
42 $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
51 function boxon_drop(event, ui) {
52 //var $this = $(what);
55 drag_cells = ui.draggable.data('cells');
62 for ( var c=0; c < drag_cells; c++) {
64 /* well, its not exactly what i want, would prefer if it could properly
65 mouse in-out, but this sorta helps for now?
66 revisit when everthing else is working */
67 /* $this.effect("highlight", {}, 1500); */
69 $this.css('background-color', '#ffffdd');
71 $this.css('border-top', '1px double black');
72 $this.css('border-left', '1px double black');
73 $this.css('border-right', '1px solid black');
74 } else if ( c == (drag_cells-1) ) {
75 $this.css('border-left', '1px double black');
76 $this.css('border-right', '1px solid black');
77 $this.css('border-bottom', '1px solid black');
79 $this.css('border-left', '1px double black');
80 $this.css('border-right', '1px solid black');
83 var rownum = $this.parent().prevAll('tr').length;
84 var colnum = $this.prevAll('td').length;
85 $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
91 function boxoff_do(what) {
95 for ( var c=0; c < drag_cells; c++) {
97 //$this.css('background-color', '');
98 //$this.css('border', ''); //IE8 woes, removes cell borders
99 $this.removeAttr('style'); //slightly "flashy" on cell changes under IE8
100 //but at least it doesn't remove cell borders
102 var rownum = $this.parent().prevAll('tr').length;
103 var colnum = $this.prevAll('td').length;
104 $this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
108 function reschedule_appointment( event, ui ) {
110 % #get the ticket number and appointment length (from the draggable object)
111 var ticketid = ui.draggable.data('ticketid');
112 var length = ui.draggable.data('length');
113 var bgcolor = ui.draggable.data('bgcolor');
115 % #and.. the new date and time, and username (from the droppable object)
116 var starts = $(this).data('starts');
117 var username = $(this).data('username');
119 var due = parseInt(starts) + parseInt(length);
121 var n_epoch = $(this).data('epoch');
122 var n_st_tod_row = $(this).data('tod_row');
124 var draggable = ui.draggable;
125 var droppable = $(this);
126 draggable.effect( "transfer", { to: droppable }, 1000 );
128 % #tell the backend to reschedule it
129 var url = "<% popurl(3) %>misc/xmlhttp-ticket-update.html?" +
130 "id=" + ticketid + ";starts=" + starts + ";due=" + due +
131 ";username=" + username;
133 $.getJSON( url, function( data ) {
134 if ( data.error && data.error.length ) {
135 % #error? "that shouldn't happen" but should display
137 % #XX and should revert the dragable...
140 //draggable.effect( "transfer", { to: droppable }, 1000 );
142 var label = data.sched_label;
144 % #remove the old appointment entirely
145 var epoch = ui.draggable.data('epoch');
146 var st_tod_row = ui.draggable.data('tod_row');
147 var old_username = ui.draggable.data('username');
148 var cells = ui.draggable.data('cells');
149 for ( var c=0; c < cells; c++) {
150 var tod_row = parseInt(st_tod_row) + (c * <%$timestep%>);
151 var td_id = 'td_' + epoch +
152 '_' + String( tod_row ) +
154 $('#'+td_id).css('background-color', '#FFFFFF');
155 $('#'+td_id).text('');
156 % #(and make those boxes droppable)
157 $('#'+td_id).droppable({
159 drop: reschedule_appointment,
164 % #maybe use that animation which shows the box from point A to B
169 for ( var d=0; d < cells; d++) {
170 var n_tod_row = parseInt(n_st_tod_row) + (d * <%$timestep%>);
171 var n_td_id = 'td_' + n_epoch +
172 '_' + String( n_tod_row ) +
174 $('#'+n_td_id).css('background-color', bgcolor);
175 % #remove their droppable
176 $('#'+n_td_id).droppable('destroy');
178 $('#'+n_td_id).text(label);
179 % #(and make the top draggable, so we could do it all over again)
180 $('#'+n_td_id).draggable({
181 containment: '.titlebox-content',
182 %# revert: 'invalid',
186 $('#'+n_td_id).data('ticketid', ticketid );
187 $('#'+n_td_id).data('length', length );
188 $('#'+n_td_id).data('cells', cells );
189 $('#'+n_td_id).data('bgcolor', bgcolor );
201 <& /Search/Calendar.html,
203 Query => "( Status = 'new' OR Status = 'open' OR Status = 'stalled')
204 AND ( Type = 'reminder' OR 'Type' = 'ticket' )",
205 #XXX and we have the magic custom field
206 slots => scalar(@usernames),
207 Embed => 'Schedule.html',
209 Display => 'Schedule',
210 DisplayArgs => [ username => \@usernames,
211 LengthMin => $LengthMin,
212 #oops, more freeside abstraction-leaking
213 custnum => $ARGS{custnum},
214 pkgnum => $ARGS{pkgnum},
220 my $timestep = RT->Config->Get('CalendarWeeklySizeMin') || 30; #1/2h
226 #if ( ! $initialized ) {
227 push @files, map "overlibmws$_", ( '', qw( _iframe _draggable _crossframe ) );
228 push @files, map { "${_}contentmws" } qw( iframe ajax );
232 if ( ref($ARGS{username}) ) {
233 @usernames = @{ $ARGS{username} };
234 } elsif ( $ARGS{username} ) {
235 @usernames = ( $ARGS{username} );
237 #look them up ourslves... again, more FS abstraction-leaking, but
238 # we want to link to the schedule view, and better than doing this every
240 use FS::Record qw( qsearch );
242 my @sched_item = qsearch('sched_item', { 'disabled' => '', });
243 @usernames = map $_->access_user->username, @sched_item;
246 ( my $LengthMin = $ARGS{LengthMin} ) =~ /^\d+$/ or die 'non-numeric LengthMin';
248 my $cells = int($LengthMin / $timestep);
249 $cells++ if $LengthMin % $timestep;