@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
at upstream/main 476 lines 11 kB view raw
1<?php 2 3final class PHUIListItemView extends AphrontTagView { 4 5 const TYPE_LINK = 'type-link'; 6 const TYPE_SPACER = 'type-spacer'; 7 const TYPE_LABEL = 'type-label'; 8 const TYPE_BUTTON = 'type-button'; 9 const TYPE_CUSTOM = 'type-custom'; 10 const TYPE_DIVIDER = 'type-divider'; 11 const TYPE_ICON = 'type-icon'; 12 13 const STATUS_WARN = 'phui-list-item-warn'; 14 const STATUS_FAIL = 'phui-list-item-fail'; 15 16 private $name; 17 private $href; 18 private $type = self::TYPE_LINK; 19 private $isExternal; 20 private $key; 21 private $icon; 22 private $selected; 23 private $disabled; 24 private $renderNameAsTooltip; 25 private $statusColor; 26 private $order; 27 private $aural; 28 private $profileImage; 29 private $indented; 30 private $hideInApplicationMenu; 31 private $icons = array(); 32 private $openInNewWindow = false; 33 private $tooltip; 34 private $actionIcon; 35 private $actionIconHref; 36 private $count; 37 private $rel; 38 private $dropdownMenu; 39 private $keyCommand; 40 private $ariaLabel; 41 42 public function setOpenInNewWindow($open_in_new_window) { 43 $this->openInNewWindow = $open_in_new_window; 44 return $this; 45 } 46 47 public function getOpenInNewWindow() { 48 return $this->openInNewWindow; 49 } 50 51 public function setRel($rel) { 52 $this->rel = $rel; 53 return $this; 54 } 55 56 public function getRel() { 57 return $this->rel; 58 } 59 60 public function setHideInApplicationMenu($hide) { 61 $this->hideInApplicationMenu = $hide; 62 return $this; 63 } 64 65 public function getHideInApplicationMenu() { 66 return $this->hideInApplicationMenu; 67 } 68 69 public function setDropdownMenu(PhabricatorActionListView $actions) { 70 71 $this->dropdownMenu = $actions; 72 73 // TODO: "PHUICrumbsView" currently creates a bad copy of list items 74 // by reading some of their properties. To survive this copy step, we 75 // need to mutate "$this" immediately or the "Create Object" dropdown 76 // when multiple create forms exist breaks. 77 78 if (!$this->actionIcon) { 79 Javelin::initBehavior('phui-dropdown-menu'); 80 $this->addSigil('phui-dropdown-menu'); 81 $this->setMetadata($actions->getDropdownMenuMetadata()); 82 } 83 84 return $this; 85 } 86 87 public function setAural($aural) { 88 $this->aural = $aural; 89 return $this; 90 } 91 92 public function getAural() { 93 return $this->aural; 94 } 95 96 public function setOrder($order) { 97 $this->order = $order; 98 return $this; 99 } 100 101 public function getOrder() { 102 return $this->order; 103 } 104 105 public function setRenderNameAsTooltip($render_name_as_tooltip) { 106 $this->renderNameAsTooltip = $render_name_as_tooltip; 107 return $this; 108 } 109 110 public function getRenderNameAsTooltip() { 111 return $this->renderNameAsTooltip; 112 } 113 114 public function setSelected($selected) { 115 $this->selected = $selected; 116 return $this; 117 } 118 119 public function getSelected() { 120 return $this->selected; 121 } 122 123 public function setIcon($icon) { 124 $this->icon = $icon; 125 return $this; 126 } 127 128 public function setProfileImage($image) { 129 $this->profileImage = $image; 130 return $this; 131 } 132 133 public function getIcon() { 134 return $this->icon; 135 } 136 137 public function setCount($count) { 138 $this->count = $count; 139 return $this; 140 } 141 142 public function setIndented($indented) { 143 $this->indented = $indented; 144 return $this; 145 } 146 147 public function getIndented() { 148 return $this->indented; 149 } 150 151 public function setKey($key) { 152 $this->key = (string)$key; 153 return $this; 154 } 155 156 public function getKey() { 157 return $this->key; 158 } 159 160 public function setType($type) { 161 $this->type = $type; 162 return $this; 163 } 164 165 public function getType() { 166 return $this->type; 167 } 168 169 public function setHref($href) { 170 $this->href = $href; 171 return $this; 172 } 173 174 public function getHref() { 175 return $this->href; 176 } 177 178 public function setName($name) { 179 $this->name = $name; 180 return $this; 181 } 182 183 public function getName() { 184 return $this->name; 185 } 186 187 public function setActionIcon($icon, $href) { 188 $this->actionIcon = $icon; 189 $this->actionIconHref = $href; 190 return $this; 191 } 192 193 public function setIsExternal($is_external) { 194 $this->isExternal = $is_external; 195 return $this; 196 } 197 198 public function getIsExternal() { 199 return $this->isExternal; 200 } 201 202 public function setStatusColor($color) { 203 $this->statusColor = $color; 204 return $this; 205 } 206 207 public function addIcon($icon) { 208 $this->icons[] = $icon; 209 return $this; 210 } 211 212 public function getIcons() { 213 return $this->icons; 214 } 215 216 public function setTooltip($tooltip) { 217 $this->tooltip = $tooltip; 218 return $this; 219 } 220 221 /** 222 * Explicitly set an aria-label attribute for accessibility. Only to be used 223 * when no other means of differentiation are already available. 224 * @param string $aria_label aria-label text to add to a list item 225 */ 226 public function setAriaLabel($aria_label) { 227 $this->ariaLabel = $aria_label; 228 return $this; 229 } 230 231 protected function getTagName() { 232 return 'li'; 233 } 234 235 public function setKeyCommand($key_command) { 236 $this->keyCommand = $key_command; 237 return $this; 238 } 239 240 public function getKeyCommand() { 241 return $this->keyCommand; 242 } 243 244 protected function getTagAttributes() { 245 $classes = array(); 246 $classes[] = 'phui-list-item-view'; 247 $classes[] = 'phui-list-item-'.$this->type; 248 249 if ($this->icon || $this->profileImage) { 250 $classes[] = 'phui-list-item-has-icon'; 251 } 252 253 if ($this->selected) { 254 $classes[] = 'phui-list-item-selected'; 255 } 256 257 if ($this->disabled) { 258 $classes[] = 'phui-list-item-disabled'; 259 } 260 261 if ($this->statusColor) { 262 $classes[] = $this->statusColor; 263 } 264 265 if ($this->actionIcon) { 266 $classes[] = 'phui-list-item-has-action-icon'; 267 } 268 269 $sigil = null; 270 $metadata = null; 271 if ($this->dropdownMenu) { 272 $classes[] = 'dropdown'; 273 if (!$this->actionIcon) { 274 $classes[] = 'dropdown-with-caret'; 275 Javelin::initBehavior('phui-dropdown-menu'); 276 $sigil = 'phui-dropdown-menu'; 277 $metadata = $this->dropdownMenu->getDropdownMenuMetadata(); 278 } 279 } 280 281 return array( 282 'class' => $classes, 283 'sigil' => $sigil, 284 'meta' => $metadata, 285 ); 286 } 287 288 public function setDisabled($disabled) { 289 $this->disabled = $disabled; 290 return $this; 291 } 292 293 public function getDisabled() { 294 return $this->disabled; 295 } 296 297 protected function getTagContent() { 298 $name = null; 299 $icon = null; 300 $meta = null; 301 $sigil = array(); 302 303 if ($this->name) { 304 if ($this->getRenderNameAsTooltip()) { 305 Javelin::initBehavior('phabricator-tooltips'); 306 $sigil[] = 'has-tooltip'; 307 $meta = array( 308 'tip' => $this->name, 309 'align' => 'E', 310 ); 311 } else { 312 if ($this->tooltip) { 313 Javelin::initBehavior('phabricator-tooltips'); 314 $sigil[] = 'has-tooltip'; 315 $meta = array( 316 'tip' => $this->tooltip, 317 'align' => 'E', 318 'size' => 300, 319 ); 320 } 321 322 $external = null; 323 if ($this->isExternal) { 324 $external = " \xE2\x86\x97"; 325 } 326 327 // If this element has an aural representation, make any name visual 328 // only. This is primarily dealing with the links in the main menu like 329 // "Profile" and "Logout". If we don't hide the name, the mobile 330 // version of these elements will have two redundant names. 331 332 $classes = array(); 333 $classes[] = 'phui-list-item-name'; 334 if ($this->aural !== null) { 335 $classes[] = 'visual-only'; 336 } 337 338 $name = phutil_tag( 339 'span', 340 array( 341 'class' => implode(' ', $classes), 342 ), 343 array( 344 $this->name, 345 $external, 346 )); 347 } 348 } 349 350 $aural = null; 351 if ($this->aural !== null) { 352 $aural = javelin_tag( 353 'span', 354 array( 355 'aural' => true, 356 ), 357 $this->aural); 358 } 359 360 if ($this->icon) { 361 $icon_name = $this->icon; 362 if ($this->getDisabled()) { 363 $icon_name .= ' grey'; 364 } 365 366 $icon = id(new PHUIIconView()) 367 ->addClass('phui-list-item-icon') 368 ->setIcon($icon_name); 369 } 370 371 if ($this->profileImage) { 372 $icon = id(new PHUIIconView()) 373 ->setHeadSize(PHUIIconView::HEAD_SMALL) 374 ->addClass('phui-list-item-icon') 375 ->setImage($this->profileImage); 376 } 377 378 $classes = array(); 379 if ($this->href) { 380 $classes[] = 'phui-list-item-href'; 381 } 382 383 if ($this->indented) { 384 $classes[] = 'phui-list-item-indented'; 385 } 386 387 $action_link = $this->newActionIconView(); 388 389 $count = null; 390 if ($this->count) { 391 $count = phutil_tag( 392 'span', 393 array( 394 'class' => 'phui-list-item-count', 395 ), 396 $this->count); 397 } 398 399 $caret = null; 400 if ($this->dropdownMenu && !$this->actionIcon) { 401 $caret = id(new PHUIIconView()) 402 ->setIcon('fa-caret-down'); 403 } 404 405 $icons = $this->getIcons(); 406 407 $key_command = null; 408 if ($this->keyCommand) { 409 $key_command = phutil_tag( 410 'span', 411 array( 412 'class' => 'keyboard-shortcut-key', 413 ), 414 $this->keyCommand); 415 $sigil[] = 'has-key-command'; 416 $meta['keyCommand'] = $this->keyCommand; 417 } 418 419 $list_item = javelin_tag( 420 $this->href ? 'a' : 'div', 421 array( 422 'href' => $this->href, 423 'class' => implode(' ', $classes), 424 'meta' => $meta, 425 'sigil' => implode(' ', $sigil), 426 'aria-label' => $this->ariaLabel, 427 'target' => $this->getOpenInNewWindow() ? '_blank' : null, 428 'rel' => $this->rel, 429 ), 430 array( 431 $aural, 432 $icon, 433 $icons, 434 $this->renderChildren(), 435 $name, 436 $count, 437 $key_command, 438 $caret, 439 )); 440 441 return array($list_item, $action_link); 442 } 443 444 private function newActionIconView() { 445 $action_icon = $this->actionIcon; 446 $action_href = $this->actionIconHref; 447 448 if ($action_icon === null) { 449 return null; 450 } 451 452 $icon_view = id(new PHUIIconView()) 453 ->setIcon($action_icon) 454 ->addClass('phui-list-item-action-icon'); 455 456 if ($this->dropdownMenu) { 457 Javelin::initBehavior('phui-dropdown-menu'); 458 $sigil = 'phui-dropdown-menu'; 459 $metadata = $this->dropdownMenu->getDropdownMenuMetadata(); 460 } else { 461 $sigil = null; 462 $metadata = null; 463 } 464 465 return javelin_tag( 466 'a', 467 array( 468 'href' => $action_href, 469 'class' => 'phui-list-item-action-href', 470 'sigil' => $sigil, 471 'meta' => $metadata, 472 ), 473 $icon_view); 474 } 475 476}