Add preference to limit the events per day in the month view.
authorJan Schneider <jan@horde.org>
Tue, 16 Mar 2010 21:37:46 +0000 (22:37 +0100)
committerJan Schneider <jan@horde.org>
Tue, 16 Mar 2010 21:40:34 +0000 (22:40 +0100)
kronolith/config/prefs.php.dist
kronolith/docs/CHANGES
kronolith/js/kronolith.js
kronolith/lib/Kronolith.php
kronolith/themes/screen.css

index 98162a9..51a81d9 100644 (file)
@@ -10,7 +10,7 @@ $prefGroups['view'] = array(
     'label' => _("User Interface"),
     'desc' => _("Select confirmation options, how to display the different views and choose default view."),
     'members' => array('dynamic_view', 'confirm_delete', 'defaultview',
-                       'time_between_days', 'week_start_monday',
+                       'max_events', 'time_between_days', 'week_start_monday',
                        'day_hour_start', 'day_hour_end', 'day_hour_force',
                        'slots_per_hour', 'show_icons', 'show_time',
                        'show_location', 'show_fb_legend',
@@ -95,6 +95,14 @@ $_prefs['defaultview'] = array(
     'desc' => _("Select the view to display on startup:")
 );
 
+$_prefs['max_events'] = array(
+    'value' => 3,
+    'locked' => false,
+    'shared' => false,
+    'type' => 'number',
+    'desc' => _("How many events should be displayed per day in the month view? Set to 0 to always show all events."),
+);
+
 // Display the timeslots between each day column, in week view.
 $_prefs['time_between_days'] = array(
     'value' => 0,
index b4fc357..ae9875d 100644 (file)
@@ -2,6 +2,7 @@
 v3.0-git
 --------
 
+[jan] Add preference to limit the events per day in the month view.
 [jan] Add system calendars (Request #2059).
 [jan] Add URL field to events.
 [jan] Add task management capabilities to the Ajax interface.
index 965a5c3..d8164b5 100644 (file)
@@ -1276,6 +1276,88 @@ KronolithCore = {
                         }
                         this.holidays.push(event.key);
                     }
+                    if (view == 'month' && Kronolith.conf.max_events) {
+                        var events = $('kronolithMonthDay' + date).select('.kronolithEvent');
+                        if (events.size() >= Kronolith.conf.max_events) {
+                            if (date == (new Date().dateString())) {
+                                // This is today.
+                                if (event.value.al || event.value.end.isBefore()) {
+                                    // No room for all-day or finished events.
+                                    this.insertMore(date);
+                                    return;
+                                }
+                                var remove, max;
+                                // Find an event that is earlier than now or
+                                // later then the current event.
+                                events.each(function(elm) {
+                                    var calendar = elm.retrieve('calendar').split('|'),
+                                        event = this.ecache.get(calendar[0]).get(calendar[1]).get(date).get(elm.retrieve('eventid'));
+                                    if (event.start.isBefore()) {
+                                        remove = elm;
+                                        throw $break;
+                                    }
+                                    if (!max || event.start.isAfter(max)) {
+                                        max = event.start;
+                                        remove = elm;
+                                    }
+                                }, this);
+                                if (remove) {
+                                    remove.remove();
+                                } else {
+                                    this.insertMore(date);
+                                    return;
+                                }
+                            } else {
+                                // Not today.
+                                var allDays = events.findAll(function(elm) {
+                                    var calendar = elm.retrieve('calendar').split('|');
+                                    return this.ecache.get(calendar[0]).get(calendar[1]).get(date).get(elm.retrieve('eventid')).al;
+                                }.bind(this));
+                                if (event.value.al) {
+                                    // We want one all-day event.
+                                    if (allDays.size()) {
+                                        // There already is an all-day event.
+                                        if (event.value.x == Kronolith.conf.status.confirmed ||
+                                            event.value.x == Kronolith.conf.status.tentative) {
+                                            // But is there a less important
+                                            // one?
+                                            var status = [Kronolith.conf.status.free, Kronolith.conf.status.cancelled];
+                                            if (event.value.x == Kronolith.conf.status.confirmed) {
+                                                status.push(Kronolith.conf.status.tentative);
+                                            }
+                                            var free = allDays.detect(function(elm) {
+                                                var calendar = elm.retrieve('calendar').split('|');
+                                                return status.include(this.ecache.get(calendar[0]).get(calendar[1]).get(date).get(elm.retrieve('eventid')).x);
+                                            }.bind(this));
+                                            if (!free) {
+                                                this.insertMore(date);
+                                                return;
+                                            }
+                                            free.remove();
+                                        } else {
+                                            // No.
+                                            this.insertMore(date);
+                                            return;
+                                        }
+                                    } else {
+                                        // Remove the last event to make room
+                                        // for this one.
+                                        events.pop().remove();
+                                    }
+                                } else {
+                                    if (allDays.size() > 1) {
+                                        // We don't want more than one all-day
+                                        // event.
+                                        allDays.pop().remove();
+                                    } else {
+                                        // This day is full.
+                                        this.insertMore(date);
+                                        return;
+                                    }
+                                }
+                            }
+                        }
+                    }
                     break;
 
                 case 'year':
@@ -1571,12 +1653,17 @@ KronolithCore = {
             var div = _createElement(event)
                 .setStyle({ backgroundColor: Kronolith.conf.calendars[calendar[0]][calendar[1]].bg,
                             color: Kronolith.conf.calendars[calendar[0]][calendar[1]].fg });
-
             $('kronolithMonthDay' + date).insert(div);
             if (event.value.pe) {
                 div.setStyle({ cursor: 'move' });
                 new Drag('kronolithEventmonth' + event.value.calendar + date + event.key, { threshold: 5, parentElement: function() { return $('kronolithViewMonthBody'); }, snapToParent: true });
             }
+            if (Kronolith.conf.max_events) {
+                var more = $('kronolithMonthDay' + date).down('.kronolithMore');
+                if (more) {
+                    $('kronolithMonthDay' + date).insert({ bottom: more.remove() });
+                }
+            }
             break;
 
         case 'agenda':
@@ -1599,6 +1686,22 @@ KronolithCore = {
             .observe('mouseout', div.removeClassName.curry('kronolithSelected'));
     },
 
+    /**
+     * Adds a "more..." button to the month view cell that links to the days,
+     * or moves it to the buttom.
+     *
+     * @param string date  The date string of the day cell.
+     */
+    insertMore: function(date)
+    {
+        var more = $('kronolithMonthDay' + date).down('.kronolithMore');
+        if (more) {
+            $('kronolithMonthDay' + date).insert({ bottom: more.remove() });
+        } else {
+            $('kronolithMonthDay' + date).insert({ bottom: new Element('span', { className: 'kronolithMore' }).store('date', date).insert(Kronolith.text.more) });
+        }
+    },
+
     setEventText: function(div, event)
     {
         var calendar = event.calendar.split('|');
@@ -3516,6 +3619,11 @@ KronolithCore = {
                 e.stop();
                 return;
 
+            case 'kronolithMore':
+                this.go('day:' + elt.retrieve('date'));
+                e.stop();
+                return;
+
             case 'kronolithDatePicker':
                 id = elt.readAttribute('id');
                 Horde_Calendar.open(id, Date.parseExact($F(id.replace(/Picker$/, 'Date')), Kronolith.conf.date_format));
index a28fc07..0e7c61e 100644 (file)
@@ -202,14 +202,15 @@ class Kronolith
             'login_view' => $prefs->getValue('defaultview') == 'workweek' ? 'week' : $prefs->getValue('defaultview'),
             'default_calendar' => 'internal|' . self::getDefaultCalendar(Horde_Perms::EDIT),
             'week_start' => (int)$prefs->getValue('week_start_monday'),
+            'max_events' => (int)$prefs->getValue('max_events'),
             'date_format' => str_replace(array('%e', '%d', '%a', '%A', '%m', '%h', '%b', '%B', '%y', '%Y'),
                                          array('d', 'dd', 'ddd', 'dddd', 'MM', 'MMM', 'MMM', 'MMMM', 'yy', 'yyyy'),
                                          Horde_Nls::getLangInfo(D_FMT)),
             'time_format' => $prefs->getValue('twentyFour') ? 'HH:mm' : 'hh:mm tt',
             'status' => array('tentative' => self::STATUS_TENTATIVE,
-                             'confirmed' => self::STATUS_CONFIRMED,
-                             'cancelled' => self::STATUS_CANCELLED,
-                             'free' => self::STATUS_FREE),
+                              'confirmed' => self::STATUS_CONFIRMED,
+                              'cancelled' => self::STATUS_CANCELLED,
+                              'free' => self::STATUS_FREE),
             'recur' => array(Horde_Date_Recurrence::RECUR_NONE => 'None',
                              Horde_Date_Recurrence::RECUR_DAILY => 'Daily',
                              Horde_Date_Recurrence::RECUR_WEEKLY => 'Weekly',
@@ -346,6 +347,7 @@ class Kronolith
             'agenda' => _("Agenda"),
             'searching' => sprintf(_("Events matching \"%s\""), '#{term}'),
             'allday' => _("All day"),
+            'more' => _("more..."),
             'prefs' => _("Options"),
             'no_url' => _("You must specify a URL."),
             'wrong_auth' => _("The authentication information you specified wasn't accepted."),
index 78095a8..d0db1b0 100644 (file)
@@ -1282,18 +1282,6 @@ table.kronolithView td.kronolithFirstCol {
     background-color: #ebf3fc;
     border-color: #808080;
 }
-.kronolithMore {
-    position: absolute;
-    z-index: 10;
-    right: 0;
-    bottom: 0;
-    width: 15px;
-    height: 15px;
-    background: white;
-    border-right: none;
-    border-bottom: none;
-    text-align: center;
-}
 /*
 .kronolithWeekend {
     background: #ffc;