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:
parent
cd8eccde8a
commit
aee9d88c17
6 changed files with 172 additions and 56 deletions
|
@ -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',
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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};
|
||||||
|
}
|
||||||
|
|
|
@ -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};
|
||||||
}
|
}
|
||||||
|
|
89
webroot/rsrc/js/application/calendar/behavior-month-view.js
Normal file
89
webroot/rsrc/js/application/calendar/behavior-month-view.js
Normal 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();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in a new issue