diff --git a/calendar/js/app.js b/calendar/js/app.js index daa8ee699b..1990d647d5 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -995,7 +995,10 @@ app.classes.calendar = AppJS.extend( cal_open: function(_action, _senders) { - var js_integration_data = _action.parent.data.nextmatch.options.settings.js_integration_data || this.et2.getArrayMgr('content').data.nm.js_integration_data; + if(_action.parent.data && _action.parent.data.nextmatch) + { + var js_integration_data = _action.parent.data.nextmatch.options.settings.js_integration_data || this.et2.getArrayMgr('content').data.nm.js_integration_data; + } var id = _senders[0].id; var matches = id.match(/^(?:calendar::)?([0-9]+):([0-9]+)$/); var backup = _action.data; @@ -1005,7 +1008,7 @@ app.classes.calendar = AppJS.extend( return; } matches = id.match(/^([a-z_-]+)([0-9]+)/i); - if (matches) + if (matches && js_integration_data) { var app = matches[1]; _action.data.url = window.egw_webserverUrl+'/index.php?'; @@ -2346,7 +2349,7 @@ jQuery.extend(app.classes.calendar,{ var endDate = new Date(state.last); endDate = new Date(endDate.valueOf() + endDate.getTimezoneOffset() * 60 * 1000); return egw.lang('Planner view') + ': ' + date(egw.preference('dateformat'),startDate) + - ' - ' + date(egw.preference('dateformat'),endDate); + (startDate == endDate ? '' : ' - ' + date(egw.preference('dateformat'),endDate)); }, etemplates: ['calendar.planner'], group_by: function(state) { diff --git a/calendar/js/calendar_favorite_portlet.js b/calendar/js/calendar_favorite_portlet.js index 494d0d8aa3..0c5c952406 100644 --- a/calendar/js/calendar_favorite_portlet.js +++ b/calendar/js/calendar_favorite_portlet.js @@ -32,7 +32,11 @@ observer: function(_msg, _app, _id, _type, _msg_type, _targetapp) var event = egw.dataGetUIDdata('calendar::'+_id); if(event && event.data && event.data.date) { - var new_cache_id = app.classes.calendar._daywise_cache_id(event.data.date); + var new_cache_id = app.classes.calendar._daywise_cache_id( + event.data.date, + // Make sure to use the right owner, not current calendar state + this.portlet.settings.favorite.state.owner || '' + ); var daywise = egw.dataGetUIDdata(new_cache_id); daywise = daywise ? daywise.data : []; if(_type === 'delete') diff --git a/calendar/js/et2_widget_daycol.js b/calendar/js/et2_widget_daycol.js index 55aa2c8388..bc584d1ade 100644 --- a/calendar/js/et2_widget_daycol.js +++ b/calendar/js/et2_widget_daycol.js @@ -104,9 +104,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea destroy: function() { this._super.apply(this, arguments); - // In some cases, app.calendar code is unloaded before all the etemplates are destroyed - //egw.dataUnregisterUID(app.calendar.DAYWISE_CACHE_ID+'::'+this.options.date); - egw.dataUnregisterUID('calendar_daywise::'+this.options.date); + egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),false,this); }, /** @@ -759,7 +757,7 @@ jQuery.extend(et2_calendar_daycol, egw.window.et2_calendar_daycol.holiday_cache[year] = egw.json( 'calendar_timegrid_etemplate_widget::ajax_get_holidays', [year] - ).sendRequest(); + ).sendRequest(true); } cache = egw.window.et2_calendar_daycol.holiday_cache[year]; if(typeof cache.done == 'function') @@ -769,7 +767,11 @@ jQuery.extend(et2_calendar_daycol, egw.window.et2_calendar_daycol.holiday_cache[this.year] = response.response[0].data||undefined; egw.window.setTimeout(jQuery.proxy(function() { - this.widget.day_class_holiday(); + // Make sure widget hasn't been destroyed while we wait + if(typeof this.widget.free == 'undefined') + { + this.widget.day_class_holiday(); + } },this),1); },{widget:widget,year:year})); return {}; diff --git a/calendar/js/et2_widget_event.js b/calendar/js/et2_widget_event.js index 7c27f1a451..6785951fad 100644 --- a/calendar/js/et2_widget_event.js +++ b/calendar/js/et2_widget_event.js @@ -480,7 +480,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], // objects widget_object = objectManager.insertObject(false, new egwActionObject( 'calendar::'+this.id, objectManager, new et2_event_action_object_impl(this,this.getDOMNode()), - objectManager.manager.getActionById(this.id) || objectManager.manager + this._actionManager || objectManager.manager.getActionById(this.id) || objectManager.manager )); } else diff --git a/calendar/js/et2_widget_planner.js b/calendar/js/et2_widget_planner.js index d68a874e97..500c7e1618 100644 --- a/calendar/js/et2_widget_planner.js +++ b/calendar/js/et2_widget_planner.js @@ -110,12 +110,19 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize this.update_timer = null; this.setDOMNode(this.div[0]); + + this.registeredCallbacks = []; }, destroy: function() { this._super.apply(this, arguments); this.div.off(); + for(var i = 0; i < this.registeredCallbacks.length; i++) + { + egw.dataUnregisterUID(this.registeredCallbacks[i],false,this); + } + // date_helper has no parent, so we must explicitly remove it this.date_helper.destroy(); this.date_helper = null; @@ -140,9 +147,121 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize // and get ours this._link_actions(this.options.actions || this._parent.options.actions || []); + // Automatically bind drag and resize for every event using jQuery directly + // - no action system - + var planner = this; + + /** + * 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 + * than binding it for every calendar event. + */ + this.div.on('mouseover', '.calendar_calEvent:not(.ui-resizable):not(.rowNoEdit)', function() { + + // Load the event + planner._get_event_info(this); + var that = this; + + //Resizable event handler + $j(this).resizable + ({ + distance: 10, + grid: [5, 10000], + autoHide: false, + handles: 'e', + containment:'parent', + + /** + * Triggered when the resizable is created. + * + * @param {event} event + * @param {Object} ui + */ + create:function(event, ui) + { + var resizeHelper = event.target.getAttribute('data-resize'); + if (resizeHelper == 'WD' || resizeHelper == 'WDS') + { + jQuery(this).resizable('destroy'); + } + }, + + /** + * Triggered at the end of resizing the calEvent. + * + * @param {event} event + * @param {Object} ui + */ + stop:function(event, ui) + { + var e = new jQuery.Event('change'); + e.originalEvent = event; + e.data = {duration: 0}; + var event_data = planner._get_event_info(this); + var event_widget = planner.getWidgetById('event_'+event_data.id); + var sT = event_widget.options.value.start_m; + if (typeof this.dropEnd != 'undefined') + { + var eT = parseInt(this.dropEnd.getUTCHours() * 60) + parseInt(this.dropEnd.getUTCMinutes()); + e.data.duration = ((eT - sT)/60) * 3600; + + if(event_widget) + { + event_widget.options.value.end_m = eT; + event_widget.options.value.duration = e.data.duration; + } + + // Leave the helper there until the update is done + var loading = ui.helper.clone().appendTo(ui.helper.parent()); + + // and add a loading icon so user knows something is happening + $j('.calendar_timeDemo',loading).after('
'); + + $j(this).trigger(e); + + // That cleared the resize handles, so remove for re-creation... + $j(this).resizable('destroy'); + + // Remove loading, done or not + loading.remove(); + } + // Clear the helper, re-draw + if(event_widget) + { + event_widget._parent.position_event(event_widget); + } + }, + + /** + * Triggered during the resize, on the drag of the resize handler + * + * @param {event} event + * @param {Object} ui + */ + resize:function(event, ui) + { + planner._drag_helper(this,{ + top:ui.position.top, + left: ui.position.left + ui.helper.width() + },ui.helper.outerHeight()); + } + }); + }); + + // Customize and override some draggable settings + this.div.on('dragcreate','.calendar_calEvent:not(.rowNoEdit)', function(event,ui) { + $j(this).draggable('option','cursorAt',false); + }) + .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); + ui.helper.width($j(this).width()); + }); return true; }, - + /** * These handle the differences between the different group types. * They provide the different titles, labels and grouping @@ -379,8 +498,6 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize if(this.update_timer === null) { this.update_timer = window.setTimeout(jQuery.proxy(function() { - this.widget.update_timer = null; - this.widget.value = this.widget._fetch_data(); this.widget._drawGrid(); @@ -395,6 +512,7 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize { this.widget.change(); } + this.widget.update_timer = null; },{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT); } }, @@ -677,10 +795,14 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize { // prev. week var left = new Date(t); + left.setUTCHours(0); + left.setUTCMinutes(0); left.setUTCDate(left.getUTCDate() - 7); // next week var right = new Date(t); + right.setUTCHours(0); + right.setUTCMinutes(0); right.setUTCDate(right.getUTCDate() + 7); title = this._scroll_button('left',left.toJSON()) + title + this._scroll_button('right',right.toJSON()); @@ -871,31 +993,109 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize */ _link_actions: function(actions) { - // Get the parent? Might be a grid row, might not. Either way, it is - // just a container with no valid actions - var objectManager = egw_getAppObjectManager(true); - var parent = this; - var om = false; - while(parent && om !== objectManager) + if(!this._actionObject) { - if(parent.id && objectManager.getObjectById(parent.id)) + // Get the parent? Might be a grid row, might not. Either way, it is + // just a container with no valid actions + var objectManager = egw_getObjectManager(this.getInstanceManager().app,true,1); + objectManager = objectManager.getObjectById(this.getInstanceManager().uniqueId,2) || objectManager; + var parent = objectManager.getObjectById(this.id,3) || objectManager.getObjectById(this._parent.id,3) || objectManager; + if(!parent) { - om = objectManager.getObjectById(parent.id); - break; + debugger; + egw.debug('error','No parent objectManager found') + return; + } + + for(var i = 0; i < parent.children.length; i++) + { + var parent_finder = jQuery('#'+this.div.id, parent.children[i].iface.doGetDOMNode()); + if(parent_finder.length > 0) + { + parent = parent.children[i]; + break; + } } - parent = parent.getParent(); - } - if(!om) - { - om = objectManager.getObjectById(this.getInstanceManager().uniqueId); } - if(!om) return; + // This binds into the egw action system. Most user interactions (drag to move, resize) + // are handled internally using jQuery directly. + var widget_object = this._actionObject || parent.getObjectById(this.id); - var widget_object = om.getObjectById(this.id); - if(widget_object == null) + var aoi = new et2_action_object_impl(this,this.getDOMNode()); + + aoi.doTriggerEvent = function(_event, _data) { + + // 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],{ + top:ui.position.top, + left: ui.position.left - $j(this).parent().offset().left + },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: + // 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('