diff --git a/calendar/js/app.js b/calendar/js/app.js index d0e5137170..fd11d60074 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -1824,7 +1824,7 @@ app.classes.calendar = AppJS.extend( { case 'day': case 'day4': - grid_count = state.state.owner.length >= parseInt(this.egw.preference('day_consolidate','calendar')) ? 1 : state.state.owner.length; + grid_count = 1 break; case 'week': grid_count = state.state.owner.length >= parseInt(this.egw.preference('week_consolidate','calendar')) ? 1 : state.state.owner.length; @@ -1900,7 +1900,7 @@ app.classes.calendar = AppJS.extend( { widget.set_show_weekend(view.show_weekend(state.state)); } - },this, et2_valueWidget); + },this, et2_calendar_view); // Granularity needs to be done seperately grid.iterateOver(function(widget) { @@ -1908,7 +1908,7 @@ app.classes.calendar = AppJS.extend( { widget.set_granularity(view.granularity(state.state)); } - },this, et2_valueWidget); + },this, et2_calendar_view); } } else @@ -1931,11 +1931,24 @@ app.classes.calendar = AppJS.extend( { widget['set_'+updater](value); } - }, this, et2_valueWidget); + }, 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 @@ -1946,7 +1959,6 @@ app.classes.calendar = AppJS.extend( for(var i = 0; i < view.etemplates.length; i++) { $j(view.etemplates[i].DOMContainer).show(); - view.etemplates[i].resize(); } // Toggle todos if(state.state.view == 'day' || this.state.view == 'day') @@ -2343,7 +2355,8 @@ app.classes.calendar = AppJS.extend( * Take the date range(s) in the value and decide if we need to fetch data * for the date ranges, or if they're already cached fill them in. * - * @param { + * @param {Object} value + * @param {Object} state */ _need_data: function(value, state) { @@ -2522,7 +2535,7 @@ app.classes.calendar = AppJS.extend( } } catch(e) {debugger;} } - + app.calendar.state_update_in_progress = in_progress; } } diff --git a/calendar/js/et2_widget_daycol.js b/calendar/js/et2_widget_daycol.js index ba46fb2d21..5045eec629 100644 --- a/calendar/js/et2_widget_daycol.js +++ b/calendar/js/et2_widget_daycol.js @@ -227,12 +227,16 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], sprintf("%02d",this._parent.date_helper.get_date()); // Set label - // Add timezone offset back in, or formatDate will lose those hours - var formatDate = new Date(this.date.valueOf() + this.date.getTimezoneOffset() * 60 * 1000); - var date_string = this._parent._children.length === 1 ? - app.calendar.date.long_date(formatDate,false, false, true) : - jQuery.datepicker.formatDate('DD dd',formatDate); - this.title.text(date_string) + if(!this.options.label) + { + // Add timezone offset back in, or formatDate will lose those hours + var formatDate = new Date(this.date.valueOf() + this.date.getTimezoneOffset() * 60 * 1000); + var date_string = this._parent._children.length === 1 ? + app.calendar.date.long_date(formatDate,false, false, true) : + jQuery.datepicker.formatDate('DD dd',formatDate); + this.title.text(date_string); + } + this.title .attr("data-date", new_date); this.header .attr('data-date',new_date) @@ -294,7 +298,8 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], 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); + this.title + .attr("data-owner", this.options.owner); // Register for updates on events for this day egw.dataRegisterUID( @@ -328,6 +333,10 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM], this._update_events(events); }, + set_label: function(label) { + this.options.label = label; + this.title.text(label); + }, set_left: function(left) { // Maybe? window.setTimeout(jQuery.proxy(function() { diff --git a/calendar/js/et2_widget_planner.js b/calendar/js/et2_widget_planner.js index 09fcfe6700..60f1073966 100644 --- a/calendar/js/et2_widget_planner.js +++ b/calendar/js/et2_widget_planner.js @@ -12,7 +12,7 @@ "use strict"; /*egw:uses - /etemplate/js/et2_core_valueWidget; + /calendar/js/et2_widget_view.js; /calendar/js/et2_widget_planner_row.js; /calendar/js/et2_widget_event.js; */ @@ -24,31 +24,17 @@ * @augments et2_valueWidget * @class */ -var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizeable], +var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResizeable], { createNamespace: true, attributes: { - start_date: { - name: "Start date", - type: "any" - }, - end_date: { - name: "End date", - type: "any" - }, group_by: { name: "Group by", type: "string", // or category ID default: "0", description: "Display planner by 'user', 'month', or the given category" }, - owner: { - name: "Owner", - type: "any", // Integer, or array of integers - default: 0, - description: "Account ID number of the calendar owner, if not the current user" - }, filter: { name: "Filter", type: "string", @@ -103,10 +89,6 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize this.vertical_bar = $j(document.createElement("div")) .addClass('verticalBar') .appendTo(this.div); - - // Used for its date calculations - this.date_helper = et2_createWidget('date-time',{},null); - this.date_helper.loadingFinished(); this.value = []; @@ -128,10 +110,6 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize 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; - // Stop the invalidate timer if(this.update_timer) { @@ -1631,76 +1609,6 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize } }, - /** - * Change the start date - * - * @param {string|number|Date} new_date New starting date - * @returns {undefined} - */ - set_start_date: function(new_date) - { - if(!new_date || new_date === null) - { - throw new Error('Invalid start date. ' + new_date.toString()); - } - - // Use date widget's existing functions to deal - if(typeof new_date === "object" || typeof new_date === "string" && new_date.length > 8) - { - this.date_helper.set_value(new_date); - } - else if(typeof new_date === "string") - { - this.date_helper.set_year(new_date.substring(0,4)); - this.date_helper.set_month(new_date.substring(4,6)); - this.date_helper.set_date(new_date.substring(6,8)); - } - - var old_date = this.options.start_date; - this.options.start_date = new Date(this.date_helper.getValue()); - - if(old_date !== this.options.start_date && this.isAttached()) - { - this.invalidate(true); - } - }, - - /** - * Change the end date - * - * @param {string|number|Date} new_date New end date - * @returns {undefined} - */ - set_end_date: function(new_date) - { - if(!new_date || new_date === null) - { - throw new Error('Invalid end date. ' + new_date.toString()); - } - // Use date widget's existing functions to deal - if(typeof new_date === "object" || typeof new_date === "string" && new_date.length > 8) - { - this.date_helper.set_value(new_date); - } - else if(typeof new_date === "string") - { - this.date_helper.set_year(new_date.substring(0,4)); - this.date_helper.set_month(new_date.substring(4,6)); - this.date_helper.set_date(new_date.substring(6,8)); - } - - this.date_helper.set_hours(23); - this.date_helper.set_minutes(59); - this.date_helper.date.setSeconds(59); - var old_date = this.options.end_date; - this.options.end_date = new Date(this.date_helper.getValue()); - - if(old_date !== this.options.end_date && this.isAttached()) - { - this.invalidate(true); - } - }, - /** * Change how the planner is grouped * @@ -1722,37 +1630,6 @@ var et2_calendar_planner = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResize } }, - /** - * Set which users to display when filtering, and for rows when grouping by user. - * - * @param {number|number[]} _owner Account ID - */ - set_owner: function(_owner) - { - var old = this.options.owner; - if(!jQuery.isArray(_owner)) - { - if(typeof _owner === "string") - { - _owner = _owner.split(','); - } - else - { - _owner = [_owner]; - } - } - else - { - _owner = jQuery.extend([],_owner); - } - this.options.owner = _owner; - if(old !== this.options.owner && this.isAttached()) - { - this.invalidate(true); - } - }, - - /** * Call change handler, if set */ diff --git a/calendar/js/et2_widget_timegrid.js b/calendar/js/et2_widget_timegrid.js index dc9a9266b6..796657977e 100644 --- a/calendar/js/et2_widget_timegrid.js +++ b/calendar/js/et2_widget_timegrid.js @@ -12,7 +12,7 @@ "use strict"; /*egw:uses - /etemplate/js/et2_core_valueWidget; + /calendar/js/et2_widget_view.js; /calendar/js/et2_widget_daycol.js; /calendar/js/et2_widget_event.js; */ @@ -24,19 +24,11 @@ * * @augments et2_DOMWidget */ -var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizeable], +var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResizeable], { createNamespace: true, attributes: { - start_date: { - name: "Start date", - type: "any" - }, - end_date: { - name: "End date", - type: "any" - }, value: { type: "any", description: "An array of events, indexed by date (Ymd format)." @@ -65,13 +57,6 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz default: parseInt(egw.preference('interval','calendar')) || 30, description: "How many minutes per row" }, - owner: { - name: "Owner", - type: "any", // Integer, or array of integers - default: 0, - description: "Account ID number of the calendar owner, if not the current user" - }, - "onchange": { "name": "onchange", "type": "js", @@ -118,10 +103,6 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz .addClass("calendar_calDayCols") .appendTo(this.scrolling); - // Used for its date calculations - this.date_helper = et2_createWidget('date',{},null); - this.date_helper.loadingFinished(); - // Used for owners this.owner = et2_createWidget('select-account_ro',{},this); @@ -166,10 +147,6 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz this.scrolling = null; this._labelContainer = null; - // date_helper has no parent, so we must explicitly remove it - this.date_helper.destroy(); - this.date_helper = null; - // Stop the invalidate timer if(this.update_timer) { @@ -510,7 +487,7 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz * The whole grid is not regenerated because times aren't expected to change, * just the days. * - * @param {boolean} trigger=false Trigger an event once things are done. + * @param {boolean} [trigger=false] Trigger an event once things are done. * Waiting until invalidate completes prevents 2 updates when changing the date range. * @returns {undefined} */ @@ -740,21 +717,25 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz { this.day_list = this._calculate_day_list(this.options.start_date, this.options.end_date, this.options.show_weekend); } - var day_width = ( this.days.width()/this.day_list.length); + // For a single day, we show each owner in their own daycol + var daily_owner = this.day_list.length === 1 && this.options.owner.length < parseInt(egw.preference('day_consolidate','calendar')); + var daycols_needed = daily_owner ? this.options.owner.length : this.day_list.length; + var day_width = ( Math.min( $j(this.getInstanceManager().DOMContainer).width(),this.days.width())/daycols_needed); if(!day_width || !this.day_list) { // Hidden on another tab, or no days for some reason var dim = egw.getHiddenDimensions(this.days, false); - day_width = ( dim.w /Math.max(this.day_list.length,1)); + day_width = ( dim.w /Math.max(daycols_needed,1)); } // Create any needed widgets - otherwise, we'll just recycle // Add any needed day widgets (now showing more days) var add_index = 0; var before = true; - while(this.day_list.length > this.day_widgets.length) + + while(daycols_needed > this.day_widgets.length) { - var existing_index = this.day_widgets[add_index] ? this.day_list.indexOf(this.day_widgets[add_index].options.date) : -1; + var existing_index = this.day_widgets[add_index] && !daily_owner ? this.day_list.indexOf(this.day_widgets[add_index].options.date) : -1; before = existing_index > add_index; var day = et2_createWidget('calendar-daycol',{ @@ -779,16 +760,19 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz // Remove any extra day widgets (now showing less) var delete_index = this.day_widgets.length - 1; before = false; - while(this.day_widgets.length > this.day_list.length) + while(this.day_widgets.length > daycols_needed) { // If we're going down to an existing one, just keep it for cool CSS animation - while(this.day_list.indexOf(this.day_widgets[delete_index].options.date) > -1) + while(delete_index > 1 && this.day_list.indexOf(this.day_widgets[delete_index].options.date) > -1) { delete_index--; before = true; } + if(delete_index < 0) delete_index = 0; // Wait until any animations or other timeouts are done window.setTimeout(jQuery.proxy(function() { + this.div.hide(); + this.header.hide(); this.free(); },this.day_widgets[delete_index]),1000); @@ -801,16 +785,27 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz } // Create / update day widgets with dates and data - for(var i = 0; i < this.day_list.length; i++) + for(var i = 0; i < this.day_widgets.length; i++) { day = this.day_widgets[i]; // Position day.set_left((day_width * i) + 'px'); - - 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]); + if(daily_owner) + { + 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_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'); } @@ -1233,73 +1228,6 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz this.day_list = []; }, - /** - * Change the start date - * - * @param {string|number|Date} new_date New starting date - * @returns {undefined} - */ - set_start_date: function(new_date) - { - if(!new_date || new_date === null) - { - throw exception('Invalid start date. ' + new_date.toString()); - } - - // Use date widget's existing functions to deal - if(typeof new_date === "object" || typeof new_date === "string" && new_date.length > 8) - { - this.date_helper.set_value(new_date); - } - else if(typeof new_date === "string") - { - this.date_helper.set_year(new_date.substring(0,4)); - this.date_helper.set_month(new_date.substring(4,6)); - this.date_helper.set_date(new_date.substring(6,8)); - } - - var old_date = this.options.start_date; - this.options.start_date = this.date_helper.getValue(); - - if(old_date !== this.options.start_date && this.isAttached()) - { - this.invalidate(true); - } - }, - - /** - * Change the end date - * - * @param {string|number|Date} new_date New end date - * @returns {undefined} - */ - set_end_date: function(new_date) - { - if(!new_date || new_date === null) - { - throw exception('Invalid end date. ' + new_date.toString()); - } - // Use date widget's existing functions to deal - if(typeof new_date === "object" || typeof new_date === "string" && new_date.length > 8) - { - this.date_helper.set_value(new_date); - } - else if(typeof new_date === "string") - { - this.date_helper.set_year(new_date.substring(0,4)); - this.date_helper.set_month(new_date.substring(4,6)); - this.date_helper.set_date(new_date.substring(6,8)); - } - - var old_date = this.options.end_date; - this.options.end_date = this.date_helper.getValue(); - - if(old_date !== this.options.end_date && this.isAttached()) - { - this.invalidate(true); - } - }, - /** * Set which user owns this. Owner is passed along to the individual * days. @@ -1640,9 +1568,14 @@ var et2_calendar_timegrid = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResiz } // Try to resize width, though animations cause problems - var day_width = ( $j(this.getInstanceManager().DOMContainer).width() - (this.div.innerWidth() - this.days.innerWidth()))/this.day_list.length; + 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_list.length; i++) + for(var i = 0; i < this.day_widgets.length; i++) { var day = this.day_widgets[i]; diff --git a/calendar/js/et2_widget_view.js b/calendar/js/et2_widget_view.js new file mode 100644 index 0000000000..3c2603f8f4 --- /dev/null +++ b/calendar/js/et2_widget_view.js @@ -0,0 +1,217 @@ +/* + * Egroupware + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package + * @subpackage + * @link http://www.egroupware.org + * @author Nathan Gray + * @version $Id$ + */ + +"use strict"; + +/*egw:uses + /etemplate/js/et2_core_valueWidget; +*/ + +/** + * Parent class for the various calendar views to reduce copied code + * + * @augments et2_valueWidget + */ +var et2_calendar_view = et2_valueWidget.extend( +{ + createNamespace: true, + + attributes: { + owner: { + name: "Owner", + type: "any", // Integer, or array of integers, or string like r13 (resources, addressbook) + default: 0, + description: "Account ID number of the calendar owner, if not the current user" + }, + start_date: { + name: "Start date", + type: "any" + }, + end_date: { + name: "End date", + type: "any" + }, + }, + + /** + * Constructor + * + * @memberOf et2_calendar_planner + * @constructor + */ + init: function init() { + this._super.apply(this, arguments); + + // Used for its date calculations + this.date_helper = et2_createWidget('date-time',{},null); + this.date_helper.loadingFinished(); + }, + + destroy: function destroy() { + this._super.apply(this, arguments); + + // date_helper has no parent, so we must explicitly remove it + this.date_helper.destroy(); + this.date_helper = null; + }, + + /** + * 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. + * Waiting until invalidate completes prevents 2 updates when changing the date range. + * @returns {undefined} + */ + invalidate: function invalidate(trigger) {}, + + /** + * Change the start date + * + * @param {string|number|Date} new_date New starting date + * @returns {undefined} + */ + set_start_date: function set_start_date(new_date) + { + if(!new_date || new_date === null) + { + throw exception('Invalid start date. ' + new_date.toString()); + } + + // Use date widget's existing functions to deal + if(typeof new_date === "object" || typeof new_date === "string" && new_date.length > 8) + { + this.date_helper.set_value(new_date); + } + else if(typeof new_date === "string") + { + this.date_helper.set_year(new_date.substring(0,4)); + this.date_helper.set_month(new_date.substring(4,6)); + this.date_helper.set_date(new_date.substring(6,8)); + } + + var old_date = this.options.start_date; + this.options.start_date = this.date_helper.getValue(); + + if(old_date !== this.options.start_date && this.isAttached()) + { + this.invalidate(true); + } + }, + + /** + * Change the end date + * + * @param {string|number|Date} new_date New end date + * @returns {undefined} + */ + set_end_date: function set_end_date(new_date) + { + if(!new_date || new_date === null) + { + throw exception('Invalid end date. ' + new_date.toString()); + } + // Use date widget's existing functions to deal + if(typeof new_date === "object" || typeof new_date === "string" && new_date.length > 8) + { + this.date_helper.set_value(new_date); + } + else if(typeof new_date === "string") + { + this.date_helper.set_year(new_date.substring(0,4)); + this.date_helper.set_month(new_date.substring(4,6)); + this.date_helper.set_date(new_date.substring(6,8)); + } + + var old_date = this.options.end_date; + this.options.end_date = this.date_helper.getValue(); + + if(old_date !== this.options.end_date && this.isAttached()) + { + this.invalidate(true); + } + }, + + /** + * Set which users to display + * + * @param {number|number[]|string|string[]} _owner Account ID + */ + set_owner: function set_owner(_owner) + { + var old = this.options.owner; + if(!jQuery.isArray(_owner)) + { + if(typeof _owner === "string") + { + _owner = _owner.split(','); + } + else + { + _owner = [_owner]; + } + } + else + { + _owner = jQuery.extend([],_owner); + } + this.options.owner = _owner; + if(old !== this.options.owner && this.isAttached()) + { + this.invalidate(true); + } + }, + + /** + * Calendar supports many different owner types, including users & resources. + * This translates an ID to a user-friendly name. + * + * @param {string} user + * @returns {string} + */ + _get_owner_name: function _get_owner_name(user) { + if(parseInt(user) === 0) + { + // 0 means current user + user = egw.user('account_id'); + } + if (isNaN(user)) // resources or contact + { + var application = 'home-accounts'; + switch(user[0]) + { + case 'c': + application = 'addressbook'; + break; + case 'r': + application = 'resources'; + this.owner.set_value(_owner.substr(1)); + break; + } + // This might not have a value right away + user = egw.link_title(application,user.match(/\d+/)[0]); + } + else // users + { + user = parseInt(user) + var accounts = egw.accounts(); + for(var j = 0; j < accounts.length; j++) + { + if(accounts[j].value === user) + { + user = accounts[j].label; + break; + } + } + } + return user; + } +}); \ No newline at end of file