@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.

at recaptime-dev/main 270 lines 6.9 kB view raw
1<?php 2 3final class PhabricatorProfileMenuItemViewList 4 extends Phobject { 5 6 private $engine; 7 private $views = array(); 8 private $selectedView; 9 10 public function setProfileMenuEngine(PhabricatorProfileMenuEngine $engine) { 11 $this->engine = $engine; 12 return $this; 13 } 14 15 public function getProfileMenuEngine() { 16 return $this->engine; 17 } 18 19 public function addItemView(PhabricatorProfileMenuItemView $view) { 20 $this->views[] = $view; 21 return $this; 22 } 23 24 public function getItemViews() { 25 return $this->views; 26 } 27 28 public function setSelectedView(PhabricatorProfileMenuItemView $view) { 29 $found = false; 30 foreach ($this->getItemViews() as $item_view) { 31 if ($view === $item_view) { 32 $found = true; 33 break; 34 } 35 } 36 37 if (!$found) { 38 throw new Exception( 39 pht( 40 'Provided view is not one of the views in the list: you can only '. 41 'select a view which appears in the list.')); 42 } 43 44 $this->selectedView = $view; 45 46 return $this; 47 } 48 49 public function setSelectedViewWithItemIdentifier($identifier) { 50 $views = $this->getViewsWithItemIdentifier($identifier); 51 52 if (!$views) { 53 throw new Exception( 54 pht( 55 'No views match identifier "%s"!', 56 $identifier)); 57 } 58 59 return $this->setSelectedView(head($views)); 60 } 61 62 public function getViewsWithItemIdentifier($identifier) { 63 $views = $this->getItemViews(); 64 65 $results = array(); 66 foreach ($views as $view) { 67 $config = $view->getMenuItemConfiguration(); 68 69 if (!$config->matchesIdentifier($identifier)) { 70 continue; 71 } 72 73 $results[] = $view; 74 } 75 76 return $results; 77 } 78 79 public function getDefaultViews() { 80 $engine = $this->getProfileMenuEngine(); 81 $can_pin = $engine->isMenuEnginePinnable(); 82 83 $views = $this->getItemViews(); 84 85 // Remove all the views which were built by an item that can not be the 86 // default item. 87 foreach ($views as $key => $view) { 88 $config = $view->getMenuItemConfiguration(); 89 90 if (!$config->canMakeDefault()) { 91 unset($views[$key]); 92 continue; 93 } 94 } 95 96 // Remove disabled views. 97 foreach ($views as $key => $view) { 98 if ($view->getDisabled()) { 99 unset($views[$key]); 100 } 101 } 102 103 // If this engine supports pinning items and we have candidate views from a 104 // valid pinned item, they are the default views. 105 if ($can_pin) { 106 $pinned = array(); 107 108 foreach ($views as $key => $view) { 109 $config = $view->getMenuItemConfiguration(); 110 111 if ($config->isDefault()) { 112 $pinned[] = $view; 113 continue; 114 } 115 } 116 117 if ($pinned) { 118 return $pinned; 119 } 120 } 121 122 // Return whatever remains that's still valid. 123 return $views; 124 } 125 126 public function newNavigationView() { 127 $engine = $this->getProfileMenuEngine(); 128 129 $base_uri = $engine->getItemURI(''); 130 $base_uri = new PhutilURI($base_uri); 131 132 $navigation = id(new AphrontSideNavFilterView()) 133 ->setIsProfileMenu(true) 134 ->setBaseURI($base_uri); 135 136 $views = $this->getItemViews(); 137 $selected_item = null; 138 $item_key = 0; 139 $items = array(); 140 foreach ($views as $view) { 141 $list_item = $view->newListItemView(); 142 143 // Assign unique keys to the list items. These keys are purely internal. 144 $list_item->setKey(sprintf('item(%d)', $item_key++)); 145 146 if ($this->selectedView) { 147 if ($this->selectedView === $view) { 148 $selected_item = $list_item; 149 } 150 } 151 152 $navigation->addMenuItem($list_item); 153 $items[] = $list_item; 154 } 155 156 if (!$views) { 157 // If the navigation menu has no items, add an empty label item to 158 // force it to render something. 159 $empty_item = id(new PHUIListItemView()) 160 ->setType(PHUIListItemView::TYPE_LABEL); 161 $navigation->addMenuItem($empty_item); 162 } 163 164 $highlight_key = $this->getHighlightedItemKey( 165 $items, 166 $selected_item); 167 $navigation->selectFilter($highlight_key); 168 169 return $navigation; 170 } 171 172 /** 173 * @param array<PHUIListItemView> $items 174 * @param ?PHUIListItemView $selected_item 175 */ 176 private function getHighlightedItemKey( 177 array $items, 178 ?PHUIListItemView $selected_item = null) { 179 180 assert_instances_of($items, PHUIListItemView::class); 181 182 $default_key = null; 183 if ($selected_item) { 184 $default_key = $selected_item->getKey(); 185 } 186 187 $engine = $this->getProfileMenuEngine(); 188 $controller = $engine->getController(); 189 190 // In some rare cases, when like building the "Favorites" menu on a 191 // 404 page, we may not have a controller. Just accept whatever default 192 // behavior we'd otherwise end up with. 193 if (!$controller) { 194 return $default_key; 195 } 196 197 $request = $controller->getRequest(); 198 199 // See T12949. If one of the menu items is a link to the same URI that 200 // the page was accessed with, we want to highlight that item. For example, 201 // this allows you to add links to a menu that apply filters to a 202 // workboard. 203 204 $matches = array(); 205 foreach ($items as $item) { 206 $href = $item->getHref(); 207 if ($this->isMatchForRequestURI($request, $href)) { 208 $matches[] = $item; 209 } 210 } 211 212 foreach ($matches as $match) { 213 if ($match->getKey() === $default_key) { 214 return $default_key; 215 } 216 } 217 218 if ($matches) { 219 return head($matches)->getKey(); 220 } 221 222 return $default_key; 223 } 224 225 private function isMatchForRequestURI(AphrontRequest $request, $item_uri) { 226 $request_uri = $request->getAbsoluteRequestURI(); 227 $item_uri = new PhutilURI($item_uri); 228 229 // If the request URI and item URI don't have matching paths, they 230 // do not match. 231 if ($request_uri->getPath() !== $item_uri->getPath()) { 232 return false; 233 } 234 235 // If the request URI and item URI don't have matching parameters, they 236 // also do not match. We're specifically trying to let "?filter=X" work 237 // on Workboards, among other use cases, so this is important. 238 $request_params = $request_uri->getQueryParamsAsPairList(); 239 $item_params = $item_uri->getQueryParamsAsPairList(); 240 if ($request_params !== $item_params) { 241 return false; 242 } 243 244 // If the paths and parameters match, the item domain must be: empty; or 245 // match the request domain; or match the production domain. 246 247 $request_domain = $request_uri->getDomain(); 248 249 $production_uri = PhabricatorEnv::getProductionURI('/'); 250 $production_domain = id(new PhutilURI($production_uri)) 251 ->getDomain(); 252 253 $allowed_domains = array( 254 '', 255 $request_domain, 256 $production_domain, 257 ); 258 $allowed_domains = array_fuse($allowed_domains); 259 260 $item_domain = $item_uri->getDomain(); 261 $item_domain = (string)$item_domain; 262 263 if (isset($allowed_domains[$item_domain])) { 264 return true; 265 } 266 267 return false; 268 } 269 270}