From a014327f05a153450aa407a9a58aa48e2632755f Mon Sep 17 00:00:00 2001 From: Christian Binder Date: Fri, 15 Dec 2006 20:05:47 +0000 Subject: [PATCH] drag and drop for calendar for all those who cannot wait for cooxdoo or dojoproject :o) - it is disabled by default - if you want to use it you have to go to common preferences and enable drag and drop (last entry before template-specific settings) - just for Mozilla based browsers ATM, all other browsers get auto-disabled - it lacks a lot features, e.g. recurring events and whole day events but this will come - HAVE FUN --- calendar/inc/class.ajaxcalendar.inc.php | 66 ++++++++++++++ calendar/inc/class.uical.inc.php | 1 + calendar/inc/class.uiviews.inc.php | 112 +++++++++++++++++++++--- calendar/js/dragDropFunctions.js | 65 ++++++++++++++ preferences/inc/hook_settings.inc.php | 9 ++ 5 files changed, 241 insertions(+), 12 deletions(-) create mode 100644 calendar/inc/class.ajaxcalendar.inc.php create mode 100644 calendar/js/dragDropFunctions.js diff --git a/calendar/inc/class.ajaxcalendar.inc.php b/calendar/inc/class.ajaxcalendar.inc.php new file mode 100644 index 0000000000..9385432753 --- /dev/null +++ b/calendar/inc/class.ajaxcalendar.inc.php @@ -0,0 +1,66 @@ + + * @package calendar + * @copyright (c) 2006 by Christian Binder + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id: class.ajaxcalendar.inc.php 22777 2006-11-26 20:55:00Z jaytraxx $ + */ + +require_once(EGW_INCLUDE_ROOT.'/calendar/inc/class.bocalupdate.inc.php'); + +/** + * General object of the calendar ajax class + * + * @package calendar + * @author Christian Binder + * @copyright (c) 2006 by Christian Binder + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + */ + +class ajaxcalendar { + + /** + * @var object $calendar object to handle events + */ + var $calendar; + + function ajaxcalendar() { + $this->calendar = new bocalupdate; + } + + /** + * moves an event to another date/time + * + * @param string $eventID id of the event which has to be moved + * @param string $calendarOwner the owner of the calendar the event is in + * @param string $targetDateTime the datetime where the event should be moved to, format: YYYYMMDD + * @param string $targetOwner the owner of the target calendar + * @return string XML response if no error occurs + */ + function moveEvent($eventId,$calendarOwner,$targetDateTime,$targetOwner) + { + // we do not allow dragging into another users calendar ATM + if(!$calendarOwner == $targetOwner) + { + return false; + } + + $event=$this->calendar->read($eventId); + $duration=$event['end']-$event['start']; + + $event['start'] = $this->calendar->date2ts($targetDateTime); + $event['end'] = $event['start']+$duration; + + $result=$this->calendar->update($event); + //Todo: handle the result !!! + + $response =& new xajaxResponse(); + $response->addRedirect($PHP_SELF); + + return $response->getXML(); + } +} diff --git a/calendar/inc/class.uical.inc.php b/calendar/inc/class.uical.inc.php index 9f23a19ae0..6c7e4934bf 100644 --- a/calendar/inc/class.uical.inc.php +++ b/calendar/inc/class.uical.inc.php @@ -233,6 +233,7 @@ class uical */ function do_header() { + $GLOBALS['egw_info']['flags']['include_xajax'] = true; $GLOBALS['egw']->common->egw_header(); if ($_GET['msg']) echo '

'.$this->html->htmlspecialchars($_GET['msg'])."

\n"; diff --git a/calendar/inc/class.uiviews.inc.php b/calendar/inc/class.uiviews.inc.php index 77d8aee520..dd0d5f8461 100644 --- a/calendar/inc/class.uiviews.inc.php +++ b/calendar/inc/class.uiviews.inc.php @@ -13,6 +13,7 @@ /* $Id$ */ include_once(EGW_INCLUDE_ROOT . '/calendar/inc/class.uical.inc.php'); +include_once(EGW_INCLUDE_ROOT . '/phpgwapi/inc/class.dragdrop.inc.php'); /** * Class to generate the calendar views and the necesary widgets @@ -90,6 +91,13 @@ class uiviews extends uical */ var $use_time_grid=true; + /** + * Dragdrop Object + * + * @var object $dragdrop; + */ + var $dragdrop; + /** * Can we display the whole day in a timeGrid of the size of the workday and just scroll to workday start * @@ -138,6 +146,7 @@ class uiviews extends uical $this->holidays = $this->bo->read_holidays($this->year); $this->check_owners_access(); + $this->dragdrop = new dragdrop(); } /** @@ -320,6 +329,10 @@ class uiviews extends uical echo $content; } + + // make wz_dragdrop elements work + $this->dragdrop->setJSCode(); + return $content; } @@ -442,6 +455,10 @@ class uiviews extends uical echo $content; } + + // make wz_dragdrop elements work + $this->dragdrop->setJSCode(); + return $content; } @@ -514,10 +531,17 @@ class uiviews extends uical { echo $cols[0]; } + // make wz_dragdrop elements work + $this->dragdrop->setJSCode(); } else { - return $this->timeGridWidget($this->bo->search($this->search_params),$this->cal_prefs['interval'],300); + $content = $this->timeGridWidget($this->bo->search($this->search_params),$this->cal_prefs['interval'],300); + + // make wz_dragdrop elements work + $this->dragdrop->setJSCode(); + + return $content; } } @@ -791,6 +815,7 @@ class uiviews extends uical } $html .= "\n"; } + return $html; } @@ -880,6 +905,16 @@ class uiviews extends uical if ($this->use_time_grid) { + // drag and drop: check if the current user has EDIT permissions on the grid + if($owner) + { + $dropPermission = $this->bo->check_perms(EGW_ACL_EDIT,0,$owner); + } + else + { + $dropPermission = true; + } + // adding divs to click on for each row / time-span for($t = $this->scroll_to_wdstart ? 0 : $this->wd_start,$i = 1+$this->extraRows; $t <= $this->wd_end || $this->scroll_to_wdstart && $t < 24*60; @@ -888,20 +923,35 @@ class uiviews extends uical $linkData = array( 'menuaction' =>'calendar.uiforms.edit', 'date' => $day_ymd, - 'hour' => floor($t / 60), - 'minute' => floor($t % 60), + 'hour' => sprintf("%02d",floor($t / 60)), + 'minute' => sprintf("%02d",floor($t % 60)), ); if ($owner) $linkData['owner'] = $owner; + + $droppableDateTime = $linkData['date'] . "T" . $linkData['hour'] . $linkData['minute']; + $droppableID='drop_'.$droppableDateTime.'_O'.$owner; - $html .= $indent."\t".'
'."\n"; + + if($dropPermission) + { + $this->dragdrop->addDroppable( + $droppableID, + array( + 'datetime'=>$droppableDateTime, + 'owner'=>$owner ? $owner : $this->user, + ) + ); + } } } // displaying all event columns of the day foreach($eventCols as $n => $eventCol) { $html .= $this->eventColWidget($eventCol,!$n ? 0 : 60-10*(count($eventCols)-$n), - count($eventCols) == 1 ? 100 : (!$n ? 80 : 50),$indent."\t"); + count($eventCols) == 1 ? 100 : (!$n ? 80 : 50),$indent."\t", + $owner ? $owner : $this->user); } $html .= $indent."\n"; // calDayCol @@ -968,8 +1018,9 @@ class uiviews extends uical * @param int $left start of the widget * @param int $width width of the widget * @param string $indent string for correct indention + * @param int $owner owner of the eventCol */ - function eventColWidget($events,$left,$width,$indent) + function eventColWidget($events,$left,$width,$indent,$owner) { if ($this->debug > 1 || $this->debug==='eventColWidget') $this->bo->debug_message('uiviews::eventColWidget(%1,left=%2,width=%3,)',False,$events,$left,$width); @@ -977,7 +1028,7 @@ class uiviews extends uical (!$this->use_time_grid ? ' top: '.$this->rowHeight.'%;' : '').'">'."\n"; foreach($events as $event) { - $html .= $this->eventWidget($event,$width,$indent."\t"); + $html .= $this->eventWidget($event,$width,$indent."\t",$owner); } $html .= $indent."\n"; @@ -992,11 +1043,12 @@ class uiviews extends uical * @param $event array with the data of event to show * @param $width int width of the widget * @param string $indent string for correct indention + * @param int $owner owner of the calendar the event is in * @param boolean $return_array=false should an array with keys(tooltip,popup,html) be returned or the complete widget as string * @param string $block='event_widget' template used the render the widget * @return string/array */ - function eventWidget($event,$width,$indent,$return_array=false,$block='event_widget') + function eventWidget($event,$width,$indent,$owner,$return_array=false,$block='event_widget') { if ($this->debug > 1 || $this->debug==='eventWidget') $this->bo->debug_message('uiviews::eventWidget(%1,width=%2)',False,$event,$width); @@ -1159,10 +1211,39 @@ class uiviews extends uical { $style = 'position: relative; margin-top: 3px;'; } - return $indent.'
html->tooltip($tooltip,False,array('BorderWidth'=>0,'Padding'=>0)). - '>'."\n".$ie_fix.$html.$indent."
\n"; + '>'."\n".$ie_fix.$html."\n". + $indent.""."\n"; + + // ATM we do not support whole day events or recurring events for dragdrop + if ( $this->use_time_grid && + $this->bo->check_perms(EGW_ACL_EDIT,$event['id']) && + !$event['whole_day_on_top'] && + !$event['whole_day'] && + !$event['recur_type'] + ) + { + // register event as draggable + $this->dragdrop->addDraggable( + $draggableID, + array( + 'eventId'=>$event['id'], + 'eventOwner'=>$event['owner'], + 'calendarOwner'=>$owner, + 'errorImage'=>addslashes($this->html->image('phpgwapi','dialog_error',false,'style="width: 16px;"')), + 'loaderImage'=>addslashes($this->html->image('phpgwapi','ajax-loader')), + ), + 'calendar.dragDropFunctions.dragEvent', + 'calendar.dragDropFunctions.dropEvent' + ); + } + + return $html; } function add_nonempty($content,$label,$one_per_line=False,$space = True) @@ -1781,11 +1862,18 @@ class uiviews extends uical { $start = $this->bo->date2array($event['start']); $end = $this->bo->date2array($event['end']); - if(!$start['hour'] && !$start['minute'] && $end['hour'] == 23 && $end['minute'] == 59 && $event['non_blocking']) + if(!$start['hour'] && !$start['minute'] && $end['hour'] == 23 && $end['minute'] == 59) { + if($event['non_blocking']) + { $dayEvents[$day][$num]['whole_day_on_top']=true; $this->whole_day_positions[$num]=($this->rowHeight*($num+2)); $extraRowsToAdd++; + } + else + { + $dayEvents[$day][$num]['whole_day']=true; + } } } // check after every day if we have to increase $this->extraRows diff --git a/calendar/js/dragDropFunctions.js b/calendar/js/dragDropFunctions.js new file mode 100644 index 0000000000..d8a953de61 --- /dev/null +++ b/calendar/js/dragDropFunctions.js @@ -0,0 +1,65 @@ +function dragEvent() +{ + if(minOffset()) + { + // make a snapshot of the old (original) innerHTML of the dragged event + if(!dd.obj.oldInnerHTML) + { + dd.obj.oldInnerHTML = dd.obj.div.innerHTML; + } + + if(dropTarget = dd.obj.getEltBelow()) + { + var datetime = dropTarget.my_datetime; + } + + // we just allow to drop within the users own calendar + // and not crossing into another calendar ATM + if(datetime && (dd.obj.my_calendarOwner == dropTarget.my_owner )) + { + dd.obj.div.innerHTML = '
' + datetime.substr(9,2) + ":" + datetime.substr(11,2) + '
'; + } else { + + dd.obj.div.innerHTML = '
' + dd.obj.my_errorImage + '
'; + } + } +} + +function dropEvent() +{ + // minimum requirements for ajax call + if( minOffset() && + (dropTarget = dd.obj.getEltBelow()) && + (dropTarget.my_datetime) && + (dd.obj.my_calendarOwner == dropTarget.my_owner) + ) + { + dd.obj.div.innerHTML = '
' + dd.obj.my_loaderImage + '
'; + + xajax_doXMLHTTP( + 'calendar.ajaxcalendar.moveEvent', + dd.obj.my_eventId, + dd.obj.my_calendarOwner, + dropTarget.my_datetime, + dropTarget.my_owner + ); + } + else + { + // abort - move to old position and restore old innerHTML + if(dd.obj.oldInnerHTML) + { + dd.obj.div.innerHTML = dd.obj.oldInnerHTML; + } + dd.obj.moveTo(dd.obj.defx,dd.obj.defy); + } +} + +function minOffset() +{ + var offsetX = Math.abs(dd.obj.defx - dd.obj.x); + var offsetY = Math.abs(dd.obj.defy - dd.obj.y); + + if(offsetX > 5 || offsetY > 5) { return true; } + return false; +} diff --git a/preferences/inc/hook_settings.inc.php b/preferences/inc/hook_settings.inc.php index f8ab0214d2..3b438826cc 100755 --- a/preferences/inc/hook_settings.inc.php +++ b/preferences/inc/hook_settings.inc.php @@ -230,5 +230,14 @@ 'help' => 'Should this help messages shown up always, when you enter the preferences or only on request.', 'xmlrpc' => False, 'admin' => False + ), + 'enable_dragdrop' => array( + 'type' => 'check', + 'label' => 'Enable drag and drop functionality (experimental)', + 'name' => 'enable_dragdrop', + 'help' => 'Enables or disables drag and drop functions in all applications. If the browser does not support '. + 'drag and drop, it will be disabled automatically. This feature is experimental at the moment.', + 'xmlrpc' => False, + 'admin' => False ) );