@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 recaptime-dev/main 207 lines 4.6 kB view raw
1<?php 2 3final class PHUIListView extends AphrontTagView { 4 5 const NAVBAR_LIST = 'phui-list-navbar'; 6 const NAVBAR_VERTICAL = 'phui-list-navbar-vertical'; 7 const SIDENAV_LIST = 'phui-list-sidenav'; 8 const TABBAR_LIST = 'phui-list-tabbar'; 9 10 private $items = array(); 11 private $type; 12 13 protected function canAppendChild() { 14 return false; 15 } 16 17 public function newLabel($name, $key = null) { 18 $item = id(new PHUIListItemView()) 19 ->setType(PHUIListItemView::TYPE_LABEL) 20 ->setName($name); 21 22 if ($key !== null) { 23 $item->setKey($key); 24 } 25 26 $this->addMenuItem($item); 27 28 return $item; 29 } 30 31 public function newLink($name, $href, $key = null) { 32 $item = id(new PHUIListItemView()) 33 ->setType(PHUIListItemView::TYPE_LINK) 34 ->setName($name) 35 ->setHref($href); 36 37 if ($key !== null) { 38 $item->setKey($key); 39 } 40 41 $this->addMenuItem($item); 42 43 return $item; 44 } 45 46 public function newButton($name, $href) { 47 $item = id(new PHUIListItemView()) 48 ->setType(PHUIListItemView::TYPE_BUTTON) 49 ->setName($name) 50 ->setHref($href); 51 52 $this->addMenuItem($item); 53 54 return $item; 55 } 56 57 public function addMenuItem(PHUIListItemView $item) { 58 return $this->addMenuItemAfter(null, $item); 59 } 60 61 public function addMenuItemAfter($key, PHUIListItemView $item) { 62 if ($key === null) { 63 $this->items[] = $item; 64 return $this; 65 } 66 67 if (!$this->getItem($key)) { 68 throw new Exception(pht("No such key '%s' to add menu item after!", 69 $key)); 70 } 71 72 $result = array(); 73 foreach ($this->items as $other) { 74 $result[] = $other; 75 if ($other->getKey() == $key) { 76 $result[] = $item; 77 } 78 } 79 80 $this->items = $result; 81 return $this; 82 } 83 84 public function addMenuItemBefore($key, PHUIListItemView $item) { 85 if ($key === null) { 86 array_unshift($this->items, $item); 87 return $this; 88 } 89 90 $this->requireKey($key); 91 92 $result = array(); 93 foreach ($this->items as $other) { 94 if ($other->getKey() == $key) { 95 $result[] = $item; 96 } 97 $result[] = $other; 98 } 99 100 $this->items = $result; 101 return $this; 102 } 103 104 public function addMenuItemToLabel($key, PHUIListItemView $item) { 105 $this->requireKey($key); 106 107 $other = $this->getItem($key); 108 if ($other->getType() != PHUIListItemView::TYPE_LABEL) { 109 throw new Exception(pht("Menu item '%s' is not a label!", $key)); 110 } 111 112 $seen = false; 113 $after = null; 114 foreach ($this->items as $other) { 115 if (!$seen) { 116 if ($other->getKey() == $key) { 117 $seen = true; 118 } 119 } else { 120 if ($other->getType() == PHUIListItemView::TYPE_LABEL) { 121 break; 122 } 123 } 124 $after = $other->getKey(); 125 } 126 127 return $this->addMenuItemAfter($after, $item); 128 } 129 130 private function requireKey($key) { 131 if (!$this->getItem($key)) { 132 throw new Exception(pht("No menu item with key '%s' exists!", $key)); 133 } 134 } 135 136 public function getItem($key) { 137 $key = (string)$key; 138 139 // NOTE: We could optimize this, but need to update any map when items have 140 // their keys change. Since that's moderately complex, wait for a profile 141 // or use case. 142 143 foreach ($this->items as $item) { 144 if ($item->getKey() == $key) { 145 return $item; 146 } 147 } 148 149 return null; 150 } 151 152 public function getItems() { 153 return $this->items; 154 } 155 156 public function willRender() { 157 $key_map = array(); 158 foreach ($this->items as $item) { 159 $key = $item->getKey(); 160 if ($key !== null) { 161 if (isset($key_map[$key])) { 162 throw new Exception( 163 pht("Menu contains duplicate items with key '%s'!", $key)); 164 } 165 $key_map[$key] = $item; 166 } 167 } 168 } 169 170 protected function getTagName() { 171 return 'ul'; 172 } 173 174 public function setType($type) { 175 $this->type = $type; 176 return $this; 177 } 178 179 protected function getTagAttributes() { 180 require_celerity_resource('phui-list-view-css'); 181 $classes = array(); 182 $classes[] = 'phui-list-view'; 183 if ($this->type) { 184 switch ($this->type) { 185 case self::NAVBAR_LIST: 186 $classes[] = 'phui-list-navbar'; 187 $classes[] = 'phui-list-navbar-horizontal'; 188 break; 189 case self::NAVBAR_VERTICAL: 190 $classes[] = 'phui-list-navbar'; 191 $classes[] = 'phui-list-navbar-vertical'; 192 break; 193 default: 194 $classes[] = $this->type; 195 break; 196 } 197 } 198 199 return array( 200 'class' => implode(' ', $classes), 201 ); 202 } 203 204 protected function getTagContent() { 205 return $this->items; 206 } 207}