diff --git a/calendar/inc/class.calendar_ui.inc.php b/calendar/inc/class.calendar_ui.inc.php index 24150c15bd..cf2201ca82 100644 --- a/calendar/inc/class.calendar_ui.inc.php +++ b/calendar/inc/class.calendar_ui.inc.php @@ -796,6 +796,9 @@ class calendar_ui { $event['app_id'] .= ':'.egw_time::to($event['recur_date'] ? $event['recur_date'] : $event['start'],'ts'); } + // set id for grid + $event['row_id'] = $event['id'].($event['recur_type'] ? ':'.egw_time::to($event['recur_date'] ? $event['recur_date'] : $event['start'],'ts') : ''); + $event['parts'] = implode(",\n",$this->bo->participants($event,false)); $event['date'] = $this->bo->date2string($event['start']); diff --git a/calendar/inc/class.calendar_uilist.inc.php b/calendar/inc/class.calendar_uilist.inc.php index 4e5853ac83..8705ab206a 100644 --- a/calendar/inc/class.calendar_uilist.inc.php +++ b/calendar/inc/class.calendar_uilist.inc.php @@ -462,9 +462,6 @@ class calendar_uilist extends calendar_ui $event['edit_link'] = $this->popup($view_link).'; return false;'; } - // set id for grid - $event['row_id'] = $event['id'].($event['recur_type'] ? ':'.egw_time::to($event['recur_date'] ? $event['recur_date'] : $event['start'],'ts') : ''); - // Format start and end with timezone foreach(array('start','end') as $time) { diff --git a/calendar/inc/class.calendar_uiviews.inc.php b/calendar/inc/class.calendar_uiviews.inc.php index b33f6ec93c..ce5f3bce9d 100644 --- a/calendar/inc/class.calendar_uiviews.inc.php +++ b/calendar/inc/class.calendar_uiviews.inc.php @@ -661,20 +661,36 @@ class calendar_uiviews extends calendar_ui $content = array('view' => array()); - // Always do 7 days for a week so scrolling works properly - $this->last = ($days == 4 ? $this->last : $search_params['end'] = strtotime("+$days days",$this->first) - 1); - if (count($users) == 1 || count($users) >= $this->cal_prefs['week_consolidate']) // for more then X users, show all in one row + if(!$home) { - $content['view'][] = (array)$this->tagWholeDayOnTop($this->bo->search($search_params)) + - array('owner' => $users); + // Fill with the minimum needed 'weeks' + $min = max( + 6, // Some months need 6 weeks for full display + $this->cal_prefs['multiple_weeks'], // WeekN view + $this->cal_prefs['week_consolidate'] // We collapse after this many users + ); + for($i = 0; $i < $min; $i++) + { + $content['view'][] = array(); + } } else { - foreach($this->_get_planner_users(false) as $uid => $label) + // Always do 7 days for a week so scrolling works properly + $this->last = ($days == 4 ? $this->last : $search_params['end'] = strtotime("+$days days",$this->first) - 1); + if (count($users) == 1 || count($users) >= $this->cal_prefs['week_consolidate']) // for more then X users, show all in one row { - $search_params['users'] = $uid; - $content['view'][] = $this->tagWholeDayOnTop($this->bo->search($search_params)) - + array('owner' => $uid); + $content['view'][] = (array)$this->tagWholeDayOnTop($this->bo->search($search_params)) + + array('owner' => $users); + } + else + { + foreach($this->_get_planner_users(false) as $uid => $label) + { + $search_params['users'] = $uid; + $content['view'][] = $this->tagWholeDayOnTop($this->bo->search($search_params)) + + array('owner' => $uid); + } } } $tmpl = $home ? $home :new etemplate_new('calendar.view'); diff --git a/calendar/js/app.js b/calendar/js/app.js index 088b5f325e..1bbe2b56c2 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -1594,7 +1594,7 @@ app.classes.calendar = AppJS.extend( * * @param {Object} _set New settings */ - update_state: function(_set) + update_state: function update_state(_set) { // Make sure we're running in top window if(window !== window.top) @@ -1632,7 +1632,7 @@ app.classes.calendar = AppJS.extend( * * @return {object} description */ - getState: function() + getState: function getState() { var state = jQuery.extend({},this.state); @@ -1683,7 +1683,7 @@ app.classes.calendar = AppJS.extend( * * @param {object} state containing "name" attribute to be used as "favorite" GET parameter to a nextmatch */ - setState: function(state) + setState: function setState(state) { // State should be an object, not a string, but we'll parse if(typeof state == "string") @@ -1730,7 +1730,7 @@ app.classes.calendar = AppJS.extend( } // Check for valid cache - var cachable_changes = ['date','view','days','planner_days','sortby']; + var cachable_changes = ['date','weekend','view','days','planner_days','sortby']; var keys = jQuery.unique(Object.keys(this.state).concat(Object.keys(state.state))); for(var i = 0; i < keys.length; i++) { @@ -1838,19 +1838,18 @@ app.classes.calendar = AppJS.extend( var grid = view.etemplates[0].widgetContainer.getWidgetById('view'); /* - If the count is different, we need to have the correct number (just remove all & re-create) + If the count is different, we need to have the correct number If the count is > 1, it's either because there are multiple date spans (weekN, month) and we need the correct span per row, or there are multiple owners and we need the correct owner per row. */ - if(grid && (grid_count !== grid._children.length || grid_count > 1)) + if(grid) { - // Need to redo the number of grids var value = []; state.state.first = view.start_date(state.state).toJSON(); // We'll modify this one, so it needs to be a new object var date = new Date(state.state.first); - // Determine the different end date + // Determine the different end date & varying values switch(state.state.view) { case 'month': @@ -1861,59 +1860,147 @@ app.classes.calendar = AppJS.extend( for(var week = 0; week < grid_count; week++) { var val = { - id: ""+date.getUTCFullYear() + sprintf("%02d",date.getUTCMonth()) + sprintf("%02d",date.getUTCDate()), + id: app.classes.calendar._daywise_cache_id(date,state.state.owner), start_date: date.toJSON(), end_date: new Date(date.toJSON()), owner: state.state.owner }; val.end_date.setUTCHours(24*7-1); + val.end_date.setUTCMinutes(59); + val.end_date.setUTCSeconds(59); val.end_date = val.end_date.toJSON(); value.push(val); date.setUTCHours(24*7); } state.state.last=val.end_date; break; + case 'day': + var end = state.state.last = view.end_date(state.state).toJSON(); + value.push({ + id: app.classes.calendar._daywise_cache_id(date,state.state.owner), + start_date: state.state.first, + end_date: state.state.last, + owner: view.owner(state.state) + }); + break; default: var end = state.state.last = view.end_date(state.state).toJSON(); for(var owner = 0; owner < grid_count && owner < state.state.owner.length; owner++) { + var _owner = grid_count > 1 ? state.state.owner[owner] || 0 : state.state.owner value.push({ - id: ""+date.getUTCFullYear() + sprintf("%02d",date.getUTCMonth()) + sprintf("%02d",date.getUTCDate()), + id: app.classes.calendar._daywise_cache_id(date,_owner), start_date: date, end_date: end, - owner: grid_count > 1 ? state.state.owner[owner] || 0 : state.state.owner + owner: _owner }); } break; } // If we have cached data for the timespan, pass it along this._need_data(value,state.state); - if(grid) + + var row_index = 0; + + // Find any matching, existing rows - they can be kept + grid.iterateOver(function(widget) { + for(var i = 0; i < value.length; i++) + { + if(widget.id == value[i].id) + { + // Keep it, but move it + if(i > row_index) + { + for(var j = i-row_index; j > 0; j--) + { + // Move from the end to the start + grid._children.unshift(grid._children.pop()); + + // Swap DOM nodes + var a = grid._children[0].getDOMNode().parentNode.parentNode; + var b = grid._children[1].getDOMNode().parentNode.parentNode; + a.parentNode.insertBefore(a,b); + } + } + else if (row_index > i) + { + for(var j = row_index - i; j > 0; j--) + { + // Move from the start to the end + grid._children.push(grid._children.shift()); + + // Swap DOM nodes + var a = grid._children[grid._children.length - 1].getDOMNode().parentNode.parentNode; + a.parentNode.insertBefore(a,null); + } + } + break; + } + } + row_index++; + },this,et2_calendar_view); + row_index = 0; + + // Set rows that need it + grid.iterateOver(function(widget) { + if(row_index < value.length) + { + widget.set_disabled(false); + } + else + { + widget.set_disabled(true); + return; + } + if(widget.set_show_weekend) + { + widget.set_show_weekend(view.show_weekend(state.state)); + } + if(widget.id == value[row_index].id && + widget.get_end_date().toJSON() == value[row_index].end_date + ) + { + // Do not need to re-set this row, but we do need to re-do + // the times, as they may have changed + widget.invalidate(); + row_index++; + return; + } + if(widget.set_value) + { + widget.set_value(value[row_index++]); + } + },this, et2_calendar_view); + grid.iterateOver(function(widget) { + if(widget.set_granularity) + { + widget.set_granularity(view.granularity(state.state)); + } + if(widget.resize) + { + widget.resize(); + } + },this,et2_calendar_view); + + // Single day with multiple owners still needs owners split to satisfy + // caching keys, otherwise they'll cache consolidated + if(state.state.view == 'day' && state.state.owner.length < parseInt(this.egw.preference('day_consolidate','calendar'))) { - grid.set_value( - {content: value} - ); - - // Weekend needs to be done seperately - grid.iterateOver(function(widget) { - if(widget.set_show_weekend) - { - widget.set_show_weekend(view.show_weekend(state.state)); - } - },this, et2_calendar_view); - - // Granularity needs to be done seperately - grid.iterateOver(function(widget) { - if(widget.set_granularity) - { - widget.set_granularity(view.granularity(state.state)); - } - },this, et2_calendar_view); + value = []; + for(var i = 0; i < state.state.owner.length; i++) + { + value.push({ + start_date: state.state.first, + end_date: state.state.last, + owner: state.state.owner[i] + }); + } + this._need_data(value,state.state); } } else { - // Simple, easy case - just one widget for the selected time span. + // Simple, easy case - just one widget for the selected time span. (planner) // Update existing view's special attribute filters, defined in the view list for(var updater in view) { @@ -1929,26 +2016,13 @@ app.classes.calendar = AppJS.extend( view.etemplates[i].widgetContainer.iterateOver(function(widget) { if(typeof widget['set_'+updater] === 'function') { - widget['set_'+updater](value); + widget['set_'+updater](value); } }, this, et2_calendar_view); } } } var value = [{start_date: state.state.first, end_date: state.state.last}]; - // Single day with multiple owners still needs owners split - if(state.state.view == 'day' && state.state.owner.length < parseInt(this.egw.preference('day_consolidate','calendar'))) - { - value = []; - for(var i = 0; i < state.state.owner.length; i++) - { - value.push({ - start_date: state.state.first, - end_date: state.state.last, - owner: state.state.owner[i] - }); - } - } this._need_data(value,state.state); } // Include first & last dates in state, mostly for server side processing @@ -2488,7 +2562,7 @@ app.classes.calendar = AppJS.extend( {start: start, num_rows:200}, query, this.id, - function(data) { + function calendar_handleResponse(data) { console.log(data); // Look for any updated select options if(data.rows && data.rows.sel_options && this.sidebox_et2) @@ -3282,10 +3356,6 @@ jQuery.extend(app.classes.calendar,{ // Always 7 days, we just turn weekends on or off d.setUTCHours(24*7-1); return d; - }, - granularity: function(state) { - // Does not care how many users you select - return parseInt(egw.preference('interval','calendar')) || 30; } }), month: app.classes.calendar.prototype.View.extend({ diff --git a/calendar/js/et2_widget_daycol.js b/calendar/js/et2_widget_daycol.js index 791848e52f..3c151e7720 100644 --- a/calendar/js/et2_widget_daycol.js +++ b/calendar/js/et2_widget_daycol.js @@ -93,6 +93,8 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], // Percentage; not yet available titleHeight: 2.0 } + + this.registeredUID = null; }, doLoadingFinished: function() { @@ -122,7 +124,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], this.date_helper.destroy(); this.date_helper = null; - egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),false,this); + egw.dataUnregisterUID(this.registeredUID,false,this); }, /** @@ -248,9 +250,11 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], return; } - if(this.options.date) + var cache_id = app.classes.calendar._daywise_cache_id(new_date,this.options.owner); + if(this.options.date && this.registeredUID && + cache_id !== this.registeredUID) { - egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),false,this); + egw.dataUnregisterUID(this.registeredUID,false,this); // Remove existing events while(this._children.length > 0) @@ -271,11 +275,10 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], // Register for updates on events for this day - var cache_id = app.classes.calendar._daywise_cache_id(new_date,this.options.owner); - egw.dataRegisterUID(cache_id, this._data_callback,this,this.getInstanceManager().execId,this.id); - - if(events) { - this._update_events(events); + if(this.registeredUID !== cache_id) + { + this.registeredUID = cache_id; + egw.dataRegisterUID(this.registeredUID, this._data_callback,this,this.getInstanceManager().execId,this.id); } }, @@ -295,17 +298,22 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], return; } - egw.dataUnregisterUID(app.classes.calendar._daywise_cache_id(this.options.date,this.options.owner),false,this); + var cache_id = app.classes.calendar._daywise_cache_id(this.options.date,_owner) + if(this.options.date && this.registeredUID && + cache_id !== this.registeredUID) + { + egw.dataUnregisterUID(this.registeredUID,false,this); + } this.options.owner = _owner; this.title .attr("data-owner", 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), - this._data_callback,this,this.getInstanceManager().execId,this.id - ); + if(this.registeredUID !== cache_id) + { + this.registeredUID = cache_id; + egw.dataRegisterUID(this.registeredUID, this._data_callback,this,this.getInstanceManager().execId,this.id); + } }, /** @@ -445,22 +453,20 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], { // Create event var event = et2_createWidget('calendar-event',{ - id:events[c].id, + id:'event_'+events[c].id, value: events[c] },this); - if(this.isInTree()) - { - event.doLoadingFinished(); - } - - // Copy actions set in parent - event._link_actions(this._parent._parent.options.actions||{}); } // Seperate loop so column sorting finds all children in the right place for(var c = 0; c < events.length && c < this._children.length; c++) { - this.getWidgetById(events[c].id).set_value(events[c]); + var event = this.getWidgetById('event_'+events[c].id); + if(!event) continue; + if(this.isInTree()) + { + event.doLoadingFinished(); + } } // Apply styles to hidden events diff --git a/calendar/js/et2_widget_event.js b/calendar/js/et2_widget_event.js index eab6952afe..be76f7eea9 100644 --- a/calendar/js/et2_widget_event.js +++ b/calendar/js/et2_widget_event.js @@ -97,6 +97,16 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], this.options.date = ''; this.set_date(date); } + if(this.options.value && this.options.value.row_id) + { + egw.dataRegisterUID( + 'calendar::'+this.options.value.row_id, + this._UID_callback , + this, + this.getInstanceManager().execId, + this.id + ); + } }, destroy: function() { @@ -131,47 +141,60 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], // Un-register for updates if(this.options.value) { - var old_app_id = this.options.value.app_id; - egw.dataUnregisterUID('calendar::'+old_app_id,false,this); + var old_id = this.options.value.row_id; + if(!_value || !_value.row_id || old_id !== _value.row_id) + { + egw.dataUnregisterUID('calendar::'+old_id,false,this); + } } this.options.value = _value; // Register for updates - var app_id = this.options.value.app_id; - egw.dataRegisterUID('calendar::'+app_id, function _UID_callback(event) { - // Make sure id is a string - this._values_check(event); - - // Check for changing days in the grid view - if(!this._sameday_check(event)) - { - // This should now cease to exist, as new events have been created - this.free(); - return; - } - - // Copy to avoid changes, which may cause nm problems - this.options.value = jQuery.extend({},event); - - if(this._parent.options.date) - { - this.options.value.date = this._parent.options.date; - } - - // Let parent position - this._parent.position_event(this); - - // 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); - - if(_value && !egw.dataHasUID('calendar::'+app_id)) + var id = this.options.value.row_id; + if(!old_id || old_id !== id) { - egw.dataStoreUID('calendar::'+app_id, _value); + egw.dataRegisterUID('calendar::'+id, this._UID_callback ,this,this.getInstanceManager().execId,this.id); + } + if(_value && !egw.dataHasUID('calendar::'+id)) + { + egw.dataStoreUID('calendar::'+id, _value); + } + }, + + _UID_callback: function _UID_callback(event) { + // Make sure id is a string + this._values_check(event); + + // Check for changing days in the grid view + if(!this._sameday_check(event)) + { + // This should now cease to exist, as new events have been created + this.free(); + return; + } + + // Copy to avoid changes, which may cause nm problems + this.options.value = jQuery.extend({},event); + + if(this._parent.options.date) + { + this.options.value.date = this._parent.options.date; + } + + // Let parent position + this._parent.position_event(this); + + // Parent may remove this if the date isn't the same + if(this._parent) + { + // This gives some slight speed enhancements over doing it immediately, + // but it looks weird + /* + window.setTimeout(jQuery.proxy(function() { + if(this.options) this._update(this.options.value); + },this),100); + */ + this._update(this.options.value); } }, @@ -180,15 +203,19 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], // Copy new information this.options.value = event; - var app_id = event.app_id ? event.app_id : event.id + (event.recur_type ? ':'+event.recur_date : ''); + var id = event.row_id ? event.row_id : event.id + (event.recur_type ? ':'+event.recur_date : ''); 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('event_' + event.app_id); + this.set_id('event_' + id); if(this._actionObject) { - this._actionObject.id = 'calendar::' + event.app_id; + this._actionObject.id = 'calendar::' + id; } + + // Copy actions set in parent + this._link_actions(this._parent._parent._parent.options.actions||{}); + // Make sure category stuff is there // Fake it to use the cache / call - if already there, these will return // immediately. @@ -217,7 +244,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], // Put everything we need for basic interaction here, so it's available immediately .attr('data-id', event.id) .attr('data-app', event.app || 'calendar') - .attr('data-app_id', app_id) + .attr('data-app_id', event.app_id) .attr('data-start', formatted_start) .attr('data-owner', event.owner) .attr('data-recur_type', event.recur_type) diff --git a/calendar/js/et2_widget_planner.js b/calendar/js/et2_widget_planner.js index b0687efb36..8dd0f45af2 100644 --- a/calendar/js/et2_widget_planner.js +++ b/calendar/js/et2_widget_planner.js @@ -692,30 +692,29 @@ var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResi window.clearTimeout(this.update_timer); } this.update_timer = window.setTimeout(jQuery.proxy(function() { - this.doInvalidate = false; - - this.widget.value = this.widget._fetch_data(); + this.widget.doInvalidate = false; // Show AJAX loader - framework.applications.calendar.sidemenuEntry.showAjaxLoader(); + this.widget.loader.show(); + + this.widget.value = this.widget._fetch_data(); this.widget._drawGrid(); // Update actions - if(this._actionManager) + if(this.widget._actionManager) { - this._link_actions(this._actionManager.children); + this.widget._link_actions(this.widget._actionManager.children); } - // Hide AJAX loader - framework.applications.calendar.sidemenuEntry.hideAjaxLoader(); - if(this.trigger) { this.widget.change(); } this.widget.update_timer = null; - this.doInvalidate = true; + this.widget.doInvalidate = true; + + window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this.widget),100); },{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT); }, diff --git a/calendar/js/et2_widget_planner_row.js b/calendar/js/et2_widget_planner_row.js index 97c5963d70..ef42444820 100644 --- a/calendar/js/et2_widget_planner_row.js +++ b/calendar/js/et2_widget_planner_row.js @@ -227,22 +227,20 @@ var et2_calendar_planner_row = et2_valueWidget.extend([et2_IDetachedDOM], { // Create event var event = et2_createWidget('calendar-event',{ - id:events[c].id, + id:'event_'+events[c].row_id, value: events[c] },this); + } + + // Seperate loop so column sorting finds all children in the right place + for(var c = 0; c < events.length && c < this._children.length; c++) + { + var event = this.getWidgetById('event_'+events[c].row_id); + if(!event) continue; if(this.isInTree()) { event.doLoadingFinished(); } - - // Copy actions set in parent - event._link_actions(this._parent._parent.options.actions||this._parent.options.actions||{}); - } - - // Seperate loop so column sorting finds all children in the right place - for(var c = 0; c < events.length && c < this._children.length; c++) - { - this.getWidgetById(events[c].id).set_value(events[c]); } }, diff --git a/calendar/js/et2_widget_timegrid.js b/calendar/js/et2_widget_timegrid.js index 5121581231..2af6aafb35 100644 --- a/calendar/js/et2_widget_timegrid.js +++ b/calendar/js/et2_widget_timegrid.js @@ -96,7 +96,8 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes // Contains times / rows this.scrolling = $j(document.createElement('div')) .addClass("calendar_calTimeGridScroll") - .appendTo(this.div); + .appendTo(this.div) + .append('
'); // Contains days / columns this.days = $j(document.createElement("div")) @@ -500,25 +501,31 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes this.day_list = []; // Wait a bit to see if anything else changes, then re-draw the days - if(this.update_timer === null) + if(this.update_timer) { - this.update_timer = window.setTimeout(jQuery.proxy(function() { - this.widget.update_timer = null; - - // Update actions - if(this.widget._actionManager) - { - this.widget._link_actions(this.widget._actionManager.children); - } - - this.widget._drawDays(); - this.widget._resizeTimes(); - if(this.trigger) - { - this.widget.change(); - } - },{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT); + window.clearTimeout(this.update_timer); } + this.update_timer = window.setTimeout(jQuery.proxy(function() { + this.widget.update_timer = null; + this.widget.loader.hide().show(); + + // Update actions + if(this.widget._actionManager) + { + this.widget._link_actions(this.widget._actionManager.children); + } + + this.widget._drawDays(); + // We have to completely re-do times, as they may have changed in + // scale to the point where more labels are needed / need to be removed + this.widget._drawTimes(); + if(this.trigger) + { + this.widget.change(); + } + // Hide loader + window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this.widget),100); + },{widget:this,"trigger":trigger}),ET2_GRID_INVALIDATE_TIMEOUT); }, detachFromDOM: function() { @@ -562,6 +569,14 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes } }, + set_disabled: function(disabled) { + this._super.apply(this, arguments); + if(disabled) + { + this.loader.show(); + } + }, + /** * Clear everything, and redraw the whole grid */ @@ -569,6 +584,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes this.div.css('height', this.options.height) .empty(); + this.loader.prependTo(this.div).show(); // Draw in the horizontal - the times this._drawTimes(); @@ -605,7 +621,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes this.scrolling .css('height', (this.div.innerHeight() - header_height)+'px') .appendTo(this.div) - .empty() .off().on('scroll', jQuery.proxy(this._scroll, this)); // Percent @@ -616,8 +631,16 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes // We need a reasonable bottom limit here... if(this.rowHeight < 5 && this.div.is(':visible')) { - this.options.granularity *= 2; - return this._drawTimes(); + if(this.rowHeight === 0) + { + // Something is not right... + this.rowHeight = 5; + } + else + { + this.options.granularity *= 2; + return this._drawTimes(); + } } // the hour rows @@ -659,8 +682,9 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes } // Set heights in pixels for scrolling - this.scrolling - .append('
' + html + '
'); + $j('.calendar_calTimeLabels',this.scrolling) + .empty() + .append(html); this.days.css('height', (this.rowHeight*i)+'px'); // Scroll to start of day @@ -797,25 +821,30 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes day.set_left((day_width * i) + 'px'); if(daily_owner) { + day.set_id(this.day_list[0]+'-'+this.options.owner[i]); day.set_date(this.day_list[0], false); day.set_owner(this.options.owner[i]); - day.set_id(this.day_list[0]+'-'+this.options.owner[i]); day.set_label(this._get_owner_name(this.options.owner[i])); } else { // Go back to self-calculated date day.set_label(''); + day.set_id(this.day_list[i]); day.set_date(this.day_list[i], this.value[this.day_list[i]] || false); day.set_owner(this.options.owner); - day.set_id(this.day_list[i]); } day.set_width(day_width + 'px'); } // Don't hold on to value any longer, use the data cache for best info this.value = {}; - + + if(daily_owner) + { + this.set_label(''); + } + // Adjust and scroll to start of day this._resizeTimes(); @@ -1190,7 +1219,8 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes set_value: function(events) { if(typeof events !== 'object') return false; - + + this.loader.show(); var use_days_sent = true; if(events.id) @@ -1198,11 +1228,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes this.set_id(events.id); delete events.id; } - if(events.owner) - { - this.set_owner(events.owner); - delete events.owner; - } if(events.start_date) { this.set_start_date(events.start_date); @@ -1215,6 +1240,13 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes delete events.end_date; use_days_sent = false; } + // set_owner() wants start_date set to get the correct week number + // for the corner label + if(events.owner) + { + this.set_owner(events.owner); + delete events.owner; + } this.value = events || {}; @@ -1230,6 +1262,12 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes // Reset and calculate instead of just use the keys so we can get the weekend preference this.day_list = []; + + // None of the above changed anything, hide the loader + if(!this.update_timer) + { + window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this),100); + } }, /** @@ -1244,6 +1282,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes var old = this.options.owner || 0; this.owner.set_label(''); this.div.removeClass('calendar_TimeGridNoLabel'); + this.options.owner = _owner; if(typeof _owner == 'string' && isNaN(_owner)) { @@ -1262,7 +1301,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes // Label is empty, but give extra space for the owner name this.div.removeClass('calendar_TimeGridNoLabel'); } - else if (typeof _owner == 'object' && _owner.length) + else if (!_owner || typeof _owner == 'object' && _owner.length) { // Don't show owners if more than one, show week number this.owner.set_value(''); @@ -1275,10 +1314,10 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes { this.owner.options.application = 'home-accounts' this.owner.set_value(typeof _owner == "string" || typeof _owner == "number" ? _owner : jQuery.extend([],_owner)); + this.set_label(''); $j(this.getDOMNode(this.owner)).prepend(this.owner.getDOMNode()); } - this.options.owner = _owner;//this.owner.getValue(); if(this.isAttached() && ( typeof old == "number" && typeof _owner == "number" && old !== this.options.owner || // Array of ids will not compare as equal @@ -1304,7 +1343,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes // 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'); this.div.toggleClass('calendar_TimeGridNoLabel', label.trim().length < 6 && typeof this.options.owner === 'object'); }, @@ -1318,11 +1356,15 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes // Avoid 0 or less minutes = Math.max(1,minutes); - if(this.options.granularity != minutes) + if(this.options.granularity !== minutes) { this.options.granularity = minutes; this._drawTimes(); } + else + { + this._resizeTimes(); + } }, /** @@ -1332,9 +1374,10 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes */ set_show_weekend: function(weekends) { + weekends = weekends ? true : false; if(this.options.show_weekend !== weekends) { - this.options.show_weekend = weekends ? true : false; + this.options.show_weekend = weekends; if(this.isAttached()) { this.invalidate(); @@ -1430,7 +1473,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes result = this.onclick.apply(this, args); } - if(event.id && result && !this.options.disabled && !this.options.readonly) + if(event.id && result && !this.disabled && !this.options.readonly) { et2_calendar_event.recur_prompt(event); @@ -1539,33 +1582,35 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes // Resizable interface resize: function () { - if(!this.div.is(':visible')) + if(this.disabled || !this.div.is(':visible')) { return; } + // Set the max width to avoid animations screwing up the width + this.div.css('max-width',$j(this.getInstanceManager().DOMContainer).width()); + // We expect the timegrid to be in a table with 0 or more other timegrids, // 1 per row. We want each timegrid to be as large as possible, but space // shared equally. Height can't be set to a percentage on the rows, because // that doesn't work. - // Find the table - var table = this.div.parentsUntil('table').parent(); - // How many rows? - var rowCount = table.children('tr').length; + var rowCount = 0; + this._parent.iterateOver(function(widget) { + if(!widget.disabled) rowCount++; + },this, et2_calendar_timegrid); // Take the whole tab height this.options.height = Math.floor(Math.min($j(this.getInstanceManager().DOMContainer).height(),$j(this.getInstanceManager().DOMContainer).parent().innerHeight()) / rowCount); this.options.height = Math.floor((egw.getHiddenDimensions(this.getInstanceManager().DOMContainer).h ) / rowCount); this.options.height -= 2*((this.div.outerWidth(true) - this.div.innerWidth()) + parseInt(this.div.parent().css('padding-top'))); - - if(this.options.height+"px" != this.div.css('height')) + if(this.options.height+"px" !== this.div.css('height')) { this.div.css('height', this.options.height); // Re-do time grid - this._drawGrid(); + this._drawTimes(); // Just re-did everything, no need to do more return; @@ -1575,8 +1620,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes var total_width = ( $j(this.getInstanceManager().DOMContainer).width() - ( this.days.innerWidth() ? this.div.innerWidth() - this.days.innerWidth() : 0 )); - // Set the max width to avoid animations screwing up the width - this.div.css('max-width',$j(this.getInstanceManager().DOMContainer).width()); var day_width = (total_width > 0 ? total_width : $j(this.getInstanceManager().DOMContainer).width())/this.day_widgets.length; // update day widgets for(var i = 0; i < this.day_widgets.length; i++) diff --git a/calendar/js/et2_widget_view.js b/calendar/js/et2_widget_view.js index 3c2603f8f4..f5202bbb01 100644 --- a/calendar/js/et2_widget_view.js +++ b/calendar/js/et2_widget_view.js @@ -43,7 +43,7 @@ var et2_calendar_view = et2_valueWidget.extend( /** * Constructor * - * @memberOf et2_calendar_planner + * @memberOf et2_calendar_view * @constructor */ init: function init() { @@ -52,6 +52,8 @@ var et2_calendar_view = et2_valueWidget.extend( // Used for its date calculations this.date_helper = et2_createWidget('date-time',{},null); this.date_helper.loadingFinished(); + + this.loader = $j('
'); }, destroy: function destroy() { @@ -62,22 +64,53 @@ var et2_calendar_view = et2_valueWidget.extend( this.date_helper = null; }, + doLoadingFinished: function() { + this._super.apply(this, arguments); + this.loader.hide(0).prependTo(this.div); + }, + /** * Something changed, and the view need to be re-drawn. We wait a bit to * avoid re-drawing twice if start and end date both changed, then recreate * as needed. * - * @param {boolean} [trigger=false] Trigger an event once things are done. + * @param {boolean} [trigger_event=false] Trigger an event once things are done. * Waiting until invalidate completes prevents 2 updates when changing the date range. * @returns {undefined} + * + * @memberOf et2_calendar_view */ - invalidate: function invalidate(trigger) {}, + invalidate: function invalidate(trigger_event) {}, + + /** + * Returns the current start date + * + * @returns {Date} + * + * @memberOf et2_calendar_view + */ + get_start_date: function get_start_date() { + return new Date(this.options.start_date); + }, + + /** + * Returns the current start date + * + * @returns {Date} + * + * @memberOf et2_calendar_view + */ + get_end_date: function get_end_date() { + return new Date(this.options.end_date); + }, /** * Change the start date * * @param {string|number|Date} new_date New starting date * @returns {undefined} + * + * @memberOf et2_calendar_view */ set_start_date: function set_start_date(new_date) { @@ -112,6 +145,8 @@ var et2_calendar_view = et2_valueWidget.extend( * * @param {string|number|Date} new_date New end date * @returns {undefined} + * + * @memberOf et2_calendar_view */ set_end_date: function set_end_date(new_date) { @@ -144,6 +179,8 @@ var et2_calendar_view = et2_valueWidget.extend( * Set which users to display * * @param {number|number[]|string|string[]} _owner Account ID + * + * @memberOf et2_calendar_view */ set_owner: function set_owner(_owner) { @@ -176,6 +213,8 @@ var et2_calendar_view = et2_valueWidget.extend( * * @param {string} user * @returns {string} + * + * @memberOf et2_calendar_view */ _get_owner_name: function _get_owner_name(user) { if(parseInt(user) === 0) diff --git a/calendar/templates/default/app.css b/calendar/templates/default/app.css index d73a81d20e..5fba129753 100644 --- a/calendar/templates/default/app.css +++ b/calendar/templates/default/app.css @@ -61,6 +61,9 @@ width: 100%; transition: width 1s ease-in-out; } +#calendar-view_view td { + padding: 0px; +} /* Header classes */ tr.dialogHeader td, tr.dialogHeader2 td, tr.dialogHeader3 td, tr.dialogHeader4 td, tr.dialogOperators td,.dialogFooterToolbar { @@ -171,6 +174,13 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget overflow-x: hidden; } +.calendar_calTimeGrid .loading,.calendar_plannerWidget .loading { + top: 0px; + bottom: 0px; + left: 0px; + right: 0px; + position: absolute; +} /* single row in the time-line you dont need to set a bgcolor, but you can */ .calendar_calTimeRow { @@ -624,7 +634,6 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget top: 0px; left: 0px; width: 99.5%; - border: 1px solid gray; padding-right: 3px; } .calendar_plannerWidget > div:not(.calendar_plannerHeader) { @@ -723,14 +732,14 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget text-overflow: ellipsis; white-space:nowrap; overflow:hidden; - margin-left: 20px; + padding-left: 20px; padding-right: 2px; } .calendar_plannerRowHeader:hover { width: initial !important; overflow:visible; z-index: 30; - background-color: white; + cursor: pointer; } /* calendar_eventRows contain multiple eventRowWidgets diff --git a/calendar/templates/default/view.xet b/calendar/templates/default/view.xet index a61ed6f95f..3f8555112b 100644 --- a/calendar/templates/default/view.xet +++ b/calendar/templates/default/view.xet @@ -22,6 +22,7 @@ Egroupware