From 1ac7324243c9f26081784125739ca86adb559c67 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 21 Jul 2015 23:45:38 +0000 Subject: [PATCH] Calendar et2 conversion work in progress. - Drag & drop reschedule across days/weeks (grid views) --- calendar/inc/class.calendar_ui.inc.php | 1 + calendar/inc/class.calendar_uiforms.inc.php | 44 +++- calendar/js/app.js | 75 ++++-- calendar/js/et2_widget_daycol.js | 47 +++- calendar/js/et2_widget_event.js | 35 ++- calendar/js/et2_widget_timegrid.js | 266 ++++++++++---------- 6 files changed, 289 insertions(+), 179 deletions(-) diff --git a/calendar/inc/class.calendar_ui.inc.php b/calendar/inc/class.calendar_ui.inc.php index bb8b4b87bf..b751403fc3 100644 --- a/calendar/inc/class.calendar_ui.inc.php +++ b/calendar/inc/class.calendar_ui.inc.php @@ -833,6 +833,7 @@ class calendar_ui $event['app_id'] .= ':'.$event['recur_date']; } $event['parts'] = implode(",\n",$this->bo->participants($event,true)); + $event['date'] = $this->bo->date2string($event['start']); // Change dates foreach(calendar_egw_record::$types['date-time'] as $field) diff --git a/calendar/inc/class.calendar_uiforms.inc.php b/calendar/inc/class.calendar_uiforms.inc.php index 38d5689f04..7f4098e7f2 100644 --- a/calendar/inc/class.calendar_uiforms.inc.php +++ b/calendar/inc/class.calendar_uiforms.inc.php @@ -914,6 +914,11 @@ class calendar_uiforms extends calendar_ui { // Directly update stored data. If event is still visible, it will // be notified & update itself. + if(!$old_event) + { + // For new events, make sure we have the whole event, not just form data + $event = $this->bo->read($event['id']); + } $this->to_client($event); $response->call('egw.dataStoreUID','calendar::'.$event['id'],$event); } @@ -1036,7 +1041,7 @@ class calendar_uiforms extends calendar_ui } else { - egw_framework::refresh_opener($msg, 'calendar', $content['id'], $button == 'save' ? 'update' : 'delete'); + egw_framework::refresh_opener($msg, 'calendar', $event['id'], $button == 'save' ? ($content['id'] ? 'update' : 'add') : 'delete'); } egw_framework::window_close(); common::egw_exit(); @@ -2549,10 +2554,29 @@ class calendar_uiforms extends calendar_ui function ajax_moveEvent($_eventId,$calendarOwner,$targetDateTime,$targetOwner,$durationT=null) { // we do not allow dragging into another users calendar ATM - if(!$calendarOwner == $targetOwner) + if($targetOwner < 0) + { + $targetOwner = [$targetOwner]; + } + if($calendarOwner !== $targetOwner && !is_array($targetOwner)) { return false; } + // But you may be viewing multiple users, or a group calendar and + // dragging your event + if(is_array($targetOwner) && !in_array($calendarOwner, $targetOwner)) + { + $return = true; + foreach($targetOwner as $owner) + { + if($owner < 0 && in_array($calendarOwner, $GLOBALS['egw']->accounts->members($owner,true))) + { + $return = false; + break; + } + } + if($return) return; + } list($eventId, $date) = explode(':', $_eventId); $old_event=$event=$this->bo->read($eventId); if (!$durationT) @@ -2608,17 +2632,23 @@ class calendar_uiforms extends calendar_ui } } - $conflicts=$this->bo->update($event); + $message = false; + $conflicts=$this->bo->update($event,false, true, false, true, $message); $response = egw_json_response::get(); - if(!is_array($conflicts)) + if(!is_array($conflicts) && $conflicts) { // Directly update stored data. If event is still visible, it will // be notified & update itself. $this->to_client($event); $response->call('egw.dataStoreUID','calendar::'.$event['id'].($date?':'.$date:''),$event); + + if(!$sameday ) + { + $response->call('egw.refresh', '','calendar',$event['id'],'update'); + } } - else + else if ($conflicts) { $response->call( 'egw_openWindowCentered2', @@ -2630,6 +2660,10 @@ class calendar_uiforms extends calendar_ui .'&cancel_needs_refresh=true', '',750,410); } + else if ($message) + { + $response->call('egw.message', implode('
', $message)); + } if ($status_reset_to_unknown) { foreach((array)$event['participants'] as $uid => $status) diff --git a/calendar/js/app.js b/calendar/js/app.js index 682279ea6e..5feaf082ca 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -247,19 +247,19 @@ app.classes.calendar = AppJS.extend( } break; case 'calendar': - debugger; var event = egw.dataGetUIDdata('calendar::'+_id); if(event && event.data && event.data.date) { var new_cache_id = this._daywise_cache_id(event.data.date) - var daywise = egw.dataGetUIDdata(new_cache_id).data || []; + var daywise = egw.dataGetUIDdata(new_cache_id); + daywise = daywise ? daywise.data : []; if(_type === 'delete') { daywise.splice(daywise.indexOf(_id),1); } - else + else if (daywise.indexOf(_id) < 0) { - daywise.push(event.date); + daywise.push(_id); } egw.dataStoreUID(new_cache_id,daywise); } @@ -338,8 +338,9 @@ app.classes.calendar = AppJS.extend( var $sortItem = jQuery(this); }, - start: function () + start: function (event, ui) { + $j('.calendar_calTimeGrid',ui.helper).css('position', 'absolute'); // Put owners into row IDs app.classes.calendar.views[state.view].etemplates[0].widgetContainer.iterateOver(function(widget) { widget.div.parents('tr').attr('data-owner',widget.options.owner); @@ -363,7 +364,7 @@ app.classes.calendar = AppJS.extend( // Enable or disable if((state.view == 'day' || state.view == 'week') && - state.owner.length > 1 && state.owner.length > egw.config('calview_no_consolidate','phpgwapi')) + state.owner.length > 1 && state.owner.length < egw.config('calview_no_consolidate','phpgwapi')) { sortable.sortable('enable') .sortable("refresh") @@ -414,26 +415,7 @@ app.classes.calendar = AppJS.extend( var view = app.classes.calendar.views[app.calendar.state.view] || false; if (view) { - if(direction > 0) - { - start = view.end_date({date:start}); - } - else - { - start = view.start_date({date:start}); - } - start.setUTCDate(start.getUTCDate()+direction); - } - // Calculate the current difference, and move - else if(app.calendar.state.first && app.calendar.state.last) - { - start = new Date(app.calendar.state.first); - end = new Date(app.calendar.state.last); - // Get the number of days - delta = (Math.round(Math.max(1,end - start)/(24*3600*1000)))*24*3600*1000; - // Adjust - start = new Date(start.valueOf() + (delta * direction )); - end = new Date(end.valueOf() + (delta * direction)); + start = view.scroll(direction * delta); } app.calendar.update_state({date:app.calendar.date.toString(start)}); @@ -516,7 +498,7 @@ app.classes.calendar = AppJS.extend( { egw().json( 'calendar.calendar_uiforms.ajax_moveEvent', - [widget.id, widget.options.value.owner, widget.options.value.start, widget.options.value.owner, widget.options.value.duration] + [widget.options.value.id, widget.options.value.owner, widget.options.value.start, widget.options.value.owner, widget.options.value.duration] ).sendRequest(true); }, @@ -2137,9 +2119,23 @@ app.classes.calendar = AppJS.extend( d.setUTCMilliseconds(0); return d; }, + /** + * Get the owner for this view + * + * This is always the owner from the given state, we use a function + * to trigger setting the widget value. + * + * @param {number[]|String} state.owner List of owner IDs, or a comma seperated list + * @returns {number[]|String} + */ owner: function(state) { return state.owner || 0; }, + /** + * Should the view show the weekends + * + * @returns {boolean} Current preference to show 5 or 7 days in weekview + */ show_weekend: function(state) { return parseInt(egw.preference('days_in_weekview','calendar')) == 7; @@ -2147,6 +2143,19 @@ app.classes.calendar = AppJS.extend( extend: function(sub) { return jQuery.extend({},this,{_super:this},sub); + }, + /** + * Determines the new date after scrolling. The default is 1 week. + * + * @param {number} delta Integer for how many 'ticks' to move, positive for + * forward, negative for backward + * @returns {Date} + */ + scroll: function(delta) + { + var d = new Date(app.calendar.state.date); + d.setUTCDate(d.getUTCDate() + (7 * delta)); + return d; } } }); @@ -2177,6 +2186,12 @@ jQuery.extend(app.classes.calendar,{ state.days = '1'; return app.calendar.View.show_weekend.call(this,state); + }, + scroll: function(delta) + { + var d = new Date(app.calendar.state.date); + d.setUTCDate(d.getUTCDate() + (delta)); + return d; } }), day4: app.classes.calendar.prototype.View.extend({ @@ -2251,6 +2266,12 @@ jQuery.extend(app.classes.calendar,{ if(week_start < d) week_start.setUTCHours(24*7); week_start.setUTCHours(week_start.getUTCHours()-1); return week_start; + }, + scroll: function(delta) + { + var d = new Date(app.calendar.state.date); + d.setUTCMonth(d.getUTCMonth() + delta); + return d; } }), diff --git a/calendar/js/et2_widget_daycol.js b/calendar/js/et2_widget_daycol.js index 09ec11b88b..b27a238fce 100644 --- a/calendar/js/et2_widget_daycol.js +++ b/calendar/js/et2_widget_daycol.js @@ -181,9 +181,9 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea } else if(typeof _date === "string") { - this._parent.date_helper.set_year(_date.substring(0,4)); - this._parent.date_helper.set_month(_date.substring(4,6)); - this._parent.date_helper.set_date(_date.substring(6,8)); + // Need a new date to avoid invalid month/date combinations when setting + // month then day + this._parent.date_helper.set_value(new Date(_date.substring(0,4),_date.substring(4,6)-1,_date.substring(6,8))); } this.date = new Date(this._parent.date_helper.getValue()); @@ -225,7 +225,11 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea var events = []; for(var i = 0; i < event_ids.length; i++) { - events.push(egw.dataGetUIDdata('calendar::'+event_ids[i]).data); + var event = egw.dataGetUIDdata('calendar::'+event_ids[i]).data; + if(event && event.date && event.date === this.options.date) + { + events.push(event); + } } this._update_events(events); },this,this.getInstanceManager().execId,this.id); @@ -253,7 +257,11 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea var events = []; for(var i = 0; i < event_ids.length; i++) { - events.push(egw.dataGetUIDdata('calendar::'+event_ids[i]).data); + var event = egw.dataGetUIDdata('calendar::'+event_ids[i]).data; + if(event && event.date && event.date === this.options.date) + { + events.push(event); + } } this._update_events(events); },this,this.getInstanceManager().execId,this.id); @@ -322,16 +330,24 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea */ _update_events: function(_events) { - // Remove all events - while(this._children.length) + var events = _events || this.getArrayMgr('content').getEntry(this.options.date) || []; + + // Remove extra events + while(this._children.length > events.length) { var node = this._children[this._children.length-1]; this.removeChild(node); node.free(); } - var events = _events || this.getArrayMgr('content').getEntry(this.options.date) || []; - - for(var c = 0; c < events.length; c++) + + // Make sure children are in cronological order, or columns are backwards + events.sort(function(a,b) { + var start = new Date(a.start) - new Date(b.start); + var end = new Date(a.end) - new Date(b.end); + return a.whole_day ? -1 : (start ? start : end); + }); + + for(var c = this._children.length; c < events.length; c++) { // Create event var event = et2_createWidget('calendar-event',{ @@ -348,7 +364,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea } // Seperate loop so column sorting finds all children in the right place - for(var c = 0; c < events.length; c++) + for(var c = 0; c < events.length && c < this._children.length; c++) { this._children[c].set_value(events[c]); } @@ -386,7 +402,14 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea { var event = this._children[i].options.value || false; if(!event) continue; - + if(event.date && event.date != this.options.date) + { + // Still have a child event that has changed date (DnD) + this._children[i].destroy(); + this.removeChild(this._children[i]); + continue; + } + var c = 0; event['multiday'] = false; if(typeof event.start !== 'object') diff --git a/calendar/js/et2_widget_event.js b/calendar/js/et2_widget_event.js index 952ec2069e..534c03e6af 100644 --- a/calendar/js/et2_widget_event.js +++ b/calendar/js/et2_widget_event.js @@ -99,13 +99,33 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], // Register for updates var app_id = this.options.value.app_id ? this.options.value.app_id : this.options.value.id + (this.options.value.recur_type ? ':'+this.options.value.recur_date : ''); egw.dataRegisterUID('calendar::'+app_id, function(event) { + if(this._parent && this.options.value.date && event.date != this.options.value.date) + { + // Date changed, reparent + var new_parent = this._parent._parent.getWidgetById(event.date); + if(new_parent) + { + new_parent.addChild(this); + } + else + { + // Could not find the right date + this._parent.removeChild(this); + this.destroy(); + } + return; + } // Copy to avoid changes, which may cause nm problems this.options.value = jQuery.extend({},event); // Let parent position this._parent.position_event(this); - - this._update(this.options.value); + + // Parent may remove this if the date isn't the same + if(this._parent) + { + this._update(this.options.value); + } },this,this.getInstanceManager().execId,this.id); @@ -123,10 +143,10 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], var eventId = event.id.match(/-?\d+\.?\d*/g)[0]; var appName = event.id.replace(/-?\d+\.?\d*/g,''); var app_id = event.app_id ? event.app_id : event.id + (event.recur_type ? ':'+event.recur_date : ''); - this._parent.date_helper.set_value(event.start); + this._parent.date_helper.set_value(event.start.valueOf ? new Date(event.start) : event.start); var formatted_start = this._parent.date_helper.getValue(); - this.set_id(eventId || event.id); + this.set_id('event_' + (eventId || event.id)); this.div // Empty & re-append to make sure dnd helpers are gone @@ -156,7 +176,8 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], // Remove any resize classes, the handles are gone due to empty() .removeClass('ui-resizable') .addClass(event.class) - .toggleClass('calendar_calEventPrivate', event.private) + .toggleClass('calendar_calEventPrivate', event.private); + this.options.class = event.class; if(event.category) { this.div.addClass('cat_' + event.category); @@ -240,9 +261,9 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], var bg_color = this.div.css('background-color'); var header_color = this.title.css('color'); - this._parent.date_helper.set_value(this.options.value.start); + this._parent.date_helper.set_value(this.options.value.start.valueOf ? new Date(this.options.value.start) : this.options.value.start); var start = this._parent.date_helper.input_date.val(); - this._parent.date_helper.set_value(this.options.value.end); + this._parent.date_helper.set_value(this.options.value.end.valueOf ? new Date(this.options.value.end) : this.options.value.end); var end = this._parent.date_helper.input_date.val(); var times = !this.options.value.multiday ? diff --git a/calendar/js/et2_widget_timegrid.js b/calendar/js/et2_widget_timegrid.js index 20b0ba0e02..c47a4eb5ec 100644 --- a/calendar/js/et2_widget_timegrid.js +++ b/calendar/js/et2_widget_timegrid.js @@ -160,35 +160,6 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz // - no action system - var timegrid = this; - // Show the current time while dragging - // Used for resizing as well as drag & drop - var drag_helper = function(event, element,height) - { - this.dropEnd = timegrid._get_time_from_position(element.getBoundingClientRect().left, - element.getBoundingClientRect().top+parseInt(height)); - - if (typeof this.dropEnd != 'undefined' && this.dropEnd.length) - { - this.dropEnd.addClass("drop-hover"); - var time = jQuery.datepicker.formatTime( - egw.preference("timeformat") == 12 ? "h:mmtt" : "HH:mm", - { - hour: this.dropEnd.attr('data-hour'), - minute: this.dropEnd.attr('data-minute'), - seconds: 0, - timezone: 0 - }, - {"ampm": (egw.preference("timeformat") == "12")} - ); - this.innerHTML = '
'+time+'
'; - } - else - { - this.innerHTML = '
'; - } - return this.dropEnd; - }; - /** * If user puts the mouse over an event, then we'll set up resizing so * they can adjust the length. Should be a little better on resources @@ -236,7 +207,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz e.originalEvent = event; e.data = {duration: 0}; var event_data = timegrid._get_event_info(this); - var event_widget = timegrid.getWidgetById(event_data.id); + var event_widget = timegrid.getWidgetById('event_'+event_data.id); var sT = event_widget.options.value.start_m; if (typeof this.dropEnd != 'undefined' && this.dropEnd.length == 1) { @@ -269,7 +240,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz resize:function(event, ui) { // Add 5px to make sure it doesn't land right on the edge of a div - drag_helper.call(this,event,ui.element[0],ui.helper.outerHeight()+5); + timegrid._drag_helper(this,ui.element[0],ui.helper.outerHeight()+5); } }); }); @@ -278,70 +249,106 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz this.div.on('dragcreate','.calendar_calEvent:not(.rowNoEdit)', function(event,ui) { $j(this).draggable('option','cursorAt',false); }) - .on('dragstart', '.calendar_calEvent:not(.rowNoEdit)', function(event,ui) { + .on('dragstart', '.calendar_calEvent', function(event,ui) { $j('.calendar_calEvent',ui.helper).width($j(this).width()) .height($j(this).outerHeight()) + .css('top', '').css('left','') .appendTo(ui.helper); - }) - .on('dragstop','.calendar_calEvent:not(.rowNoEdit)', function(event,ui) { - var e = new jQuery.Event('change'); - e.originalEvent = event; - e.data = {start: 0}; - if (typeof this.dropEnd != 'undefined' && this.dropEnd.length >= 1) - { - var drop_date = this.dropEnd.attr('data-date')||false; - - var eT = parseInt(this.dropEnd.attr('data-hour') * 60) + parseInt(this.dropEnd.attr('data-minute')); - - var event_data = timegrid._get_event_info(this); - var event_widget = timegrid.getWidgetById(event_data.id); - - if(event_widget) - { - event_widget._parent.date_helper.set_year(drop_date.substring(0,4)); - event_widget._parent.date_helper.set_month(drop_date.substring(4,6)); - event_widget._parent.date_helper.set_date(drop_date.substring(6,8)); - event_widget._parent.date_helper.set_hours(this.dropEnd.attr('data-hour')); - event_widget._parent.date_helper.set_minutes(this.dropEnd.attr('data-minute')); - event_widget.options.value.start = event_widget._parent.date_helper.getValue(); - - // Leave the helper there until the update is done - var loading = ui.helper.clone().appendTo(ui.helper.parent()); - loading.addClass('loading'); - - event_widget.recur_prompt(function(button_id) { - //Get infologID if in case if it's an integrated infolog event - if (event_data.app === 'infolog') - { - // If it is an integrated infolog event we need to edit infolog entry - egw().json('stylite_infolog_calendar_integration::ajax_moveInfologEvent', - [event_data.id, event_widget.options.value.start||false], - function() {loading.remove();} - ).sendRequest(true); - } - else - { - //Edit calendar event - egw().json('calendar.calendar_uiforms.ajax_moveEvent', [ - button_id=='series' ? event_data.id : event_data.app_id,event_data.owner, - event_widget.options.value.start, - timegrid.options.owner||egw.user('account_id') - ], - function() { loading.remove();} - ).sendRequest(true); - } - }); - } - } - }) - // As event is dragged, update the time - .on('drag', '.calendar_calEvent:not(.rowNoEdit)', function(event,ui) { - this.dropEnd = drag_helper.call($j('.calendar_calEventHeader',ui.helper)[0],event,ui.helper[0],0); - $j('.calendar_timeDemo',ui.helper).css('bottom','auto'); + ui.helper.width($j(this).width()); }); return true; }, + /** + * Show the current time while dragging + * Used for resizing as well as drag & drop + */ + _drag_helper: function(element, helper,height) + { + element.dropEnd = this._get_time_from_position(helper.getBoundingClientRect().left, + helper.getBoundingClientRect().top+parseInt(height)); + + if (typeof element.dropEnd != 'undefined' && element.dropEnd.length) + { + element.dropEnd.addClass("drop-hover"); + var time = jQuery.datepicker.formatTime( + egw.preference("timeformat") == 12 ? "h:mmtt" : "HH:mm", + { + hour: element.dropEnd.attr('data-hour'), + minute: element.dropEnd.attr('data-minute'), + seconds: 0, + timezone: 0 + }, + {"ampm": (egw.preference("timeformat") == "12")} + ); + element.innerHTML = '
'+time+'
'; + } + else + { + element.innerHTML = '
'; + } + $j(element).width($j(helper).width()); + return element.dropEnd; + }, + + /** + * Handler for dropping an event on the timegrid + */ + _event_drop: function(timegrid, event,ui) { + var e = new jQuery.Event('change'); + e.originalEvent = event; + e.data = {start: 0}; + if (typeof this.dropEnd != 'undefined' && this.dropEnd.length >= 1) + { + var drop_date = this.dropEnd.attr('data-date')||false; + + var event_data = timegrid._get_event_info(ui.draggable); + var event_widget = timegrid.getWidgetById('event_'+event_data.id); + if(!event_widget) + { + // Widget was moved across weeks / owners + event_widget = timegrid.getParent().getWidgetById('event_'+event_data.id); + } + if(event_widget) + { + event_widget._parent.date_helper.set_year(drop_date.substring(0,4)); + event_widget._parent.date_helper.set_month(drop_date.substring(4,6)); + event_widget._parent.date_helper.set_date(drop_date.substring(6,8)); + event_widget._parent.date_helper.set_hours(this.dropEnd.attr('data-hour')); + event_widget._parent.date_helper.set_minutes(this.dropEnd.attr('data-minute')); + event_widget.options.value.start = new Date(event_widget._parent.date_helper.getValue()); + + // Leave the helper there until the update is done + var loading = ui.helper.clone().appendTo(ui.helper.parent()); + loading.addClass('loading'); + + event_widget.recur_prompt(function(button_id) { + if(button_id === 'cancel' || !button_id) return; + //Get infologID if in case if it's an integrated infolog event + if (event_data.app === 'infolog') + { + // If it is an integrated infolog event we need to edit infolog entry + egw().json('stylite_infolog_calendar_integration::ajax_moveInfologEvent', + [event_data.id, event_widget.options.value.start||false], + function() {loading.remove();} + ).sendRequest(true); + } + else + { + //Edit calendar event + egw().json('calendar.calendar_uiforms.ajax_moveEvent', [ + button_id==='series' ? event_data.id : event_data.app_id,event_data.owner, + event_widget.options.value.start, + timegrid.options.owner||egw.user('account_id') + ], + function() { loading.remove();} + ).sendRequest(true); + } + }); + } + } + }, + /** * Something changed, and the days need to be re-drawn. We wait a bit to * avoid re-drawing twice if start and end date both changed, then recreate @@ -381,7 +388,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz detachFromDOM: function() { // Remove the binding to the change handler - $j(this.div).off("change.et2_calendar_timegrid"); + $j(this.div).off(".et2_calendar_timegrid"); this._super.apply(this, arguments); }, @@ -636,42 +643,55 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz // Determine target node var event = _data.event || false; if(!event) return; - + if(_data.ui.draggable.hasClass('rowNoEdit')) return; + + /* + We have to handle the drop in the normal event stream instead of waiting + for the egwAction system so we can get the helper, and destination + */ + if(event.type === 'drop') + { + this.getWidget()._event_drop.call($j('.calendar_d-n-d_timeCounter',_data.ui.helper)[0],this.getWidget(),event, _data.ui); + } + var drag_listener = function(event, ui) { + aoi.getWidget()._drag_helper($j('.calendar_d-n-d_timeCounter',ui.helper)[0],ui.helper[0],0); + }; + var time = $j('.calendar_d-n-d_timeCounter',_data.ui.helper); switch(_event) { // Triggered once, when something is dragged into the timegrid's div case EGW_AI_DRAG_OVER: - _data.ui.draggable.off('.et2_timegrid') - // Listen to the drag and update the helper with the time - .on('drag.et2_timegrid',function(event,ui) { - var nodes = aoi.getWidget()._get_time_from_position(event.clientX,event.clientY); + // Listen to the drag and update the helper with the time + // This part lets us drag between different timegrids + _data.ui.draggable.on('drag.et2_timegrid'+widget_object.id, drag_listener); + _data.ui.draggable.on('dragend.et2_timegrid'+widget_object.id, function() { + _data.ui.draggable.off('drag.et2_timegrid' + widget_object.id); + }); + if(time.length) + { + // The out will trigger after the over, so we count + time.data('count',time.data('count')+1); + } + else + { + _data.ui.helper.prepend('
'); + } - // Highlight the destination time - $j('[data-date]',aoi.doGetDOMNode()).removeClass("ui-state-active"); - nodes.addClass('ui-state-active'); - - // Update the helper with the actual time - var time = jQuery.datepicker.formatTime( - egw.preference("timeformat") == 12 ? "h:mmtt" : "HH:mm", - { - hour: nodes.attr('data-hour'), - minute: nodes.attr('data-minute'), - seconds: 0, - timezone: 0 - }, - {"ampm": (egw.preference("timeformat") == "12")} - ); - $j('.calendar_d-n-d_timeCounter span',ui.helper).empty().html(time); - }) - _data.ui.helper.prepend('
'); break; // Triggered once, when something is dragged out of the timegrid case EGW_AI_DRAG_OUT: - // Reset + // Stop listening + _data.ui.draggable.off('drag.et2_timegrid'+widget_object.id); + // Remove any highlighted time squares $j('[data-date]',this.doGetDOMNode()).removeClass("ui-state-active"); - _data.ui.draggable.off('.et2_timegrid'); - $j('.calendar_d-n-d_timeCounter',_data.ui.helper[0]).remove(); + + // Out triggers after the over, count to not accidentally remove + time.data('count',time.data('count')-1); + if(time.length && time.data('count') <= 0) + { + time.remove(); + } break; } }; @@ -804,17 +824,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz { // Create drag action that allows linking drag_action = mgr.addAction('drag', 'egw_link_drag', egw.lang('link'), 'link', function(action, selected) { - // Drag helper - list titles. Arbitrarily limited to 10. - var helper = $j(document.createElement("div")); - for(var i = 0; i < selected.length && i < 10; i++) - { - var id = selected[i].id.split('::'); - var span = $j(document.createElement('span')).appendTo(helper); - egw.link_title(id[0],id[1], function(title) { - this.append(title); - this.append('
'); - }, span); - } + // Drag helper - list titles. // As we wanted to have a general defaul helper interface, we return null here and not using customize helper for links // TODO: Need to decide if we need to create a customized helper interface for links anyway //return helper; @@ -823,7 +833,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz } if(actionLinks.indexOf(drag_action.id) < 0) { - //actionLinks.push(drag_action.id); + actionLinks.push(drag_action.id); } drag_action.set_dragType('link'); }, @@ -1038,7 +1048,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz if (this.onevent_change) { var event_data = this._get_event_info(dom_node); - var event_widget = this.getWidgetById(event_data.id); + var event_widget = this.getWidgetById('event_'+event_data.id); et2_calendar_event.recur_prompt(event_data, jQuery.proxy(function(button_id, event_data) { // No need to continue if(button_id === 'cancel') return false;