@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+172 -56
+6 -4
resources/celerity/map.php
··· 117 117 'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983', 118 118 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'f15bb6d6', 119 119 'rsrc/css/phui/calendar/phui-calendar-list.css' => '5d89cd71', 120 - 'rsrc/css/phui/calendar/phui-calendar-month.css' => 'f3bb2030', 121 - 'rsrc/css/phui/calendar/phui-calendar.css' => '3354bbd6', 120 + 'rsrc/css/phui/calendar/phui-calendar-month.css' => '29a5ef75', 121 + 'rsrc/css/phui/calendar/phui-calendar.css' => 'daadaf39', 122 122 'rsrc/css/phui/phui-action-list.css' => 'c5eba19d', 123 123 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 124 124 'rsrc/css/phui/phui-badge.css' => '3baef8db', ··· 364 364 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 365 365 'rsrc/js/application/calendar/behavior-day-view.js' => '4b3c4443', 366 366 'rsrc/js/application/calendar/behavior-event-all-day.js' => '937bb700', 367 + 'rsrc/js/application/calendar/behavior-month-view.js' => 'fe33e256', 367 368 'rsrc/js/application/calendar/behavior-recurring-edit.js' => '5f1c4d5f', 368 369 'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408', 369 370 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2', ··· 590 591 'javelin-behavior-audit-preview' => 'd835b03a', 591 592 'javelin-behavior-badge-view' => '8ff5e24c', 592 593 'javelin-behavior-bulk-job-reload' => 'edf8a145', 594 + 'javelin-behavior-calendar-month-view' => 'fe33e256', 593 595 'javelin-behavior-choose-control' => '327a00d1', 594 596 'javelin-behavior-comment-actions' => '06460e71', 595 597 'javelin-behavior-config-reorder-fields' => 'b6993408', ··· 825 827 'phui-big-info-view-css' => 'bd903741', 826 828 'phui-box-css' => '5c8387cf', 827 829 'phui-button-css' => '4a5fbe3d', 828 - 'phui-calendar-css' => '3354bbd6', 830 + 'phui-calendar-css' => 'daadaf39', 829 831 'phui-calendar-day-css' => 'f15bb6d6', 830 832 'phui-calendar-list-css' => '5d89cd71', 831 - 'phui-calendar-month-css' => 'f3bb2030', 833 + 'phui-calendar-month-css' => '29a5ef75', 832 834 'phui-chart-css' => '6bf6f78e', 833 835 'phui-crumbs-view-css' => 'b4fa5755', 834 836 'phui-curtain-view-css' => '7148ae25',
+5 -1
src/view/phui/calendar/PHUICalendarListView.php
··· 32 32 protected function getTagAttributes() { 33 33 require_celerity_resource('phui-calendar-css'); 34 34 require_celerity_resource('phui-calendar-list-css'); 35 - return array('class' => 'phui-calendar-event-list'); 35 + 36 + return array( 37 + 'sigil' => 'calendar-event-list', 38 + 'class' => 'phui-calendar-event-list', 39 + ); 36 40 } 37 41 38 42 protected function getTagContent() {
+55 -44
src/view/phui/calendar/PHUICalendarMonthView.php
··· 53 53 public function render() { 54 54 $viewer = $this->getViewer(); 55 55 56 + Javelin::initBehavior('calendar-month-view'); 57 + 56 58 $events = msort($this->events, 'getEpochStart'); 57 59 $days = $this->getDatesInMonth(); 58 60 ··· 111 113 $day->format('m').'/'. 112 114 $day->format('d').'/'; 113 115 114 - $cell_lists[] = array( 116 + $day_id = $day->format('Ymd'); 117 + 118 + $cell_lists[$day_id] = array( 119 + 'dayID' => $day_id, 115 120 'list' => $list, 116 121 'date' => $day, 117 - 'uri' => $uri, 122 + 'dayURI' => $uri, 118 123 'count' => count($all_day_events) + count($list_events), 119 124 'class' => $class, 120 - ); 125 + ); 121 126 } 122 127 123 128 $rows = array(); 124 - $cell_lists_by_week = array_chunk($cell_lists, 7); 125 - 129 + $cell_lists_by_week = array_chunk($cell_lists, 7, true); 126 130 foreach ($cell_lists_by_week as $week_of_cell_lists) { 127 131 $cells = array(); 128 - $max_count = $this->getMaxDailyEventsForWeek($week_of_cell_lists); 132 + $action_map = array(); 133 + foreach ($week_of_cell_lists as $day_id => $cell_list) { 134 + $cells[] = $this->getEventListCell($cell_list); 129 135 130 - foreach ($week_of_cell_lists as $cell_list) { 131 - $cells[] = $this->getEventListCell($cell_list, $max_count); 136 + $action_map[$day_id] = array( 137 + 'dayURI' => $cell_list['dayURI'], 138 + ); 132 139 } 133 - $rows[] = phutil_tag('tr', array(), $cells); 140 + $rows[] = javelin_tag( 141 + 'tr', 142 + array( 143 + 'sigil' => 'calendar-week calendar-week-body', 144 + 'meta' => array( 145 + 'actionMap' => $action_map, 146 + ), 147 + ), 148 + $cells); 134 149 135 150 $cells = array(); 136 - foreach ($week_of_cell_lists as $cell_list) { 151 + foreach ($week_of_cell_lists as $day_id => $cell_list) { 137 152 $cells[] = $this->getDayNumberCell($cell_list); 138 153 } 139 - $rows[] = phutil_tag('tr', array(), $cells); 154 + $rows[] = javelin_tag( 155 + 'tr', 156 + array( 157 + 'sigil' => 'calendar-week calendar-week-foot', 158 + ), 159 + $cells); 140 160 } 141 161 142 162 $header = $this->getDayNamesHeader(); ··· 175 195 return $max_count; 176 196 } 177 197 178 - private function getEventListCell($event_list, $max_count = 0) { 198 + private function getEventListCell($event_list) { 179 199 $list = $event_list['list']; 180 200 $class = $event_list['class']; 181 - $uri = $event_list['uri']; 182 201 $count = $event_list['count']; 183 202 184 203 $viewer_is_invited = $list->getIsViewerInvitedOnList(); 185 - 186 204 $event_count_badge = $this->getEventCountBadge($count, $viewer_is_invited); 187 - $cell_day_secret_link = $this->getHiddenDayLink($uri, $max_count, 125); 188 205 189 - $cell_data_div = phutil_tag( 206 + $cell_content = phutil_tag( 190 207 'div', 191 208 array( 192 209 'class' => 'phui-calendar-month-cell-div', 193 210 ), 194 211 array( 195 - $cell_day_secret_link, 196 212 $event_count_badge, 197 213 $list, 198 214 )); 199 215 200 - return phutil_tag( 216 + $cell_meta = array( 217 + 'dayID' => $event_list['dayID'], 218 + ); 219 + 220 + $classes = array(); 221 + $classes[] = 'phui-calendar-month-event-list'; 222 + $classes[] = $event_list['class']; 223 + $classes = implode(' ', $classes); 224 + 225 + return javelin_tag( 201 226 'td', 202 227 array( 203 - 'class' => 'phui-calendar-month-event-list '.$class, 228 + 'class' => $classes, 229 + 'meta' => $cell_meta, 204 230 ), 205 - $cell_data_div); 231 + $cell_content); 206 232 } 207 233 208 234 private function getDayNumberCell($event_list) { 209 235 $class = $event_list['class']; 210 236 $date = $event_list['date']; 211 - $cell_day_secret_link = null; 212 237 $week_number = null; 213 238 214 239 if ($date) { 215 - $uri = $event_list['uri']; 216 - $cell_day_secret_link = $this->getHiddenDayLink($uri, 0, 25); 217 - 218 240 $cell_day = phutil_tag( 219 241 'a', 220 242 array( 221 243 'class' => 'phui-calendar-date-number', 222 - 'href' => $uri, 244 + 'href' => $event_list['dayURI'], 223 245 ), 224 246 $date->format('j')); 225 247 ··· 228 250 'a', 229 251 array( 230 252 'class' => 'phui-calendar-week-number', 231 - 'href' => $uri, 253 + 'href' => $event_list['dayURI'], 232 254 ), 233 255 $date->format('W')); 234 256 } ··· 256 278 'class' => 'phui-calendar-month-cell-div', 257 279 ), 258 280 array( 259 - $cell_day_secret_link, 260 281 $week_number, 261 282 $cell_day, 262 283 $today_slot, 263 284 )); 264 285 265 286 $classes = array(); 266 - $classes[] = 'phui-calendar-date-number-container'; 287 + $classes[] = 'phui-calendar-month-number'; 267 288 268 289 if ($date) { 269 290 if ($this->isDateInCurrentWeek($date)) { ··· 277 298 } 278 299 } 279 300 280 - return phutil_tag( 301 + $cell_meta = array( 302 + 'dayID' => $event_list['dayID'], 303 + ); 304 + 305 + return javelin_tag( 281 306 'td', 282 307 array( 283 308 'class' => implode(' ', $classes), 309 + 'meta' => $cell_meta, 284 310 ), 285 311 $cell_div); 286 312 } ··· 318 344 'class' => 'phui-calendar-month-event-count', 319 345 ), 320 346 $event_count); 321 - } 322 - 323 - private function getHiddenDayLink($uri, $count, $max_height) { 324 - // approximately the height of the tallest cell 325 - $height = 18 * $count + 5; 326 - $height = ($height > $max_height) ? $height : $max_height; 327 - $height_style = 'height: '.$height.'px'; 328 - return phutil_tag( 329 - 'a', 330 - array( 331 - 'class' => 'phui-calendar-month-secret-link', 332 - 'style' => $height_style, 333 - 'href' => $uri, 334 - ), 335 - null); 336 347 } 337 348 338 349 private function getDayNamesHeader() {
+11 -7
webroot/rsrc/css/phui/calendar/phui-calendar-month.css
··· 50 50 min-height: 32px; 51 51 } 52 52 53 - a.phui-calendar-month-secret-link { 54 - position: absolute; 55 - left: 0; 56 - right: 0; 57 - } 58 - 59 53 table.phui-calendar-view tr td:first-child { 60 54 border-left-width: 0px; 61 55 } ··· 113 107 width: 12px; 114 108 } 115 109 116 - table.phui-calendar-view td.phui-calendar-date-number-container { 110 + table.phui-calendar-view td.phui-calendar-month-number { 117 111 font-weight: normal; 118 112 color: {$lightgreytext}; 119 113 border-width: 0 1px 0 1px; ··· 215 209 color: {$lightgreytext}; 216 210 text-align: right; 217 211 } 212 + 213 + td.phui-calendar-month-day, 214 + td.phui-calendar-month-number { 215 + cursor: pointer; 216 + } 217 + 218 + .device-desktop td.phui-calendar-month-day.calendar-hover, 219 + .device-desktop td.phui-calendar-month-number.calendar-hover { 220 + background: {$lightblue}; 221 + }
+6
webroot/rsrc/css/phui/calendar/phui-calendar.css
··· 2 2 * @provides phui-calendar-css 3 3 */ 4 4 5 + .phui-calendar-list { 6 + /* When hovering over a day, this allows the hover color to peek through 7 + the event name, but for event names to mostly remain readable. */ 8 + background: rgba(255, 255, 255, 0.75); 9 + } 10 + 5 11 .phui-calendar-list a { 6 12 color: {$greytext}; 7 13 }
+89
webroot/rsrc/js/application/calendar/behavior-month-view.js
··· 1 + /** 2 + * @provides javelin-behavior-calendar-month-view 3 + */ 4 + JX.behavior('calendar-month-view', function() { 5 + 6 + var hover_nodes = []; 7 + 8 + function get_info(e) { 9 + var week_body = e.getNode('calendar-week-body'); 10 + if (!week_body) { 11 + week_body = e.getNode('calendar-week-foot').previousSibling; 12 + } 13 + 14 + var week_foot = week_body.nextSibling; 15 + var day_id = JX.Stratcom.getData(e.getNode('tag:td')).dayID; 16 + 17 + var day_body; 18 + var day_foot; 19 + var body_nodes = JX.DOM.scry(week_body, 'td'); 20 + var foot_nodes = JX.DOM.scry(week_foot, 'td'); 21 + for (var ii = 0; ii < body_nodes.length; ii++) { 22 + if (JX.Stratcom.getData(body_nodes[ii]).dayID == day_id) { 23 + day_body = body_nodes[ii]; 24 + day_foot = foot_nodes[ii]; 25 + break; 26 + } 27 + } 28 + 29 + return { 30 + data: JX.Stratcom.getData(week_body), 31 + dayID: day_id, 32 + nodes: { 33 + week: { 34 + body: week_body, 35 + foot: week_foot 36 + }, 37 + day: { 38 + body: day_body, 39 + foot: day_foot 40 + } 41 + } 42 + }; 43 + } 44 + 45 + function alter_hover(enable) { 46 + for (var ii = 0; ii < hover_nodes.length; ii++) { 47 + JX.DOM.alterClass(hover_nodes[ii], 'calendar-hover', enable); 48 + } 49 + } 50 + 51 + JX.enableDispatch(document.body, 'mouseover'); 52 + JX.enableDispatch(document.body, 'mouseout'); 53 + 54 + JX.Stratcom.listen('mouseover', ['calendar-week', 'tag:td'], function(e) { 55 + if (e.getNode('calendar-event-list')) { 56 + alter_hover(false); 57 + hover_nodes = []; 58 + return; 59 + } 60 + 61 + var info = get_info(e); 62 + hover_nodes = [ 63 + info.nodes.day.body, 64 + info.nodes.day.foot 65 + ]; 66 + 67 + alter_hover(true); 68 + }); 69 + 70 + JX.Stratcom.listen('mouseout', ['calendar-week', 'tag:td'], function() { 71 + alter_hover(false); 72 + }); 73 + 74 + JX.Stratcom.listen('click', ['calendar-week', 'tag:td'], function(e) { 75 + if (!e.isNormalClick()) { 76 + return; 77 + } 78 + 79 + // If this is a click in the event list or on a link, ignore it. This 80 + // allows users to follow links to events and select text. 81 + if (e.getNode('calendar-event-list') || e.getNode('tag:a')) { 82 + return; 83 + } 84 + 85 + var info = get_info(e); 86 + JX.$U(info.data.actionMap[info.dayID].dayURI).go(); 87 + }); 88 + 89 + });