<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'));
+ set_cell_div($cell,$cell.data('content'),$cell.data('bgcolor'));
+ }
+
+ // 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.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++) {
$this.css('background-color', '#ffffdd');
+ set_cell_div($this,'','#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;
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');
+ 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;
$this = $this.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
}
-% }
-
- var drag_cells = 0;
- var drag_hi;
- function boxon_drop(event, ui) {
- //var $this = $(what);
- var $this = $(this);
+% } else {
- drag_cells = ui.draggable.data('cells');
+ // functions for drag-and-drop rescheduling
- if ( drag_hi ) {
- boxoff_do(drag_hi);
+ // 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('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')) {
+ 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;
+ $where = $where.parent().parent().children('tr').eq(rownum+1).children('td').eq(colnum);
}
- drag_hi = $this;
+ return true;
+ }
- for ( var c=0; c < drag_cells; c++) {
+ // 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'
+ });
+ }
- /* 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); */
+ // makes cell draggable (able to be rescheduled)
+ function set_draggable_cell ($cell) {
+ var $div = $cell.data('div');
+ $div.draggable({
+ containment: '.titlebox-content',
+ revert: true,
+ revertDuration: 0,
+ start: appointment_drag_start,
+ stop: appointment_drag_stop,
+ zIndex: 10,
+ });
+ }
- $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');
+ // 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');
+ set_cell_div($cell,'','#FFFFFF');
+ }
+
+ // track drag highlighting
+ var drag_hi;
+
+ // clear drag highlighting
+ function clear_drag_hi (cells) {
+ if ( drag_hi ) {
+ 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);
+ }
+ 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;
+ }
+ }
+ // drag start event
+ function appointment_drag_start(event, ui) {
+ var $this = $(this);
+ // 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');
+ // 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 ($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);
}
-
-
}
- 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);
+ // cell that's dragging
+ $this = $this.data('cell');
+ var cells = $this.data('cells');
+ clear_drag_hi(cells);
+ $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'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')) {
+ set_cell_div($this,'','#ffffdd');
+ } else {
+ $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);
}
}
+ // 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 ticketid = ui.draggable.data('ticketid');
- var length = ui.draggable.data('length');
- var bgcolor = ui.draggable.data('bgcolor');
+ 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');
- var username = $(this).data('username');
-
+ 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 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 );
+ var droppable = $this;
+ ui.draggable.effect( "transfer", { to: droppable }, 420 );
% #tell the backend to reschedule it
var url = "<% popurl(3) %>misc/xmlhttp-ticket-update.html?" +
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 = 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 = 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;
- $('#'+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);
+ $cell.data('div').draggable('destroy');
+ set_schedulable_cell($cell);
+ set_droppable_cell($cell);
}
-% #maybe use that animation which shows the box from point A to B
-
- if ( drag_hi ) {
- boxoff_do(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 ) {
- $('#'+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 );
- }
+ 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,
@_,
Query => "( Status = 'new' OR Status = 'open' OR Status = 'stalled')
- AND ( Type = 'reminder' OR 'Type' = 'ticket' )",
- #XXX and we have the magic custom field
+ AND ( Type = 'reminder' OR 'Type' = 'ticket' )
+ AND Queue = $queueid ",
slots => scalar(@usernames),
Embed => 'Schedule.html',
DimPast => 1,
#oops, more freeside abstraction-leaking
custnum => $ARGS{custnum},
pkgnum => $ARGS{pkgnum},
+ RedirectToBasics => $ARGS{RedirectToBasics},
],
&>
</%ONCE>
<%init>
+#abstraction-leaking
+my $conf = new FS::Conf;
+my $queueid = $conf->config('ticket_system-appointment-queueid')
+ or die "ticket_system-appointment-queueid configuration not set";
+
my @files = ();
#if ( ! $initialized ) {
push @files, map "overlibmws$_", ( '', qw( _iframe _draggable _crossframe ) );