Rescheduling events by dragging them in day view

Summary: Ref T8300, Rescheduling events by dragging them in day view

Test Plan: Open day view, drag events, observe them reschedule.

Reviewers: chad, epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Maniphest Tasks: T8300

Differential Revision: https://secure.phabricator.com/D12988
This commit is contained in:
lkassianik
2015-05-23 19:47:23 -07:00
parent 7d757483a0
commit 963485a3da
8 changed files with 274 additions and 90 deletions

View File

@@ -7,7 +7,7 @@
*/ */
return array( return array(
'names' => array( 'names' => array(
'core.pkg.css' => '36142bff', 'core.pkg.css' => '439658b5',
'core.pkg.js' => '328799d0', 'core.pkg.js' => '328799d0',
'darkconsole.pkg.js' => 'e7393ebb', 'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => 'bb338e4b', 'differential.pkg.css' => 'bb338e4b',
@@ -112,7 +112,7 @@ return array(
'rsrc/css/core/core.css' => 'aaea7a7a', 'rsrc/css/core/core.css' => 'aaea7a7a',
'rsrc/css/core/remarkup.css' => '07b7dc54', 'rsrc/css/core/remarkup.css' => '07b7dc54',
'rsrc/css/core/syntax.css' => '6b7b24d9', 'rsrc/css/core/syntax.css' => '6b7b24d9',
'rsrc/css/core/z-index.css' => '8414a09b', 'rsrc/css/core/z-index.css' => 'c4732d32',
'rsrc/css/diviner/diviner-shared.css' => '38813222', 'rsrc/css/diviner/diviner-shared.css' => '38813222',
'rsrc/css/font/font-awesome.css' => 'e2e712fe', 'rsrc/css/font/font-awesome.css' => 'e2e712fe',
'rsrc/css/font/font-source-sans-pro.css' => '8906c07b', 'rsrc/css/font/font-source-sans-pro.css' => '8906c07b',
@@ -121,7 +121,7 @@ return array(
'rsrc/css/layout/phabricator-hovercard-view.css' => 'dd9121a9', 'rsrc/css/layout/phabricator-hovercard-view.css' => 'dd9121a9',
'rsrc/css/layout/phabricator-side-menu-view.css' => 'c1db9e9c', 'rsrc/css/layout/phabricator-side-menu-view.css' => 'c1db9e9c',
'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894', 'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894',
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'c0cf782a', 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'feba82c5',
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338', 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338',
'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0',
'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893', 'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893',
@@ -331,7 +331,7 @@ return array(
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'b1a59974', 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'b1a59974',
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761',
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
'rsrc/js/application/calendar/behavior-day-view.js' => 'f4f4ad80', 'rsrc/js/application/calendar/behavior-day-view.js' => 'dc0065ab',
'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8', 'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8',
'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de', 'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de',
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '10246726', 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '10246726',
@@ -554,7 +554,7 @@ return array(
'javelin-behavior-dashboard-move-panels' => '82439934', 'javelin-behavior-dashboard-move-panels' => '82439934',
'javelin-behavior-dashboard-query-panel-select' => '453c5375', 'javelin-behavior-dashboard-query-panel-select' => '453c5375',
'javelin-behavior-dashboard-tab-panel' => 'd4eecc63', 'javelin-behavior-dashboard-tab-panel' => 'd4eecc63',
'javelin-behavior-day-view' => 'f4f4ad80', 'javelin-behavior-day-view' => 'dc0065ab',
'javelin-behavior-device' => 'a205cf28', 'javelin-behavior-device' => 'a205cf28',
'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18', 'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18',
'javelin-behavior-differential-comment-jump' => '4fdb476d', 'javelin-behavior-differential-comment-jump' => '4fdb476d',
@@ -752,7 +752,7 @@ return array(
'phabricator-uiexample-reactor-select' => 'a155550f', 'phabricator-uiexample-reactor-select' => 'a155550f',
'phabricator-uiexample-reactor-sendclass' => '1def2711', 'phabricator-uiexample-reactor-sendclass' => '1def2711',
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee', 'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
'phabricator-zindex-css' => '8414a09b', 'phabricator-zindex-css' => 'c4732d32',
'phame-css' => '88bd4705', 'phame-css' => '88bd4705',
'pholio-css' => '95174bdd', 'pholio-css' => '95174bdd',
'pholio-edit-css' => '3ad9d1ee', 'pholio-edit-css' => '3ad9d1ee',
@@ -767,7 +767,7 @@ return array(
'phui-box-css' => '7b3a2eed', 'phui-box-css' => '7b3a2eed',
'phui-button-css' => 'de610129', 'phui-button-css' => 'de610129',
'phui-calendar-css' => 'ccabe893', 'phui-calendar-css' => 'ccabe893',
'phui-calendar-day-css' => 'c0cf782a', 'phui-calendar-day-css' => 'feba82c5',
'phui-calendar-list-css' => 'c1c7f338', 'phui-calendar-list-css' => 'c1c7f338',
'phui-calendar-month-css' => '476be7e0', 'phui-calendar-month-css' => '476be7e0',
'phui-crumbs-view-css' => '594d719e', 'phui-crumbs-view-css' => '594d719e',

View File

@@ -1498,6 +1498,7 @@ phutil_register_library_map(array(
'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php', 'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php',
'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php', 'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php',
'PhabricatorCalendarEventCommentController' => 'applications/calendar/controller/PhabricatorCalendarEventCommentController.php', 'PhabricatorCalendarEventCommentController' => 'applications/calendar/controller/PhabricatorCalendarEventCommentController.php',
'PhabricatorCalendarEventDragController' => 'applications/calendar/controller/PhabricatorCalendarEventDragController.php',
'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php', 'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php',
'PhabricatorCalendarEventEditIconController' => 'applications/calendar/controller/PhabricatorCalendarEventEditIconController.php', 'PhabricatorCalendarEventEditIconController' => 'applications/calendar/controller/PhabricatorCalendarEventEditIconController.php',
'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php', 'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php',
@@ -4853,6 +4854,7 @@ phutil_register_library_map(array(
), ),
'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventCommentController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventCommentController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventDragController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditIconController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditIconController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',

View File

@@ -54,6 +54,8 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
=> 'PhabricatorCalendarEventEditController', => 'PhabricatorCalendarEventEditController',
'edit/(?P<id>[1-9]\d*)/' 'edit/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventEditController', => 'PhabricatorCalendarEventEditController',
'drag/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventDragController',
'cancel/(?P<id>[1-9]\d*)/' 'cancel/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventCancelController', => 'PhabricatorCalendarEventCancelController',
'(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/' '(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/'

View File

@@ -0,0 +1,66 @@
<?php
final class PhabricatorCalendarEventDragController
extends PhabricatorCalendarController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$event = id(new PhabricatorCalendarEventQuery())
->setViewer($viewer)
->withIDs(array($request->getURIData('id')))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$event) {
return new Aphront404Response();
}
if (!$request->validateCSRF()) {
return new Aphront400Response();
}
if ($event->getIsAllDay()) {
return new Aphront400Response();
}
$xactions = array();
$duration = $event->getDateTo() - $event->getDateFrom();
$start = $request->getInt('start');
$start_value = id(AphrontFormDateControlValue::newFromEpoch(
$viewer,
$start));
$end = $start + $duration;
$end_value = id(AphrontFormDateControlValue::newFromEpoch(
$viewer,
$end));
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_START_DATE)
->setNewValue($start_value);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_END_DATE)
->setNewValue($end_value);
$editor = id(new PhabricatorCalendarEventEditor())
->setActor($viewer)
->setContinueOnMissingFields(true)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true);
$xactions = $editor->applyTransactions($event, $xactions);
return id(new AphrontReloadResponse());
}
}

View File

@@ -9,7 +9,6 @@ final class PHUICalendarDayView extends AphrontView {
private $year; private $year;
private $browseURI; private $browseURI;
private $events = array(); private $events = array();
private $jsTodayEvents = array();
private $allDayEvents = array(); private $allDayEvents = array();
@@ -44,8 +43,11 @@ final class PHUICalendarDayView extends AphrontView {
public function render() { public function render() {
require_celerity_resource('phui-calendar-day-css'); require_celerity_resource('phui-calendar-day-css');
$viewer = $this->getUser();
$hours = $this->getHoursOfDay(); $hours = $this->getHoursOfDay();
$js_hours = array(); $js_hours = array();
$js_today_events = array();
foreach ($hours as $hour) { foreach ($hours as $hour) {
$js_hours[] = array( $js_hours[] = array(
@@ -55,10 +57,7 @@ final class PHUICalendarDayView extends AphrontView {
} }
$first_event_hour = null; $first_event_hour = null;
$js_hourly_events = array();
$js_today_all_day_events = array(); $js_today_all_day_events = array();
$all_day_events = $this->getAllDayEvents(); $all_day_events = $this->getAllDayEvents();
$day_start = $this->getDateTime(); $day_start = $this->getDateTime();
@@ -81,60 +80,54 @@ final class PHUICalendarDayView extends AphrontView {
} }
} }
foreach ($hours as $hour) { $this->events = msort($this->events, 'getEpochStart');
$current_hour_events = array();
$hour_start = $hour->format('U'); if (!$this->events) {
$hour_end = id(clone $hour)->modify('+1 hour')->format('U'); $first_event_hour = $this->getDateTime()->setTime(8, 0, 0);
}
foreach ($this->events as $event) { foreach ($this->events as $event) {
if ($event->getIsAllDay()) { if ($event->getIsAllDay()) {
continue; continue;
} }
if (($hour == $day_start && if ($event->getEpochStart() <= $day_end_epoch &&
$event->getEpochStart() <= $hour_start && $event->getEpochEnd() > $day_start_epoch) {
$event->getEpochEnd() > $day_start_epoch) ||
($event->getEpochStart() >= $hour_start if ($first_event_hour === null) {
&& $event->getEpochStart() < $hour_end)) { $first_event_hour = new DateTime('@'.$event->getEpochStart());
$current_hour_events[] = $event; $first_event_hour->setTimeZone($viewer->getTimeZone());
$this->jsTodayEvents[] = array( $eight_am = $this->getDateTime()->setTime(8, 0, 0);
'eventStartEpoch' => $event->getEpochStart(), if ($eight_am->format('U') < $first_event_hour->format('U')) {
'eventEndEpoch' => $event->getEpochEnd(), $first_event_hour = clone $eight_am;
'eventName' => $event->getName(),
'eventID' => $event->getEventID(),
'viewerIsInvited' => $event->getViewerIsInvited(),
'uri' => $event->getURI(),
);
} }
} }
foreach ($current_hour_events as $event) {
$day_start_epoch = $this->getDateTime()->format('U');
$event_start = max($event->getEpochStart(), $day_start_epoch); $event_start = max($event->getEpochStart(), $day_start_epoch);
$event_end = min($event->getEpochEnd(), $day_end_epoch); $event_end = min($event->getEpochEnd(), $day_end_epoch);
$top = (($event_start - $hour_start) / ($hour_end - $hour_start)) $day_duration = ($day_end_epoch - $first_event_hour->format('U')) / 60;
* 100;
$top = (($event_start - $first_event_hour->format('U'))
/ ($day_end_epoch - $first_event_hour->format('U')))
* $day_duration;
$top = max(0, $top); $top = max(0, $top);
$height = (($event_end - $event_start) / ($hour_end - $hour_start)) $height = (($event_end - $event_start)
* 100; / ($day_end_epoch - $first_event_hour->format('U')))
$height = min(2400, $height); * $day_duration;
$height = min($day_duration, $height);
if ($first_event_hour === null) { $js_today_events[] = array(
$first_event_hour = $hour;
}
$js_hourly_events[] = array(
'eventStartEpoch' => $event->getEpochStart(), 'eventStartEpoch' => $event->getEpochStart(),
'eventEndEpoch' => $event->getEpochEnd(), 'eventEndEpoch' => $event->getEpochEnd(),
'eventName' => $event->getName(), 'eventName' => $event->getName(),
'eventID' => $event->getEventID(), 'eventID' => $event->getEventID(),
'viewerIsInvited' => $event->getViewerIsInvited(), 'viewerIsInvited' => $event->getViewerIsInvited(),
'uri' => $event->getURI(), 'uri' => $event->getURI(),
'hour' => $hour->format('G'),
'offset' => '0', 'offset' => '0',
'width' => '100%', 'width' => '100%',
'top' => $top.'%', 'top' => $top.'px',
'height' => $height.'%', 'height' => $height.'px',
); );
} }
} }
@@ -156,10 +149,10 @@ final class PHUICalendarDayView extends AphrontView {
'day-view', 'day-view',
array( array(
'allDayEvents' => $js_today_all_day_events, 'allDayEvents' => $js_today_all_day_events,
'todayEvents' => $this->jsTodayEvents, 'todayEvents' => $js_today_events,
'hourlyEvents' => $js_hourly_events,
'hours' => $js_hours, 'hours' => $js_hours,
'firstEventHour' => $first_event_hour->format('G'), 'firstEventHour' => $first_event_hour->format('G'),
'firstEventHourEpoch' => $first_event_hour->format('U'),
'tableID' => $table_id, 'tableID' => $table_id,
)); ));

View File

@@ -36,6 +36,10 @@
z-index: 2; z-index: 2;
} }
div.phui-calendar-day-event {
z-index: 2;
}
.slowvote-above-the-bar { .slowvote-above-the-bar {
z-index: 3; z-index: 3;
} }

View File

@@ -35,7 +35,11 @@
border-top: 1px solid {$lightgreyborder}; border-top: 1px solid {$lightgreyborder};
} }
.phui-calendar-day-view td div.phui-calendar-day-event { .phui-drag {
opacity: .25;
}
div.phui-calendar-day-event {
width: 100%; width: 100%;
position: absolute; position: absolute;
top: 0; top: 0;
@@ -43,11 +47,15 @@
min-height: 30px; min-height: 30px;
} }
div.phui-calendar-day-event.all-day {
position: relative;
}
.phui-calendar-day-event-link { .phui-calendar-day-event-link {
padding: 8px; padding: 8px;
border: 1px solid {$greyborder}; border: 1px solid {$greyborder};
background-color: {$darkgreybackground}; background-color: {$darkgreybackground};
margin: 0 4px; margin: 0 1px;
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;

View File

@@ -4,13 +4,6 @@
JX.behavior('day-view', function(config) { JX.behavior('day-view', function(config) {
var hours = config.hours;
var first_event_hour = config.firstEventHour;
var hourly_events = config.hourlyEvents;
var today_events = config.todayEvents;
var today_all_day_events = config.allDayEvents;
var table_wrapper = JX.$(config.tableID);
function findTodayClusters() { function findTodayClusters() {
var events = today_events.sort(function(x, y){ var events = today_events.sort(function(x, y){
@@ -23,8 +16,8 @@ JX.behavior('day-view', function(config) {
var today_event = events[i]; var today_event = events[i];
var destination_cluster_index = null; var destination_cluster_index = null;
var event_start = today_event.eventStartEpoch - (30*60); var event_start = today_event.eventStartEpoch - (60);
var event_end = today_event.eventEndEpoch + (30*60); var event_end = today_event.eventEndEpoch + (60);
for (var j=0; j < clusters.length; j++) { for (var j=0; j < clusters.length; j++) {
var cluster = clusters[j]; var cluster = clusters[j];
@@ -59,7 +52,7 @@ JX.behavior('day-view', function(config) {
return clusters; return clusters;
} }
function updateEventsFromCluster(cluster, hourly_events) { function updateEventsFromCluster(cluster) {
var cluster_size = cluster.length; var cluster_size = cluster.length;
var n = 0; var n = 0;
for(var i=0; i < cluster.length; i++) { for(var i=0; i < cluster.length; i++) {
@@ -69,28 +62,30 @@ JX.behavior('day-view', function(config) {
var offset = ((n / cluster_size) * 100) + '%'; var offset = ((n / cluster_size) * 100) + '%';
var width = ((1 / cluster_size) * 100) + '%'; var width = ((1 / cluster_size) * 100) + '%';
for (var j=0; j < hourly_events.length; j++) { for (var j=0; j < today_events.length; j++) {
if (hourly_events[j].eventID == event_id) { if (today_events[j].eventID == event_id) {
hourly_events[j]['offset'] = offset; today_events[j]['offset'] = offset;
hourly_events[j]['width'] = width; today_events[j]['width'] = width;
} }
} }
n++; n++;
} }
return hourly_events; return today_events;
} }
function drawEvent(hourly_event) { function drawEvent(e) {
var name = hourly_event['eventName']; var name = e['eventName'];
var viewerIsInvited = hourly_event['viewerIsInvited']; var eventID = e['eventID'];
var offset = hourly_event['offset']; var viewerIsInvited = e['viewerIsInvited'];
var width = hourly_event['width']; var offset = e['offset'];
var top = hourly_event['top']; var width = e['width'];
var height = hourly_event['height']; var top = e['top'];
var uri = hourly_events['uri']; var height = e['height'];
var uri = e['uri'];
var sigil = 'phui-calendar-day-event';
var link_class = 'phui-calendar-day-event-link'; var link_class = 'phui-calendar-day-event-link';
if (viewerIsInvited) { if (viewerIsInvited) {
@@ -109,6 +104,8 @@ JX.behavior('day-view', function(config) {
'div', 'div',
{ {
className: 'phui-calendar-day-event', className: 'phui-calendar-day-event',
sigil: sigil,
meta: {eventID: eventID, record: e, uri: uri},
style: { style: {
left: offset, left: offset,
width: width, width: width,
@@ -145,7 +142,7 @@ JX.behavior('day-view', function(config) {
var div_all_day = JX.$N( var div_all_day = JX.$N(
'div', 'div',
{className: 'phui-calendar-day-event'}, {className: 'phui-calendar-day-event all-day'},
[all_day_label, name]); [all_day_label, name]);
return div_all_day; return div_all_day;
@@ -164,24 +161,17 @@ JX.behavior('day-view', function(config) {
if (hours[i]['hour'] < min_early_hour) { if (hours[i]['hour'] < min_early_hour) {
continue; continue;
} }
var drawn_hourly_events = [];
var cell_time = JX.$N( var cell_time = JX.$N(
'td', 'td',
{className: 'phui-calendar-day-hour'}, {className: 'phui-calendar-day-hour'},
hours[i]['hour_meridian']); hours[i]['hour_meridian']);
for (var j=0; j < hourly_events.length; j++) {
if (hourly_events[j]['hour'] == hours[i]['hour']) {
drawn_hourly_events.push(drawEvent(hourly_events[j]));
}
}
var cell_event = JX.$N( var cell_event = JX.$N(
'td', 'td',
{ {
className: 'phui-calendar-day-events' className: 'phui-calendar-day-events'
}, });
drawn_hourly_events);
var row = JX.$N( var row = JX.$N(
'tr', 'tr',
{}, {},
@@ -191,10 +181,26 @@ JX.behavior('day-view', function(config) {
return rows; return rows;
} }
function clusterAndDrawEvents() {
var today_clusters = findTodayClusters(); var today_clusters = findTodayClusters();
for(var i=0; i < today_clusters.length; i++) { for(var i=0; i < today_clusters.length; i++) {
hourly_events = updateEventsFromCluster(today_clusters[i], hourly_events); today_events = updateEventsFromCluster(today_clusters[i]);
} }
var drawn_hourly_events = [];
for (i=0; i < today_events.length; i++) {
drawn_hourly_events.push(drawEvent(today_events[i]));
}
JX.DOM.setContent(hourly_events_wrapper, drawn_hourly_events);
}
var hours = config.hours;
var first_event_hour = config.firstEventHour;
var first_event_hour_epoch = parseInt(config.firstEventHourEpoch, 10);
var today_events = config.todayEvents;
var today_all_day_events = config.allDayEvents;
var table_wrapper = JX.$(config.tableID);
var rows = drawRows(); var rows = drawRows();
var all_day_events = []; var all_day_events = [];
@@ -211,5 +217,108 @@ JX.behavior('day-view', function(config) {
{className: 'phui-calendar-day-view'}, {className: 'phui-calendar-day-view'},
rows); rows);
JX.DOM.setContent(table_wrapper, [all_day_events, table]); var dragging = false;
var origin = null;
var offset_top = null;
var new_top = null;
var click_time = null;
JX.DOM.listen(
table_wrapper,
'mousedown',
'phui-calendar-day-event',
function(e){
if (!e.isNormalMouseEvent()) {
return;
}
e.kill();
dragging = e.getNode('phui-calendar-day-event');
JX.DOM.alterClass(dragging, 'phui-drag', true);
click_time = new Date();
origin = JX.$V(e);
var outer = JX.Vector.getPos(table);
var inner = JX.Vector.getPos(dragging);
offset_top = inner.y - outer.y;
new_top = offset_top;
dragging.style.top = offset_top + 'px';
});
JX.Stratcom.listen('mousemove', null, function(e){
if (!dragging) {
return;
}
var cursor = JX.$V(e);
new_top = cursor.y - origin.y + offset_top;
new_top = Math.min(new_top, 1320);
new_top = Math.max(new_top, 0);
new_top = Math.floor(new_top/15) * 15;
dragging.style.top = new_top + 'px';
});
JX.Stratcom.listen('mouseup', null, function(){
var data = JX.Stratcom.getData(dragging);
var record = data.record;
if (!dragging) {
return;
}
if (new_top == offset_top) {
var now = new Date();
if (now.getTime() - click_time.getTime() < 250) {
JX.$U(record.uri).go();
}
JX.DOM.alterClass(dragging, 'phui-drag', false);
dragging = false;
return;
}
var new_time = first_event_hour_epoch + (new_top * 60);
var id = data.eventID;
var duration = record.eventEndEpoch - record.eventStartEpoch;
record.eventStartEpoch = new_time;
record.eventEndEpoch = new_time + duration;
record.top = new_top + 'px';
new JX.Workflow(
'/calendar/event/drag/' + id + '/',
{start: new_time})
.start();
JX.DOM.alterClass(dragging, 'phui-drag', false);
dragging = false;
clusterAndDrawEvents();
});
JX.DOM.listen(table_wrapper, 'click', 'phui-calendar-day-event', function(e){
if (e.isNormalClick()) {
e.kill();
}
});
var hourly_events_wrapper = JX.$N(
'div',
{style: {
position: 'absolute',
left: '69px',
right: 0
}});
clusterAndDrawEvents();
var daily_wrapper = JX.$N(
'div',
{style: {position: 'relative'}},
[hourly_events_wrapper, table]);
JX.DOM.setContent(table_wrapper, [all_day_events, daily_wrapper]);
}); });