@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 257 lines 6.7 kB view raw
1<?php 2 3final class PhabricatorMainMenuSearchView extends AphrontView { 4 5 const DEFAULT_APPLICATION_ICON = 'fa-dot-circle-o'; 6 7 private $id; 8 private $application; 9 10 public function setApplication(PhabricatorApplication $application) { 11 $this->application = $application; 12 return $this; 13 } 14 15 public function getApplication() { 16 return $this->application; 17 } 18 19 public function getID() { 20 if (!$this->id) { 21 $this->id = celerity_generate_unique_node_id(); 22 } 23 return $this->id; 24 } 25 26 public function render() { 27 $viewer = $this->getViewer(); 28 29 $target_id = celerity_generate_unique_node_id(); 30 $search_id = $this->getID(); 31 $button_id = celerity_generate_unique_node_id(); 32 $selector_id = celerity_generate_unique_node_id(); 33 $application_id = celerity_generate_unique_node_id(); 34 35 $input = phutil_tag( 36 'input', 37 array( 38 'type' => 'text', 39 'name' => 'query', 40 'id' => $search_id, 41 'autocomplete' => 'off', 42 'autocorrect' => 'off', 43 'autocapitalize' => 'off', 44 'spellcheck' => 'false', 45 'aria-label' => pht('Search'), 46 )); 47 48 $target = javelin_tag( 49 'div', 50 array( 51 'id' => $target_id, 52 'class' => 'phabricator-main-menu-search-target', 53 ), 54 ''); 55 56 $search_datasource = new PhabricatorSearchDatasource(); 57 $scope_key = PhabricatorSearchScopeSetting::SETTINGKEY; 58 59 Javelin::initBehavior( 60 'phabricator-search-typeahead', 61 array( 62 'id' => $target_id, 63 'input' => $search_id, 64 'button' => $button_id, 65 'selectorID' => $selector_id, 66 'applicationID' => $application_id, 67 'defaultApplicationIcon' => self::DEFAULT_APPLICATION_ICON, 68 'appScope' => PhabricatorSearchController::SCOPE_CURRENT_APPLICATION, 69 'src' => $search_datasource->getDatasourceURI(), 70 'limit' => 10, 71 'placeholder' => pht('Search'), 72 'scopeUpdateURI' => '/settings/adjust/?key='.$scope_key, 73 )); 74 75 $primary_input = phutil_tag( 76 'input', 77 array( 78 'type' => 'hidden', 79 'name' => 'search:primary', 80 'value' => 'true', 81 )); 82 83 $search_text = javelin_tag( 84 'span', 85 array( 86 'aural' => true, 87 ), 88 pht('Search')); 89 90 $selector = $this->buildModeSelector($selector_id, $application_id); 91 92 $form = phabricator_form( 93 $viewer, 94 array( 95 'action' => '/search/', 96 'method' => 'POST', 97 ), 98 phutil_tag( 99 'div', 100 array( 101 'class' => 'phabricator-main-menu-search-container', 102 ), 103 array( 104 $input, 105 phutil_tag( 106 'button', 107 array( 108 'id' => $button_id, 109 'class' => 'phui-icon-view phui-font-fa fa-search', 110 ), 111 $search_text), 112 $selector, 113 $primary_input, 114 $target, 115 ))); 116 117 return $form; 118 } 119 120 public static function getGlobalSearchScopeItems( 121 PhabricatorUser $viewer, 122 ?PhabricatorApplication $application = null, 123 $global_only = false) { 124 125 $items = array(); 126 $items[] = array( 127 'name' => pht('Global Search'), 128 ); 129 130 $items[] = array( 131 'icon' => 'fa-globe', 132 'name' => pht('All Items'), 133 'value' => 'all', 134 ); 135 136 if ($application && $application->getApplicationSearchDocumentTypes()) { 137 $application_icon = $application->getIcon(); 138 $application_name = $application->getName(); 139 if (!$application_icon) { 140 $application_icon = self::DEFAULT_APPLICATION_ICON; 141 } 142 $items[] = array( 143 'icon' => $application_icon, 144 'name' => pht('In %s Only', $application_name), 145 'value' => PhabricatorSearchController::SCOPE_CURRENT_APPLICATION, 146 ); 147 } 148 149 $items[] = array( 150 'name' => pht('Saved Global Queries'), 151 ); 152 153 154 $engine = id(new PhabricatorSearchApplicationSearchEngine()) 155 ->setViewer($viewer); 156 $engine_queries = $engine->loadEnabledNamedQueries(); 157 foreach ($engine_queries as $query) { 158 $query_key = $query->getQueryKey(); 159 if ($query_key == 'all') { 160 // Skip the builtin "All" query since it's redundant with the default 161 // setting. 162 continue; 163 } 164 165 // In the global "Settings" panel, we don't want to offer personal 166 // queries the viewer may have saved. 167 if ($global_only) { 168 if (!$query->isGlobal()) { 169 continue; 170 } 171 } 172 173 $query_name = $query->getQueryName(); 174 175 $items[] = array( 176 'icon' => 'fa-certificate', 177 'name' => $query_name, 178 'value' => $query_key, 179 ); 180 } 181 182 $items[] = array( 183 'name' => pht('Documentation'), 184 ); 185 186 $items[] = array( 187 'icon' => 'fa-book', 188 'name' => pht('User Guide: Search'), 189 'href' => PhabricatorEnv::getDoclink('Search User Guide'), 190 ); 191 192 return $items; 193 } 194 195 private function buildModeSelector($selector_id, $application_id) { 196 $viewer = $this->getViewer(); 197 198 $items = self::getGlobalSearchScopeItems($viewer, $this->getApplication()); 199 200 $scope_key = PhabricatorSearchScopeSetting::SETTINGKEY; 201 $current_value = $viewer->getUserSetting($scope_key); 202 203 $current_icon = 'fa-globe'; 204 foreach ($items as $item) { 205 if (idx($item, 'value') == $current_value) { 206 $current_icon = $item['icon']; 207 break; 208 } 209 } 210 211 $application = $this->getApplication(); 212 213 $application_value = null; 214 if ($application) { 215 $application_value = get_class($application); 216 } 217 218 $selector = id(new PHUIButtonView()) 219 ->setID($selector_id) 220 ->addClass('phabricator-main-menu-search-dropdown') 221 ->addSigil('global-search-dropdown') 222 ->setMetadata( 223 array( 224 'items' => $items, 225 'icon' => $current_icon, 226 'value' => $current_value, 227 )) 228 ->setIcon( 229 id(new PHUIIconView()) 230 ->addSigil('global-search-dropdown-icon') 231 ->setIcon($current_icon)) 232 ->setAuralLabel(pht('Configure Global Search')) 233 ->setDropdown(true); 234 235 $input = javelin_tag( 236 'input', 237 array( 238 'type' => 'hidden', 239 'sigil' => 'global-search-dropdown-input', 240 'name' => 'search:scope', 241 'value' => $current_value, 242 )); 243 244 $application_input = javelin_tag( 245 'input', 246 array( 247 'type' => 'hidden', 248 'id' => $application_id, 249 'sigil' => 'global-search-dropdown-app', 250 'name' => 'search:application', 251 'value' => $application_value, 252 )); 253 254 return array($selector, $input, $application_input); 255 } 256 257}