diff --git a/calendar/js/app.js b/calendar/js/app.js index 8d7a1634dd..90577ffb3b 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -1947,27 +1947,37 @@ app.classes.calendar = AppJS.extend( * @param {Object} state * @param {etemplate2} [instance] If the full calendar app isn't loaded * (home app), pass a different instance to use it to get the data + * @param {number} [start] Result offset. Internal use only */ - _fetch_data: function(state, instance) + _fetch_data: function(state, instance, start) { if(!this.sidebox_et2 && !instance) return; + if(typeof start === 'undefined') + { + start = 0; + } + + var query = jQuery.extend({}, { + get_rows: 'calendar.calendar_uilist.get_rows', + row_id:'row_id', + startdate:state.first || state.date, + enddate:state.last, + // Participant must be an array or it won't work + col_filter: {participant: (typeof state.owner == 'string' || typeof state.owner == 'number' ? [state.owner] : state.owner)}, + filter:'custom', // Must be custom to get start & end dates + status_filter: state.filter, + cat_id: state.cat_id, + search: state.keywords + }); + // Show ajax loader + framework.applications.calendar.sidemenuEntry.showAjaxLoader() + this.egw.dataFetch( instance ? instance.etemplate_exec_id : this.sidebox_et2.getInstanceManager().etemplate_exec_id, - {start: 0, num_rows:0}, - jQuery.extend({}, { - get_rows: 'calendar.calendar_uilist.get_rows', - row_id:'row_id', - startdate:state.first || state.date, - enddate:state.last, - // Participant must be an array or it won't work - col_filter: {participant: (typeof state.owner == 'string' || typeof state.owner == 'number' ? [state.owner] : state.owner)}, - filter:'custom', // Must be custom to get start & end dates - status_filter: state.filter, - cat_id: state.cat_id, - search: state.keywords - }), + {start: start, num_rows:200}, + query, this.id, function(data) { console.log(data); @@ -2017,6 +2027,18 @@ app.classes.calendar = AppJS.extend( { this.egw.dataStoreUID(app.classes.calendar._daywise_cache_id(day, state.owner), updated_days[day]); } + + // More rows? + if(data.order.length + start < data.total) + { + // Wait a bit, let UI do something. + window.setTimeout( function() { + app.calendar._fetch_data(state, instance, start + data.order.length); + }, 100); + } + + // Hide AJAX loader + framework.applications.calendar.sidemenuEntry.hideAjaxLoader(); }, this,null ); }, diff --git a/calendar/js/et2_widget_daycol.js b/calendar/js/et2_widget_daycol.js index 580c3c4377..6581015cf6 100644 --- a/calendar/js/et2_widget_daycol.js +++ b/calendar/js/et2_widget_daycol.js @@ -30,7 +30,8 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea date: { name: "Date", type: "any", - description: "What date is this daycol for. YYYYMMDD or Date" + description: "What date is this daycol for. YYYYMMDD or Date", + default: et2_no_init }, owner: { name: "Owner", @@ -103,6 +104,14 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea destroy: function() { this._super.apply(this, arguments); + this.div.off(); + this.title.off(); + this.div = null; + this.title = null; + + // date_helper has no parent, so we must explicitly remove it + this.date_helper.destroy(); + this.date_helper = null; egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),false,this); }, @@ -247,27 +256,34 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea * @param {number|number[]} _owner Account ID */ set_owner: function(_owner) { - if(_owner !== this.options.owner) + // Simple comparison, both numbers + if(_owner === this.options.owner) return; + + // More complicated comparison, one or the other is an array + if((typeof _owner == 'object' || typeof this.options.owner == 'object') && + _owner.toString() == this.options.owner.toString()) { - egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id+(this.options.date,this.options.owner),false,this); - - this.options.owner = _owner; - this.div.attr('data-sortable-id', this.options.owner); - - // Register for updates on events for this day - egw.dataRegisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner), function(event_ids) { - var events = []; - for(var i = 0; i < event_ids.length; i++) - { - 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); + return; } + + egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id+(this.options.date,this.options.owner),false,this); + + this.options.owner = _owner; + this.div.attr('data-sortable-id', this.options.owner); + + // Register for updates on events for this day + egw.dataRegisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner), function(event_ids) { + var events = []; + for(var i = 0; i < event_ids.length; i++) + { + 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); }, /** @@ -335,7 +351,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea var events = _events || this.getArrayMgr('content').getEntry(this.options.date) || []; // Remove extra events - while(this._children.length > events.length) + while(this._children.length > 0) { var node = this._children[this._children.length-1]; this.removeChild(node); @@ -349,7 +365,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea return a.whole_day ? -1 : (start ? start : end); }); - for(var c = this._children.length; c < events.length; c++) + for(var c = 0; c < events.length; c++) { // Create event var event = et2_createWidget('calendar-event',{ diff --git a/calendar/js/et2_widget_event.js b/calendar/js/et2_widget_event.js index 4505c1fdce..0cac28c955 100644 --- a/calendar/js/et2_widget_event.js +++ b/calendar/js/et2_widget_event.js @@ -84,7 +84,23 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], destroy: function() { this._super.apply(this, arguments); - + + if(this._actionObject) + { + this._actionObject.remove(); + this._actionObject = null; + } + + this.div.off(); + this.title.remove(); + this.title = null; + this.body.remove(); + this.body = null; + this.icons = null; + this.div.remove(); + this.div = null; + + // Unregister, or we'll continue to be notified... if(this.options.value) { @@ -280,7 +296,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], ''+this.egw().lang('End') + ':' + end var cat = et2_createWidget('select-cat',{'readonly':true},this); cat.set_value(this.options.value.category); - var cat_label = cat.node.innerText; + var cat_label = cat.span.text(); cat.destroy(); return '
'+ @@ -477,33 +493,37 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], */ _link_actions: function(actions) { - // Get the top level element - timegrid or so - var objectManager = this.getParent().getParent()._actionObject || - egw_getAppObjectManager(true).getObjectById(this._parent._parent._parent.id) || egw_getAppObjectManager(true); - var widget_object = objectManager.getObjectById('calendar::'+this.id); - if (widget_object == null) { + if(!this._actionObject) + { + // Get the top level element - timegrid or so + var objectManager = this.getParent().getParent()._actionObject || + egw_getAppObjectManager(true).getObjectById(this._parent._parent._parent.id) || egw_getAppObjectManager(true); + this._actionObject = objectManager.getObjectById('calendar::'+this.id); + } + + if (this._actionObject == null) { // Add a new container to the object manager which will hold the widget // objects - widget_object = objectManager.insertObject(false, new egwActionObject( + this._actionObject = objectManager.insertObject(false, new egwActionObject( 'calendar::'+this.id, objectManager, new et2_event_action_object_impl(this,this.getDOMNode()), this._actionManager || objectManager.manager.getActionById(this.id) || objectManager.manager )); } else { - widget_object.setAOI(new et2_event_action_object_impl(this, this.getDOMNode())); + this._actionObject.setAOI(new et2_event_action_object_impl(this, this.getDOMNode())); } // Delete all old objects - widget_object.clear(); - widget_object.unregisterActions(); + this._actionObject.clear(); + this._actionObject.unregisterActions(); // Go over the widget & add links - this is where we decide which actions are // 'allowed' for this widget at this time var action_links = this._get_action_links(actions); action_links.push('egw_link_drag'); action_links.push('egw_link_drop'); - widget_object.updateActionLinks(action_links); + this._actionObject.updateActionLinks(action_links); }, /** diff --git a/calendar/js/et2_widget_planner.js b/calendar/js/et2_widget_planner.js index 8e762fe608..6ed4f3aa44 100644 --- a/calendar/js/et2_widget_planner.js +++ b/calendar/js/et2_widget_planner.js @@ -108,6 +108,7 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize // Update timer, to avoid redrawing twice when changing start & end date this.update_timer = null; + this.doInvalidate = true; this.setDOMNode(this.div[0]); @@ -549,27 +550,40 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize */ invalidate: function(trigger) { + // Busy + if(!this.doInvalidate && this.update_timer) return; + // Wait a bit to see if anything else changes, then re-draw the days - if(this.update_timer === null) + if(this.update_timer !== null) { - this.update_timer = window.setTimeout(jQuery.proxy(function() { - this.widget.value = this.widget._fetch_data(); - - this.widget._drawGrid(); - - // Update actions - if(this._actionManager) - { - this._link_actions(this._actionManager.children); - } - - if(this.trigger) - { - this.widget.change(); - } - this.widget.update_timer = null; - },{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT); + window.clearTimeout(this.update_timer); } + this.update_timer = window.setTimeout(jQuery.proxy(function() { + this.doInvalidate = false; + + this.widget.value = this.widget._fetch_data(); + + // Show AJAX loader + framework.applications.calendar.sidemenuEntry.showAjaxLoader(); + + this.widget._drawGrid(); + + // Update actions + if(this._actionManager) + { + this._link_actions(this._actionManager.children); + } + + // Hide AJAX loader + framework.applications.calendar.sidemenuEntry.hideAjaxLoader(); + + if(this.trigger) + { + this.widget.change(); + } + this.widget.update_timer = null; + this.doInvalidate = true; + },{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT); }, detachFromDOM: function() { @@ -661,6 +675,7 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize grouper.draw_row.call(this,labels[key].id, labels[key].label, events[key] || []); } + this.value = []; }, /** @@ -1352,6 +1367,8 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize { var value = []; var fetch = false; + this.doInvalidate = false; + for(var i = 0; i < this.registeredCallbacks.length; i++) { egw.dataUnregisterUID(this.registeredCallbacks[i],false,this); @@ -1412,6 +1429,8 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize filter: this.options.filter }, this.getInstanceManager()); } + + this.doInvalidate = true; return value; }, diff --git a/calendar/js/et2_widget_planner_row.js b/calendar/js/et2_widget_planner_row.js index 25ee5101a0..8ce2f9415b 100644 --- a/calendar/js/et2_widget_planner_row.js +++ b/calendar/js/et2_widget_planner_row.js @@ -181,6 +181,7 @@ var et2_calendar_planner_row = et2_valueWidget.extend([et2_IDetachedDOM], this._children[this._children.length-1].free(); this.removeChild(this._children[this._children.length-1]); } + this._cached_rows = []; for(var c = 0; c < events.length; c++) { @@ -249,6 +250,12 @@ var et2_calendar_planner_row = et2_valueWidget.extend([et2_IDetachedDOM], */ _spread_events: function() { + // Keep it so we don't have to re-do it when the next event asks + if(this._cached_rows.length == this._children.length) + { + return this._cached_rows; + } + // sorting the events in non-overlapping rows var rows = []; var row_end = [0]; @@ -304,6 +311,7 @@ var et2_calendar_planner_row = et2_valueWidget.extend([et2_IDetachedDOM], rows[row].push(this._children[n]); row_end[row] = new Date(event['end']).valueOf(); } + this._cached_rows = rows; return rows; }, diff --git a/calendar/js/et2_widget_timegrid.js b/calendar/js/et2_widget_timegrid.js index 5cfbead835..ff878f411b 100644 --- a/calendar/js/et2_widget_timegrid.js +++ b/calendar/js/et2_widget_timegrid.js @@ -139,8 +139,26 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz this.setDOMNode(this.div[0]); }, destroy: function() { + + // Stop the invalidate timer + if(this.update_timer) + { + window.clearTimeout(this.update_timer); + } + this._super.apply(this, arguments); + + // Delete all old objects + this._actionObject.clear(); + this._actionObject.unregisterActions(); + this._actionObject.remove(); + this._actionObject = null; + this.div.off(); + this.div = null; + this.gridHeader = null; + this.days = null; + this._labelContainer = null; // date_helper has no parent, so we must explicitly remove it this.date_helper.destroy(); @@ -548,6 +566,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz { day = this.day_widgets[i]; // Set the date, and pass any data we have + /* Not needed due to registered callbacks (?) if(typeof this.value[this.day_list[i]] === 'undefined') { var ids = (egw.dataGetUIDdata(app.classes.calendar._daywise_cache_id(this.day_list[i],this.options.owner))||{data:[]}); @@ -563,6 +582,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz } } } + */ day.set_date(this.day_list[i], this.value[this.day_list[i]] || false); day.set_owner(this.options.owner); @@ -1067,7 +1087,6 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz this.options.label = label; this.gridHeader.text(label); -debugger; // If it's a short label (eg week number), don't give it an extra line // but is empty, but give extra space for a single owner name this.div.removeClass('calendar_TimeGridNoLabel');