1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 19:40:55 +01:00

Give the Calendar month view a nice hover effect

Summary:
Ref T11326. Currently, we link Calendar days using hidden DOM nodes.

This is nice because it's simple, and right-clicking a day works properly. However, it's a bit ugly/unintuitive, messy, and unclear. It's especially messy because days are really two different rows, one for events and one for day/week numbers.

Instead, use JS to highlight day cells. You can still right-click by clicking the actual day number, which seems like a reasonable compromise.

Test Plan: {F1738941}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11326

Differential Revision: https://secure.phabricator.com/D16334
This commit is contained in:
epriestley 2016-07-27 06:44:42 -07:00
parent cd8eccde8a
commit aee9d88c17
6 changed files with 172 additions and 56 deletions

View file

@ -117,8 +117,8 @@ return array(
'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983', 'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983',
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'f15bb6d6', 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'f15bb6d6',
'rsrc/css/phui/calendar/phui-calendar-list.css' => '5d89cd71', 'rsrc/css/phui/calendar/phui-calendar-list.css' => '5d89cd71',
'rsrc/css/phui/calendar/phui-calendar-month.css' => 'f3bb2030', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '29a5ef75',
'rsrc/css/phui/calendar/phui-calendar.css' => '3354bbd6', 'rsrc/css/phui/calendar/phui-calendar.css' => 'daadaf39',
'rsrc/css/phui/phui-action-list.css' => 'c5eba19d', 'rsrc/css/phui/phui-action-list.css' => 'c5eba19d',
'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
'rsrc/css/phui/phui-badge.css' => '3baef8db', 'rsrc/css/phui/phui-badge.css' => '3baef8db',
@ -364,6 +364,7 @@ return array(
'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' => '4b3c4443', 'rsrc/js/application/calendar/behavior-day-view.js' => '4b3c4443',
'rsrc/js/application/calendar/behavior-event-all-day.js' => '937bb700', 'rsrc/js/application/calendar/behavior-event-all-day.js' => '937bb700',
'rsrc/js/application/calendar/behavior-month-view.js' => 'fe33e256',
'rsrc/js/application/calendar/behavior-recurring-edit.js' => '5f1c4d5f', 'rsrc/js/application/calendar/behavior-recurring-edit.js' => '5f1c4d5f',
'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408', 'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408',
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2', 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2',
@ -590,6 +591,7 @@ return array(
'javelin-behavior-audit-preview' => 'd835b03a', 'javelin-behavior-audit-preview' => 'd835b03a',
'javelin-behavior-badge-view' => '8ff5e24c', 'javelin-behavior-badge-view' => '8ff5e24c',
'javelin-behavior-bulk-job-reload' => 'edf8a145', 'javelin-behavior-bulk-job-reload' => 'edf8a145',
'javelin-behavior-calendar-month-view' => 'fe33e256',
'javelin-behavior-choose-control' => '327a00d1', 'javelin-behavior-choose-control' => '327a00d1',
'javelin-behavior-comment-actions' => '06460e71', 'javelin-behavior-comment-actions' => '06460e71',
'javelin-behavior-config-reorder-fields' => 'b6993408', 'javelin-behavior-config-reorder-fields' => 'b6993408',
@ -825,10 +827,10 @@ return array(
'phui-big-info-view-css' => 'bd903741', 'phui-big-info-view-css' => 'bd903741',
'phui-box-css' => '5c8387cf', 'phui-box-css' => '5c8387cf',
'phui-button-css' => '4a5fbe3d', 'phui-button-css' => '4a5fbe3d',
'phui-calendar-css' => '3354bbd6', 'phui-calendar-css' => 'daadaf39',
'phui-calendar-day-css' => 'f15bb6d6', 'phui-calendar-day-css' => 'f15bb6d6',
'phui-calendar-list-css' => '5d89cd71', 'phui-calendar-list-css' => '5d89cd71',
'phui-calendar-month-css' => 'f3bb2030', 'phui-calendar-month-css' => '29a5ef75',
'phui-chart-css' => '6bf6f78e', 'phui-chart-css' => '6bf6f78e',
'phui-crumbs-view-css' => 'b4fa5755', 'phui-crumbs-view-css' => 'b4fa5755',
'phui-curtain-view-css' => '7148ae25', 'phui-curtain-view-css' => '7148ae25',

View file

@ -32,7 +32,11 @@ final class PHUICalendarListView extends AphrontTagView {
protected function getTagAttributes() { protected function getTagAttributes() {
require_celerity_resource('phui-calendar-css'); require_celerity_resource('phui-calendar-css');
require_celerity_resource('phui-calendar-list-css'); require_celerity_resource('phui-calendar-list-css');
return array('class' => 'phui-calendar-event-list');
return array(
'sigil' => 'calendar-event-list',
'class' => 'phui-calendar-event-list',
);
} }
protected function getTagContent() { protected function getTagContent() {

View file

@ -53,6 +53,8 @@ final class PHUICalendarMonthView extends AphrontView {
public function render() { public function render() {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
Javelin::initBehavior('calendar-month-view');
$events = msort($this->events, 'getEpochStart'); $events = msort($this->events, 'getEpochStart');
$days = $this->getDatesInMonth(); $days = $this->getDatesInMonth();
@ -111,32 +113,50 @@ final class PHUICalendarMonthView extends AphrontView {
$day->format('m').'/'. $day->format('m').'/'.
$day->format('d').'/'; $day->format('d').'/';
$cell_lists[] = array( $day_id = $day->format('Ymd');
$cell_lists[$day_id] = array(
'dayID' => $day_id,
'list' => $list, 'list' => $list,
'date' => $day, 'date' => $day,
'uri' => $uri, 'dayURI' => $uri,
'count' => count($all_day_events) + count($list_events), 'count' => count($all_day_events) + count($list_events),
'class' => $class, 'class' => $class,
); );
} }
$rows = array(); $rows = array();
$cell_lists_by_week = array_chunk($cell_lists, 7); $cell_lists_by_week = array_chunk($cell_lists, 7, true);
foreach ($cell_lists_by_week as $week_of_cell_lists) { foreach ($cell_lists_by_week as $week_of_cell_lists) {
$cells = array(); $cells = array();
$max_count = $this->getMaxDailyEventsForWeek($week_of_cell_lists); $action_map = array();
foreach ($week_of_cell_lists as $day_id => $cell_list) {
$cells[] = $this->getEventListCell($cell_list);
foreach ($week_of_cell_lists as $cell_list) { $action_map[$day_id] = array(
$cells[] = $this->getEventListCell($cell_list, $max_count); 'dayURI' => $cell_list['dayURI'],
);
} }
$rows[] = phutil_tag('tr', array(), $cells); $rows[] = javelin_tag(
'tr',
array(
'sigil' => 'calendar-week calendar-week-body',
'meta' => array(
'actionMap' => $action_map,
),
),
$cells);
$cells = array(); $cells = array();
foreach ($week_of_cell_lists as $cell_list) { foreach ($week_of_cell_lists as $day_id => $cell_list) {
$cells[] = $this->getDayNumberCell($cell_list); $cells[] = $this->getDayNumberCell($cell_list);
} }
$rows[] = phutil_tag('tr', array(), $cells); $rows[] = javelin_tag(
'tr',
array(
'sigil' => 'calendar-week calendar-week-foot',
),
$cells);
} }
$header = $this->getDayNamesHeader(); $header = $this->getDayNamesHeader();
@ -175,51 +195,53 @@ final class PHUICalendarMonthView extends AphrontView {
return $max_count; return $max_count;
} }
private function getEventListCell($event_list, $max_count = 0) { private function getEventListCell($event_list) {
$list = $event_list['list']; $list = $event_list['list'];
$class = $event_list['class']; $class = $event_list['class'];
$uri = $event_list['uri'];
$count = $event_list['count']; $count = $event_list['count'];
$viewer_is_invited = $list->getIsViewerInvitedOnList(); $viewer_is_invited = $list->getIsViewerInvitedOnList();
$event_count_badge = $this->getEventCountBadge($count, $viewer_is_invited); $event_count_badge = $this->getEventCountBadge($count, $viewer_is_invited);
$cell_day_secret_link = $this->getHiddenDayLink($uri, $max_count, 125);
$cell_data_div = phutil_tag( $cell_content = phutil_tag(
'div', 'div',
array( array(
'class' => 'phui-calendar-month-cell-div', 'class' => 'phui-calendar-month-cell-div',
), ),
array( array(
$cell_day_secret_link,
$event_count_badge, $event_count_badge,
$list, $list,
)); ));
return phutil_tag( $cell_meta = array(
'dayID' => $event_list['dayID'],
);
$classes = array();
$classes[] = 'phui-calendar-month-event-list';
$classes[] = $event_list['class'];
$classes = implode(' ', $classes);
return javelin_tag(
'td', 'td',
array( array(
'class' => 'phui-calendar-month-event-list '.$class, 'class' => $classes,
'meta' => $cell_meta,
), ),
$cell_data_div); $cell_content);
} }
private function getDayNumberCell($event_list) { private function getDayNumberCell($event_list) {
$class = $event_list['class']; $class = $event_list['class'];
$date = $event_list['date']; $date = $event_list['date'];
$cell_day_secret_link = null;
$week_number = null; $week_number = null;
if ($date) { if ($date) {
$uri = $event_list['uri'];
$cell_day_secret_link = $this->getHiddenDayLink($uri, 0, 25);
$cell_day = phutil_tag( $cell_day = phutil_tag(
'a', 'a',
array( array(
'class' => 'phui-calendar-date-number', 'class' => 'phui-calendar-date-number',
'href' => $uri, 'href' => $event_list['dayURI'],
), ),
$date->format('j')); $date->format('j'));
@ -228,7 +250,7 @@ final class PHUICalendarMonthView extends AphrontView {
'a', 'a',
array( array(
'class' => 'phui-calendar-week-number', 'class' => 'phui-calendar-week-number',
'href' => $uri, 'href' => $event_list['dayURI'],
), ),
$date->format('W')); $date->format('W'));
} }
@ -256,14 +278,13 @@ final class PHUICalendarMonthView extends AphrontView {
'class' => 'phui-calendar-month-cell-div', 'class' => 'phui-calendar-month-cell-div',
), ),
array( array(
$cell_day_secret_link,
$week_number, $week_number,
$cell_day, $cell_day,
$today_slot, $today_slot,
)); ));
$classes = array(); $classes = array();
$classes[] = 'phui-calendar-date-number-container'; $classes[] = 'phui-calendar-month-number';
if ($date) { if ($date) {
if ($this->isDateInCurrentWeek($date)) { if ($this->isDateInCurrentWeek($date)) {
@ -277,10 +298,15 @@ final class PHUICalendarMonthView extends AphrontView {
} }
} }
return phutil_tag( $cell_meta = array(
'dayID' => $event_list['dayID'],
);
return javelin_tag(
'td', 'td',
array( array(
'class' => implode(' ', $classes), 'class' => implode(' ', $classes),
'meta' => $cell_meta,
), ),
$cell_div); $cell_div);
} }
@ -320,21 +346,6 @@ final class PHUICalendarMonthView extends AphrontView {
$event_count); $event_count);
} }
private function getHiddenDayLink($uri, $count, $max_height) {
// approximately the height of the tallest cell
$height = 18 * $count + 5;
$height = ($height > $max_height) ? $height : $max_height;
$height_style = 'height: '.$height.'px';
return phutil_tag(
'a',
array(
'class' => 'phui-calendar-month-secret-link',
'style' => $height_style,
'href' => $uri,
),
null);
}
private function getDayNamesHeader() { private function getDayNamesHeader() {
list($week_start, $week_end) = $this->getWeekStartAndEnd(); list($week_start, $week_end) = $this->getWeekStartAndEnd();

View file

@ -50,12 +50,6 @@ table.phui-calendar-view td {
min-height: 32px; min-height: 32px;
} }
a.phui-calendar-month-secret-link {
position: absolute;
left: 0;
right: 0;
}
table.phui-calendar-view tr td:first-child { table.phui-calendar-view tr td:first-child {
border-left-width: 0px; border-left-width: 0px;
} }
@ -113,7 +107,7 @@ table.phui-calendar-view a.phui-calendar-date-number {
width: 12px; width: 12px;
} }
table.phui-calendar-view td.phui-calendar-date-number-container { table.phui-calendar-view td.phui-calendar-month-number {
font-weight: normal; font-weight: normal;
color: {$lightgreytext}; color: {$lightgreytext};
border-width: 0 1px 0 1px; border-width: 0 1px 0 1px;
@ -215,3 +209,13 @@ li.phui-calendar-viewer-invited.all-day {
color: {$lightgreytext}; color: {$lightgreytext};
text-align: right; text-align: right;
} }
td.phui-calendar-month-day,
td.phui-calendar-month-number {
cursor: pointer;
}
.device-desktop td.phui-calendar-month-day.calendar-hover,
.device-desktop td.phui-calendar-month-number.calendar-hover {
background: {$lightblue};
}

View file

@ -2,6 +2,12 @@
* @provides phui-calendar-css * @provides phui-calendar-css
*/ */
.phui-calendar-list {
/* When hovering over a day, this allows the hover color to peek through
the event name, but for event names to mostly remain readable. */
background: rgba(255, 255, 255, 0.75);
}
.phui-calendar-list a { .phui-calendar-list a {
color: {$greytext}; color: {$greytext};
} }

View file

@ -0,0 +1,89 @@
/**
* @provides javelin-behavior-calendar-month-view
*/
JX.behavior('calendar-month-view', function() {
var hover_nodes = [];
function get_info(e) {
var week_body = e.getNode('calendar-week-body');
if (!week_body) {
week_body = e.getNode('calendar-week-foot').previousSibling;
}
var week_foot = week_body.nextSibling;
var day_id = JX.Stratcom.getData(e.getNode('tag:td')).dayID;
var day_body;
var day_foot;
var body_nodes = JX.DOM.scry(week_body, 'td');
var foot_nodes = JX.DOM.scry(week_foot, 'td');
for (var ii = 0; ii < body_nodes.length; ii++) {
if (JX.Stratcom.getData(body_nodes[ii]).dayID == day_id) {
day_body = body_nodes[ii];
day_foot = foot_nodes[ii];
break;
}
}
return {
data: JX.Stratcom.getData(week_body),
dayID: day_id,
nodes: {
week: {
body: week_body,
foot: week_foot
},
day: {
body: day_body,
foot: day_foot
}
}
};
}
function alter_hover(enable) {
for (var ii = 0; ii < hover_nodes.length; ii++) {
JX.DOM.alterClass(hover_nodes[ii], 'calendar-hover', enable);
}
}
JX.enableDispatch(document.body, 'mouseover');
JX.enableDispatch(document.body, 'mouseout');
JX.Stratcom.listen('mouseover', ['calendar-week', 'tag:td'], function(e) {
if (e.getNode('calendar-event-list')) {
alter_hover(false);
hover_nodes = [];
return;
}
var info = get_info(e);
hover_nodes = [
info.nodes.day.body,
info.nodes.day.foot
];
alter_hover(true);
});
JX.Stratcom.listen('mouseout', ['calendar-week', 'tag:td'], function() {
alter_hover(false);
});
JX.Stratcom.listen('click', ['calendar-week', 'tag:td'], function(e) {
if (!e.isNormalClick()) {
return;
}
// If this is a click in the event list or on a link, ignore it. This
// allows users to follow links to events and select text.
if (e.getNode('calendar-event-list') || e.getNode('tag:a')) {
return;
}
var info = get_info(e);
JX.$U(info.data.actionMap[info.dayID].dayURI).go();
});
});