diff --git a/calendar/inc/class.calendar_hooks.inc.php b/calendar/inc/class.calendar_hooks.inc.php index 64f05366db..db4767dd2e 100644 --- a/calendar/inc/class.calendar_hooks.inc.php +++ b/calendar/inc/class.calendar_hooks.inc.php @@ -117,10 +117,11 @@ class calendar_hooks '1' => lang('Yes'), '0' => lang('No'), ); - $grid_views = array( - 'all' => lang('all'), - 'day_week' => lang('Dayview').', '.lang('Four days view').' & '.lang('Weekview'), - 'day4' => lang('Dayview').' & '.lang('Four days view'), + $list_views = array( + 0 => lang('None'), + 'weekN' => lang('Multiple week view'), + 'week' => lang('Weekview'), + 'day4' => lang('Four days view'), 'day' => lang('Dayview'), ); $updates = array( @@ -346,19 +347,16 @@ class calendar_hooks 'admin' => False, 'forced' => 'user', ), - //ATM:Disable the use_time_grid preference - //@TODO: the whole use_time_grid preference should be removed - // after we decided that is not neccessary to have it at all - /*'use_time_grid' => array( - 'type' => 'select', - 'label' => 'Views with fixed time intervals', + 'use_time_grid' => array( + 'type' => 'multiselect', + 'label' => 'Views showing a list of events', 'name' => 'use_time_grid', - 'values' => $grid_views, - 'help' => 'For which views should calendar show distinct lines with a fixed time interval.', + 'values' => $list_views, + 'help' => 'For which views should calendar just a list of events instead of distinct lines with a fixed time interval.', 'xmlrpc' => True, 'admin' => False, - 'forced' => 'all', - ),*/ + 'default' => ['weekN'], + ), 'link_title' => array( 'type' => 'multiselect', 'label' => 'Link title for events to show', diff --git a/calendar/js/app.js b/calendar/js/app.js index fe0525a0d4..bef38f4e26 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -2082,6 +2082,10 @@ app.classes.calendar = AppJS.extend( { widget.set_show_weekend(view.show_weekend(state.state)); } + if(widget.set_granularity) + { + widget.set_granularity(view.granularity(state.state)); + } if(widget.id == value[row_index].id && widget.get_end_date().toJSON() == value[row_index].end_date ) @@ -2097,16 +2101,6 @@ app.classes.calendar = AppJS.extend( 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 @@ -3327,7 +3321,10 @@ app.classes.calendar = AppJS.extend( * How big or small are the displayed time chunks? */ granularity: function(state) { - return parseInt(egw.preference('interval','calendar')) || 30; + var list = egw.preference('use_time_grid','calendar').split(','); + return list.indexOf(state.view) >= 0 ? + 0 : + parseInt(egw.preference('interval','calendar')) || 30; }, extend: function(sub) { @@ -3505,7 +3502,8 @@ jQuery.extend(app.classes.calendar,{ return week_start; }, granularity: function(state) { - return 120; + // Always a list, not a grid + return 0; }, scroll: function(delta) { diff --git a/calendar/js/et2_widget_daycol.js b/calendar/js/et2_widget_daycol.js index d31d1ebcca..2b19cf45dd 100644 --- a/calendar/js/et2_widget_daycol.js +++ b/calendar/js/et2_widget_daycol.js @@ -160,29 +160,36 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea } } - this.display_settings.rowsToDisplay = ((this.display_settings.wd_end - this.display_settings.wd_start)/this.display_settings.granularity); - this.display_settings.rowHeight= (100/this.display_settings.rowsToDisplay).toFixed(1); - this.display_settings.titleHeight = (this.title.height()/this.div.height())*100; - - // adding divs to click on for each row / time-span - for(var t = 0,i = 1; t < 1440; t += this.display_settings.granularity,++i) + if(this.display_settings.granularity === 0) { - var linkData = { - 'menuaction':'calendar.calendar_uiforms.edit', - 'date' : this.options.date, - 'hour' : sprintf("%02d",Math.floor(t / 60)), - 'minute' : sprintf("%02d",Math.floor(t % 60)) - }; - if (this.options.owner) linkData['owner'] = this.options.owner; + this.div.attr('data-date', this.options.date); + } + else + { + this.display_settings.rowsToDisplay = ((this.display_settings.wd_end - this.display_settings.wd_start)/this.display_settings.granularity); + this.display_settings.rowHeight= (100/this.display_settings.rowsToDisplay).toFixed(1); + this.display_settings.titleHeight = (this.title.height()/this.div.height())*100; - var droppableDateTime = linkData['date'] + "T" + linkData['hour'] + linkData['minute']; - var droppableID='drop_'+droppableDateTime+'_O'+(this.options.owner<0?'group'+Math.abs(this.options.owner):this.options.owner); + // adding divs to click on for each row / time-span + for(var t = 0,i = 1; t < 1440; t += this.display_settings.granularity,++i) + { + var linkData = { + 'menuaction':'calendar.calendar_uiforms.edit', + 'date' : this.options.date, + 'hour' : sprintf("%02d",Math.floor(t / 60)), + 'minute' : sprintf("%02d",Math.floor(t % 60)) + }; + if (this.options.owner) linkData['owner'] = this.options.owner; - var hour = jQuery('
') - .attr('data-date',linkData.date) - .attr('data-hour',linkData.hour) - .attr('data-minute',linkData.minute) - .appendTo(this.div); + var droppableDateTime = linkData['date'] + "T" + linkData['hour'] + linkData['minute']; + var droppableID='drop_'+droppableDateTime+'_O'+(this.options.owner<0?'group'+Math.abs(this.options.owner):this.options.owner); + + var hour = jQuery('
') + .attr('data-date',linkData.date) + .attr('data-hour',linkData.hour) + .attr('data-minute',linkData.minute) + .appendTo(this.div); + } } }, @@ -245,7 +252,10 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea .attr('data-whole_day',true); // Avoid redrawing if date is the same - if(new_date === this.options.date && !force_redraw) + if(new_date === this.options.date && + this.display_settings.granularity === this._parent.options.granularity && + !force_redraw + ) { return; } @@ -361,13 +371,18 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea }, set_width: function(width) { - this.options.width = width; - window.setTimeout(jQuery.proxy(function() { - if(this.div) + if(this.width_timeout) { - this.div.outerWidth(this.options.width); - this.header.outerWidth(this.options.width); + window.clearTimeout(this.width_timeout); } + this.options.width = width; + this.width_timeout = window.setTimeout(jQuery.proxy(function() { + this.width_timeout = null; + if(this.div) + { + this.div.outerWidth(this.options.width); + this.header.outerWidth(this.options.width); + } },this),1); }, @@ -487,7 +502,6 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea this.div.children('.hiddenEventAfter').remove(); var timegrid = this._parent; - var day = this; // elem is jquery div of event function isHidden(elem) { @@ -511,12 +525,16 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea // Check each event this.iterateOver(function(event) { // Skip whole day events and events missing value - if(!event.options || !event.options.value || event.options.value.whole_day_on_top) return; + if(this.display_settings.granularity && ( + (!event.options || !event.options.value || event.options.value.whole_day_on_top)) + ) + { + return; + } // Reset event.title.css('top',''); event.body.css('padding-top',''); - var hidden = isHidden.call(this,event.div); if(!hidden) { @@ -529,68 +547,99 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea event.title.css('top',timegrid.scrolling.scrollTop() - event.div.position().top); event.body.css('padding-top',timegrid.scrolling.scrollTop() - event.div.position().top); } + // Too many in list view, show indicator + else if (this.display_settings.granularity === 0 && hidden.completely) + { + var day = this; + this._hidden_indicator(event, false, function() { + app.calendar.update_state({view: 'day', date: day.date}); + }); + } // Completely out of view, show indicator else if (hidden.completely) { - var indicator = ''; - if(hidden.hidden === 'top') - { - if($j('.hiddenEventBefore',this.header).length == 0) - { - indicator = $j('
') - .appendTo(this.header) - .text(event.options.value.title) - .attr('data-hidden_count', 1) - .on('click', function() { - $j('.calendar_calEvent',day.div).first()[0].scrollIntoView(); - return false; - }); - } - else - { - indicator = $j('.hiddenEventBefore',this.header); - indicator.attr('data-hidden_count', parseInt(indicator.attr('data-hidden_count')) + 1); - indicator.text(day.egw().lang('%1 event(s) %2',indicator.attr('data-hidden_count'),'')); - } - } - else if(hidden.hidden === 'bottom') - { - indicator = $j('.hiddenEventAfter',this.div); - if(indicator.length == 0) - { - indicator = $j('
') - .text(event.options.value.title) - .attr('data-hidden_count', 1) - .appendTo(this.div) - .on('click', function() { - $j('.calendar_calEvent',day.div).last()[0].scrollIntoView(false); - // Better re-run this to clean up - day._out_of_view(); - return false; - }); - } - else - { - indicator.attr('data-hidden_count', parseInt(indicator.attr('data-hidden_count')) + 1); - indicator.text(day.egw().lang('%1 event(s) %2',indicator.attr('data-hidden_count'),'')); - } - indicator.css('top',timegrid.scrolling.height() + timegrid.scrolling.scrollTop()-indicator.height()); - } - // Match color to the event - if(indicator !== '') - { - - // Avoid white, which is hard to see - var color = jQuery.Color(event.div.css('border-top-color')).toString() !== jQuery.Color('white').toString() ? - event.div.css('border-top-color') : event.div.css('background-color'); - - // Use border-top-color, Firefox doesn't give a value with border-color - indicator.css('border-color', color); - } + this._hidden_indicator(event, hidden.hidden == 'top'); } }, this, et2_calendar_event); }, + /** + * Show an indicator that there are hidden events + * + * @param {et2_calendar_event} event Event we're creating the indicator for + * @param {boolean} top Events hidden at the top (true) or bottom (false) + * @param {function} [onclick] Callback for when user clicks on the indicator + */ + _hidden_indicator: function _hidden_indicator(event, top, onclick) + { + var indicator = ''; + var day = this; + var timegrid = this._parent; + if(top) + { + if($j('.hiddenEventBefore',this.header).length === 0) + { + indicator = $j('
') + .appendTo(this.header) + .text(event.options.value.title) + .attr('data-hidden_count', 1) + .on('click', typeof onclick === 'function' ? onclick : function() { + $j('.calendar_calEvent',day.div).first()[0].scrollIntoView(); + return false; + }); + } + else + { + indicator = $j('.hiddenEventBefore',this.header); + indicator.attr('data-hidden_count', parseInt(indicator.attr('data-hidden_count')) + 1); + indicator.text(day.egw().lang('%1 event(s) %2',indicator.attr('data-hidden_count'),'')); + } + } + else + { + indicator = $j('.hiddenEventAfter',this.div); + if(indicator.length === 0) + { + indicator = $j('
') + .text(event.options.value.title) + .attr('data-hidden_count', 1) + .appendTo(this.div) + .on('click', typeof onclick === 'function' ? onclick : function() { + $j('.calendar_calEvent',day.div).last()[0].scrollIntoView(false); + // Better re-run this to clean up + day._out_of_view(); + return false; + }); + } + else + { + var count = parseInt(indicator.attr('data-hidden_count')) + 1 + indicator.attr('data-hidden_count', count); + if(this.display_settings.granularity === 0) + { + indicator.text(indicator.text() + "\n" + event.options.value.title); + } + else + { + indicator.text(day.egw().lang('%1 event(s) %2',indicator.attr('data-hidden_count'),'')); + } + indicator.css('top',timegrid.scrolling.height() + timegrid.scrolling.scrollTop()-indicator.height()); + } + } + // Match color to the event + if(indicator !== '') + { + // Avoid white, which is hard to see + // Use border-bottom-color, Firefox doesn't give a value with border-color + var color = jQuery.Color(event.div.css('border-bottom-color')).toString() !== jQuery.Color('white').toString() ? + event.div.css('border-bottom-color') : event.div.css('background-color'); + if(color !== 'rgba(0, 0, 0, 0)') + { + indicator.css('border-color', color); + } + } + }, + /** * Sort a day's events into minimally overlapping columns * @@ -598,6 +647,8 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea */ _spread_events: function() { + if(!this.date) return []; + var day_start = this.date.valueOf() / 1000; var dst_check = new Date(this.date); dst_check.setUTCHours(12); @@ -706,6 +757,21 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea // Calculate vertical positioning var top = 0; var height = 0; + // Position the event + if(this.display_settings.granularity === 0) + { + if(this.all_day.has(columns[c][i].div).length) + { + columns[c][i].div.prependTo(this.div); + } + columns[c][i].div.css('top', ''); + columns[c][i].div.css('height', ''); + columns[c][i].div.css('left', ''); + columns[c][i].div.css('width', ''); + // Strip out of view padding + columns[c][i].body.css('padding-top',''); + continue; + } if(columns[c][i].options.value.whole_day_on_top) { if(!this.all_day.has(columns[c][i].div).length) @@ -878,8 +944,15 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea return; } + if(this.display_settings.granularity !== this._parent.options.granularity) + { + // Layout has changed + this._draw(); + } // Resize & position all events this.position_event(); + + this._out_of_view(); } }); diff --git a/calendar/js/et2_widget_event.js b/calendar/js/et2_widget_event.js index be76f7eea9..ad2c6d839c 100644 --- a/calendar/js/et2_widget_event.js +++ b/calendar/js/et2_widget_event.js @@ -238,8 +238,8 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], // Let timegrid always get the drag .droppable('option','greedy',false) - // ? - .attr('data-draggable-id',event['id']+'_O'+event.owner+'_C'+(event.owner<0?'group'+Math.abs(event.owner):event.owner)) + // Set full day flag + .attr('data-full_day', event.whole_day_on_top) // Put everything we need for basic interaction here, so it's available immediately .attr('data-id', event.id) @@ -312,6 +312,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], { this.body .html(''+title+'') + .append(''+this._get_timespan(event) + '') .append('

'+this.options.value.description+'

'); } this.body diff --git a/calendar/js/et2_widget_timegrid.js b/calendar/js/et2_widget_timegrid.js index 3d054edb47..7d6ecdc64d 100644 --- a/calendar/js/et2_widget_timegrid.js +++ b/calendar/js/et2_widget_timegrid.js @@ -55,7 +55,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes name: "Granularity", type: "integer", default: parseInt(egw.preference('interval','calendar')) || 30, - description: "How many minutes per row" + description: "How many minutes per row, or 0 to display events as a list" }, "onchange": { "name": "onchange", @@ -194,6 +194,9 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes * for planner view to resize horizontally. */ this.div.on('mouseover', '.calendar_calEvent:not(.ui-resizable):not(.rowNoEdit)', function() { + // Only resize in timegrid + if(timegrid.options.granularity === 0) return; + // Load the event timegrid._get_event_info(this); var that = this; @@ -331,7 +334,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes { this.scrolling.scrollTop(element.dropEnd.position().top); } - else if (element.dropEnd.prev() && element.dropEnd.prev().position().top < this.scrolling[0].scrollTop) + else if (element.dropEnd.prev().length && element.dropEnd.prev().position().top < this.scrolling[0].scrollTop) { this.scrolling.scrollTop(element.dropEnd.prev().position().top); } @@ -341,6 +344,12 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes { time = this.egw().lang('Whole day'); } + else if (this.options.granularity === 0) + { + // No times, keep what's in the event + // Add class to helper to keep formatting + $j(helper).addClass('calendar_calTimeGridList'); + } else { time = jQuery.datepicker.formatTime( @@ -392,7 +401,13 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes if(event_data.app == 'calendar' && event_widget.options.value.whole_day) { event_widget._parent.date_helper.set_hours(0); - event_widget._parent.date_helper.set_minutes(0) + event_widget._parent.date_helper.set_minutes(0); + } + else if (timegrid.options.granularity === 0) + { + // List, not time grid - keep time + event_widget._parent.date_helper.set_hours(event_widget.options.value.start.getUTCHours()); + event_widget._parent.date_helper.set_minutes(event_widget.options.value.start.getUTCMinutes()); } else { @@ -507,6 +522,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes } this.update_timer = window.setTimeout(jQuery.proxy(function() { this.widget.update_timer = null; + window.clearTimeout(this.resize_timer); this.widget.loader.hide().show(); // Update actions @@ -600,12 +616,8 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes _drawTimes: function() { $j('.calendar_calTimeRow',this.div).remove(); - var wd_start = 60*this.options.day_start; - var wd_end = 60*this.options.day_end; - var granularity = this.options.granularity; - var totalDisplayMinutes = wd_end - wd_start; - var rowsToDisplay = Math.ceil((totalDisplayMinutes+60)/granularity); - + this.div.toggleClass('calendar_calTimeGridList', this.options.granularity === 0); + this.gridHeader .attr('data-date', this.options.start_date) .attr('data-owner', this.options.owner) @@ -613,14 +625,35 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes .append(this.owner.getDOMNode()) .append(this.dayHeader) .appendTo(this.div); + + // Max with 18 avoids problems when it's not shown + var header_height = Math.max(this.gridHeader.outerHeight(true), 18); + + this.scrolling + .appendTo(this.div) + .off() + + // No time grid - list + if(this.options.granularity === 0) + { + this.scrolling.css('height','100%'); + this.days.css('height', '100%'); + this.iterateOver(function(day) { + day.resize(); + },this,et2_calendar_daycol); + return; + } + + var wd_start = 60*this.options.day_start; + var wd_end = 60*this.options.day_end; + var granularity = this.options.granularity; + var totalDisplayMinutes = wd_end - wd_start; + var rowsToDisplay = Math.ceil((totalDisplayMinutes+60)/granularity); - // Max with 45 avoids problems when it's not shown - var header_height = Math.max(this.gridHeader.outerHeight(true), 45); this.scrolling .css('height', (this.div.innerHeight() - header_height)+'px') - .appendTo(this.div) - .off().on('scroll', jQuery.proxy(this._scroll, this)); + .on('scroll', jQuery.proxy(this._scroll, this)); // Percent var rowHeight = (100/rowsToDisplay).toFixed(1); @@ -701,6 +734,9 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes { window.clearTimeout(this.resize_timer); } + // No point if it is just going to be redone completely + if(this.upate_timer) return; + this.resize_timer = window.setTimeout(jQuery.proxy(function() { if(this._resizeTimes) { @@ -727,12 +763,23 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes var new_height = this.scrolling.height() / rowsToDisplay; this.rowHeight = new_height; var rows = $j('.calendar_calTimeRow',this.scrolling).height(this.rowHeight); - this.days.css('height', (this.rowHeight*rows.length)+'px'); + if(!rows.length && this.options.granularity) + { + return this._drawTimes(); + } + this.days.css('height', this.options.granularity === 0 ? + '100%' : + (this.rowHeight*rows.length)+'px' + ); $j('.calendar_calAddEvent',this.scrolling).height(this.rowHeight); // Scroll to start of day this._top_time = (wd_start * this.rowHeight) / this.options.granularity; this.scrolling.scrollTop(this._top_time); + + this.iterateOver(function(child) { + child.resize(); + },this, et2_IResizeable); }, /** @@ -749,7 +796,9 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes this.day_list = this._calculate_day_list(this.options.start_date, this.options.end_date, this.options.show_weekend); } // 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 daily_owner = this.day_list.length === 1 && + this.options.owner.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) @@ -815,6 +864,9 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes this.day_widgets.splice(delete_index--,1); } + // Adjust and scroll to start of day + this.resizeTimes(); + // Create / update day widgets with dates and data for(var i = 0; i < this.day_widgets.length; i++) { @@ -848,9 +900,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes this.set_label(''); } - // Adjust and scroll to start of day - this._resizeTimes(); - // Handle not fully visible elements this._scroll(); @@ -1356,15 +1405,24 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes */ set_granularity: function(minutes) { - // Avoid 0 or less - minutes = Math.max(1,minutes); + // Avoid < 0 + minutes = Math.max(0,minutes); if(this.options.granularity !== minutes) { - this.options.granularity = minutes; - this._drawTimes(); + if(this.options.granularity === 0 || minutes === 0) + { + this.options.granularity = minutes; + // Need to re-do a bunch to make sure this is propagated + this.invalidate(); + } + else + { + this.options.granularity = minutes; + this._drawTimes(); + } } - else + else if (!this.update_timer) { this.resizeTimes(); } @@ -1545,13 +1603,20 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes x = Math.round(x); y = Math.round(y); - var nodes = $j('.calendar_calAddEvent[data-hour],.calendar_calDayColHeader',this.div).removeClass('drop-hover').filter(function() { - var offset = $j(this).offset(); - var range={x:[offset.left,offset.left+$j(this).outerWidth()],y:[offset.top,offset.top+$j(this).outerHeight()]}; - - var i = (x >=range.x[0] && x <= range.x[1]) && (y >= range.y[0] && y <= range.y[1]); - return i; - }).addClass("drop-hover"); + var nodes = this.options.granularity === 0 ? + $j('.calendar_calDayCol',this.div) : + $j('.calendar_calAddEvent[data-hour],.calendar_calDayColHeader',this.div); + + nodes = nodes + .removeClass('drop-hover') + .filter(function() { + var offset = $j(this).offset(); + var range={x:[offset.left,offset.left+$j(this).outerWidth()],y:[offset.top,offset.top+$j(this).outerHeight()]}; + + var i = (x >=range.x[0] && x <= range.x[1]) && (y >= range.y[0] && y <= range.y[1]); + return i; + }) + nodes.addClass("drop-hover"); return nodes; }, @@ -1611,7 +1676,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes height -= $j('#calendar-toolbar').outerHeight(true); this.options.height = Math.floor(height / rowCount); - + // Allow for borders & padding 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')) @@ -1626,9 +1691,9 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes } // Try to resize width, though animations cause problems - var total_width = ( $j(this.getInstanceManager().DOMContainer).width() - ( + var total_width = Math.min(this.div.width(),( $j(this.getInstanceManager().DOMContainer).width() - ( this.days.innerWidth() ? this.div.innerWidth() - this.days.innerWidth() : 0 - )); + ))); 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/setup/setup.inc.php b/calendar/setup/setup.inc.php index 4dbb70ba6f..fafe82ed5b 100755 --- a/calendar/setup/setup.inc.php +++ b/calendar/setup/setup.inc.php @@ -10,7 +10,7 @@ */ $setup_info['calendar']['name'] = 'calendar'; -$setup_info['calendar']['version'] = '14.3.902'; +$setup_info['calendar']['version'] = '14.3.903'; $setup_info['calendar']['app_order'] = 3; $setup_info['calendar']['enable'] = 1; $setup_info['calendar']['index'] = 'calendar.calendar_uiviews.index&ajax=true'; diff --git a/calendar/setup/tables_update.inc.php b/calendar/setup/tables_update.inc.php index 7cce063ce7..3900a54017 100644 --- a/calendar/setup/tables_update.inc.php +++ b/calendar/setup/tables_update.inc.php @@ -2683,3 +2683,23 @@ function calendar_upgrade14_3_901() }); return $GLOBALS['setup_info']['calendar']['currentver'] = '14.3.902'; } + +/** + * Change grid/list preference values to list each view + */ +function calendar_upgrade14_3_902() +{ + preferences::change_preference('calendar', 'use_time_grid', function($attr, $old_value, $owner) { + switch($old_value) + { + case 'all': + return 0; + case 'day_week': + return ['day','day4','week']; + case 'day4': + return ['day','day4']; + } + return null; + }); + return $GLOBALS['setup_info']['calendar']['currentver'] = '14.3.903'; +} diff --git a/calendar/templates/default/app.css b/calendar/templates/default/app.css index d0b1f49fa9..600a916749 100644 --- a/calendar/templates/default/app.css +++ b/calendar/templates/default/app.css @@ -191,6 +191,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget width: 100%; overflow-y: auto; overflow-x: hidden; + cursor: default; } .calendar_calTimeGrid .loading,.calendar_plannerWidget .loading { @@ -298,6 +299,7 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget border-right: 0px; overflow: hidden; z-index: 40; + cursor: pointer; } .calendar_calDayColHeader .hiddenEventBefore { height: 2px; @@ -602,7 +604,9 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget .calendar_calEventBody > p, .calendar_calEventBodySmall > p { white-space: pre-wrap; } - +.calendar_calEventBody .calendar_calTimespan { + display: none; +} .calendar_calEventBodySmall{ font-size: 95%; } @@ -615,6 +619,59 @@ e.g. the div with class calendar_calTimeGrid is generated by the timeGridWidget font-weight: bold; } +/* Events as displayed in a list, not sized by time */ +.calendar_calTimeGridList .calendar_calTimeGridScroll { + overflow-y: hidden; +} +.calendar_calTimeGridList .calendar_calGridHeader { + min-height: 1em; +} +.calendar_calTimeGridList .calendar_calDayColAllDay { + display: none; +} +.calendar_calTimeGridList .calendar_calDayColHeader { + min-height: initial; + padding-bottom: 0px; +} +.calendar_calTimeGridList .calendar_calEvent { + min-height: 1.1em; + position: relative; +} +.calendar_calTimeGridList .calendar_calEvent:not([data-full_day]) { + border-top: none; + border-left: none; + border-right: none; +} +.calendar_calTimeGridList .calendar_calEventHeader { + display: none !important; +} +.calendar_calTimeGridList .calendar_calEventTitle { + font-weight: normal; + display: inline-block; + max-height:2.4em; + white-space: nowrap; +} +.calendar_calTimeGridList .calendar_calEventBody:not(.calendar_calEventBodySmall) { + overflow: hidden; +} +.calendar_calTimeGridList .calendar_calEventBody .calendar_calTimespan { + display: inline-block; + float: right; + padding-left: 1em; + opacity: 0.8; + font-size: 90% +} +.calendar_calTimeGridList .calendar_calEventBody > p { + display: none; +} +.calendar_calTimeGridList .calendar_calDayCol .hiddenEventAfter:hover { + /* Need !important to override calculated height*/ + top: initial !important; + bottom: 0px; + white-space: pre; + height: 100%; +} + /* table of the dayView containing 2 cols: 1) day-view, 2) todos */ .calendar_calDayView{