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 = '