Only add resize handlers to the first and last day of multi-day events.
authorJan Schneider <jan@horde.org>
Wed, 28 Oct 2009 13:17:54 +0000 (14:17 +0100)
committerJan Schneider <jan@horde.org>
Wed, 28 Oct 2009 14:54:21 +0000 (15:54 +0100)
Implement dragging (not resizing yet) of multi-day events.

kronolith/ajax.php
kronolith/js/kronolith.js
kronolith/lib/Event.php
kronolith/lib/Kronolith.php

index 4b9c338..67c2605 100644 (file)
@@ -258,6 +258,16 @@ try {
                     $event->end->hour = $event->end->min = $event->end->sec = 0;
                 }
                 break;
+
+            case 'offDays':
+                $event->start->mday += $value;
+                $event->end->mday += $value;
+                break;
+
+            case 'offMins':
+                $event->start->min += $value;
+                $event->end->min += $value;
+                break;
             }
         }
         $result = saveEvent($event);
index aa2e3f3..a39fbe1 100644 (file)
@@ -1044,17 +1044,30 @@ KronolithCore = {
 
             var midnight = this.parseDate(date),
                 innerDiv = new Element('DIV', { 'class': 'kronolithEventInfo' }),
-                draggerTop = new Element('DIV', { 'id': event.value.nodeId + 'top', 'class': 'kronolithDragger kronolithDraggerTop' }).setStyle(style),
+                draggerTop, draggerBottom;
+            if (event.value.fi) {
+                draggerTop = new Element('DIV', { 'id': event.value.nodeId + 'top', 'class': 'kronolithDragger kronolithDraggerTop' }).setStyle(style);
+            } else {
+                innerDiv.setStyle({ 'top': 0 });
+            }
+            if (event.value.la) {
                 draggerBottom = new Element('DIV', { 'id': event.value.nodeId + 'bottom', 'class': 'kronolithDragger kronolithDraggerBottom' }).setStyle(style);
+            } else {
+                innerDiv.setStyle({ 'bottom': 0 });
+            }
 
             div.setStyle({
                 'top': (Math.round(midnight.getElapsed(event.value.start) / 60000) * this[storage].height / 60 + this[storage].offset | 0) + 'px',
                 'height': (Math.round(event.value.start.getElapsed(event.value.end) / 60000) * this[storage].height / 60 - this[storage].spacing | 0) + 'px',
                 'width': '100%'
             })
-                .insert(innerDiv.setStyle(style))
-                .insert(draggerTop)
-                .insert(draggerBottom);
+                .insert(innerDiv.setStyle(style));
+            if (draggerTop) {
+                div.insert(draggerTop);
+            }
+            if (draggerBottom) {
+                div.insert(draggerBottom);
+            }
             $(view == 'day' ? 'kronolithEventsDay' : 'kronolithEventsWeek' + date).insert(div);
 
             if (event.value.pe) {
@@ -1062,29 +1075,43 @@ KronolithCore = {
                     // Top-most position (minimum y) of top dragger
                 var minTop = this[storage].allDay + this[storage].spacing,
                     // Number of pixels that cover 10 minutes.
-                    step = this[storage].height / 6,
+                    step = this[storage].height / 6;
+                if (draggerTop) {
                     // Top position of top dragger
-                    dragTop = draggerTop.cumulativeOffset().top,
+                    var dragTop = draggerTop.cumulativeOffset().top;
+                }
+                if (draggerBottom) {
                     // Top position of bottom dragger
-                    dragBottom = draggerBottom.cumulativeOffset().top,
-                    // Height of bottom dragger
-                    dragBottomHeight = draggerBottom.getHeight(),
+                    var dragBottom = draggerBottom.cumulativeOffset().top,
+                        // Height of bottom dragger
+                        dragBottomHeight = draggerBottom.getHeight();
+                }
                     // Top position of the whole event div
-                    eventTop = div.cumulativeOffset().top,
+                var eventTop = div.cumulativeOffset().top;
+                if (draggerTop) {
                     // Bottom-most position (maximum y) of top dragger
-                    maxTop = div.offsetTop + draggerBottom.offsetTop
+                    var maxTop = div.offsetTop
                         - minTop - draggerTop.getHeight()
-                        - parseInt(innerDiv.getStyle('lineHeight')),
+                        - parseInt(innerDiv.getStyle('lineHeight'));
+                    if (draggerBottom) {
+                        maxTop += draggerBottom.offsetTop;
+                    }
+                }
+                if (draggerBottom) {
                     // Top-most position (minimum y) of bottom dragger (upper
                     // edge)
-                    minBottom = div.offsetTop - minTop + draggerTop.getHeight()
+                    var minBottom = div.offsetTop - minTop
                         + parseInt(innerDiv.getStyle('lineHeight')),
                     // Bottom-most position (maximum y) of bottom dragger
                     // (upper edge)
                     maxBottom = 24 * this[storage].height
-                        + this[storage].allDay - dragBottomHeight,
+                        + this[storage].allDay - dragBottomHeight;
+                    if (draggerTop) {
+                        minBottom += draggerTop.getHeight();
+                    }
+                }
                     // Height of the whole event div
-                    divHeight = div.getHeight(),
+                var divHeight = div.getHeight(),
                     // Maximum height of the whole event div
                     maxDiv = 24 * this[storage].height
                         + this[storage].allDay
@@ -1101,7 +1128,7 @@ KronolithCore = {
                             this.addClassName('kronolithSelected');
                         }.bind(div),
                         'onEnd': function(d, e) {
-                            this[0]._onDragEnd(d, this[1], innerDiv, event, midnight, view);
+                            this[0]._onDragEnd(d, this[1], innerDiv, event, midnight, view, step);
                         }.bind([this, div]),
                         'onDrag': function(d, e) {
                             var div = this[1],
@@ -1130,17 +1157,21 @@ KronolithCore = {
                         }.bind([this, div])
                     };
 
-                opts.snap = function(x, y, elm) {
-                    y = Math.max(0, step * (Math.min(maxTop, y - minTop) / step | 0)) + minTop;
-                    return [0, y];
+                if (draggerTop) {
+                    opts.snap = function(x, y, elm) {
+                        y = Math.max(0, step * (Math.min(maxTop, y - minTop) / step | 0)) + minTop;
+                        return [0, y];
+                    }
+                    new Drag(event.value.nodeId + 'top', opts);
                 }
-                new Drag(event.value.nodeId + 'top', opts);
 
-                opts.snap = function(x, y, elm) {
-                    y = Math.min(maxBottom - minTop + dragBottomHeight + KronolithCore[storage].spacing, step * ((Math.max(minBottom, y - minTop) + dragBottomHeight + KronolithCore[storage].spacing) / step | 0)) + minTop - dragBottomHeight - KronolithCore[storage].spacing;
-                    return [0, y];
+                if (draggerBottom) {
+                    opts.snap = function(x, y, elm) {
+                        y = Math.min(maxBottom - minTop + dragBottomHeight + KronolithCore[storage].spacing, step * ((Math.max(minBottom, y - minTop) + dragBottomHeight + KronolithCore[storage].spacing) / step | 0)) + minTop - dragBottomHeight - KronolithCore[storage].spacing;
+                        return [0, y];
+                    }
+                    new Drag(event.value.nodeId + 'bottom', opts);
                 }
-                new Drag(event.value.nodeId + 'bottom', opts);
 
                 if (view == 'week') {
                     var dates = this.viewDates(midnight, view),
@@ -1150,6 +1181,7 @@ KronolithCore = {
                         maxLeft = $('kronolithEventsWeek' + dates[1].toString('yyyyMMdd')).offsetLeft - $('kronolithEventsWeek' + date).offsetLeft,
                         stepX = (maxLeft - minLeft) / 6;
                 }
+                var startTop = div.offsetTop - minTop;
                 new Drag(div, {
                     'threshold': 5,
                     'nodrop': true,
@@ -1173,15 +1205,18 @@ KronolithCore = {
                         }
                         if (view == 'week') {
                             var offsetX = Math.round(d.ghost.offsetLeft / stepX);
+                            event.value.offsetDays = offsetX;
                             this[0]._calculateEventDates(event.value, storage, step, d.ghost.offsetTop - minTop, divHeight, eventStart.clone().addDays(offsetX), eventEnd.clone().addDays(offsetX));
                         } else {
+                            event.value.offsetDays = 0;
                             this[0]._calculateEventDates(event.value, storage, step, d.ghost.offsetTop - minTop, divHeight);
                         }
+                        event.value.offsetTop = d.ghost.offsetTop - minTop - startTop;
                         d.innerDiv.update('(' + event.value.start.toString(Kronolith.conf.time_format) + ' - ' + event.value.end.toString(Kronolith.conf.time_format) + ') ' + event.value.t.escapeHTML());
                         this[1].clonePosition(d.ghost);
                     }.bind([this, div]),
                     'onEnd': function(d, e) {
-                        this[0]._onDragEnd(d, this[1], innerDiv, event, midnight, view);
+                        this[0]._onDragEnd(d, this[1], innerDiv, event, midnight, view, step);
                     }.bind([this, div]),
                 });
             }
@@ -1325,15 +1360,23 @@ KronolithCore = {
     /**
      * Called as the event handler after dragging/resizing a day/week event.
      */
-    _onDragEnd: function(drag, div, innerDiv, event, date, view)
+    _onDragEnd: function(drag, div, innerDiv, event, date, view, step)
     {
         var dates = this.viewDates(date, view),
             start = dates[0].toString('yyyyMMdd'),
-            end = dates[1].toString('yyyyMMdd');
+            end = dates[1].toString('yyyyMMdd'),
+            attributes;
         div.removeClassName('kronolithSelected');
         this._setEventText(innerDiv, event.value);
         drag.destroy();
         this.startLoading(event.value.calendar, start, end);
+        if (Object.isUndefined(event.value.offsetTop)) {
+            attributes = $H({ 'start': event.value.start,
+                              'end': event.value.end });
+        } else {
+            attributes = $H({ 'offDays': event.value.offsetDays,
+                              'offMins': event.value.offsetTop / step * 10 });
+        }
         this.doAction(
             'UpdateEvent',
             { 'cal': event.value.calendar,
@@ -1341,10 +1384,7 @@ KronolithCore = {
               'view': view,
               'view_start': start,
               'view_end': end,
-              'att': $H({
-                  start: event.value.start,
-                  end: event.value.end,
-              }).toJSON()
+              'att': attributes.toJSON()
             },
             function(r) {
                 if (r.response.events) {
index a0b55e9..88ff1c9 100644 (file)
@@ -108,11 +108,25 @@ abstract class Kronolith_Event
     /**
      * This tag's events.
      *
-     * @var mixed  Array of tags or comma delimited string.
+     * @var array|string
      */
     public $tags = array();
 
     /**
+     * Whether this is the event on the first day of a multi-day event.
+     *
+     * @var boolen
+     */
+    public $first = true;
+
+    /**
+     * Whether this is the event on the last day of a multi-day event.
+     *
+     * @var boolen
+     */
+    public $last = true;
+
+    /**
      * All the attendees of this event.
      *
      * This is an associative array where the keys are the email addresses
@@ -1073,6 +1087,8 @@ abstract class Kronolith_Event
      * - c: calendar id
      * - s: start date
      * - e: end date
+     * - fi: first day of a multi-day event
+     * - la: last day of a multi-day event
      * - x: status (Kronolith::STATUS_* constant)
      * - al: all-day?
      * - bg: background color
@@ -1107,6 +1123,8 @@ abstract class Kronolith_Event
         $json->c = $this->getCalendar();
         $json->s = $this->start->toJson();
         $json->e = $this->end->toJson();
+        $json->fi = $this->first;
+        $json->la = $this->last;
         $json->x = $this->status;
         $json->al = is_null($allDay) ? $this->isAllDay() : $allDay;
         $json->bg = $this->_backgroundColor;
index 1ee54ed..6f69873 100644 (file)
@@ -511,10 +511,10 @@ class Kronolith
                         $eventEnd = $endDate;
                     }
                 } else {
-                    /* If the event doesn't end at 12am set the end date to the
-                     * current end date. If it ends at 12am and does not end at
-                     * the same time that it starts (0 duration), set the end date
-                     * to the previous day's end date. */
+                    /* If the event doesn't end at 12am set the end date to
+                     * the current end date. If it ends at 12am and does not
+                     * end at the same time that it starts (0 duration), set
+                     * the end date to the previous day's end date. */
                     if ($event->end->hour != 0 ||
                         $event->end->min != 0 ||
                         $event->end->sec != 0 ||
@@ -555,6 +555,7 @@ class Kronolith
                             $addEvent->start = new Horde_Date(array(
                                 'hour' => 0, 'min' => 0, 'sec' => 0,
                                 'month' => $loopDate->month, 'mday' => $loopDate->mday, 'year' => $loopDate->year));
+                            $addEvent->first = false;
                         }
 
                         /* If this is the end day, set the end time to the
@@ -565,6 +566,7 @@ class Kronolith
                             $addEvent->end = new Horde_Date(array(
                                 'hour' => 23, 'min' => 59, 'sec' => 59,
                                 'month' => $loopDate->month, 'mday' => $loopDate->mday, 'year' => $loopDate->year));
+                            $addEvent->last = false;
                         }
 
                         $results[$loopDate->dateString()][$addEvent->getId()] = $json ? $addEvent->toJson($allDay) : $addEvent;
@@ -596,12 +598,19 @@ class Kronolith
     {
         $loopDate = new Horde_Date($eventStart->year, $eventStart->month, $eventStart->mday);
         $allDay = $event->isAllDay();
+        $first = true;
         while ($loopDate->compareDateTime($eventEnd) <= 0) {
             if (!$allDay ||
                 $loopDate->compareDateTime($eventEnd) != 0) {
                 $addEvent = clone $event;
                 $addEvent->start = $eventStart;
                 $addEvent->end = $eventEnd;
+                if ($loopDate->compareDate($eventStart) != 0) {
+                    $addEvent->first = false;
+                }
+                if ($loopDate->compareDate($eventEnd) != 0) {
+                    $addEvent->last = false;
+                }
                 $results[$loopDate->dateString()][$addEvent->getId()] = $json ? $addEvent->toJson($allDay) : $addEvent;
             }
             $loopDate->mday++;