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

Share more code between tokenizers and global typeahead

Summary:
Ref T4420. Fixes T5306. Currently, the main menubar search has a lot of redundant/unshared code.

Move some common functions into `JX.Prefab.whatever()` and call them from the main search.

The major change here is that we apply the same "only show closed/disabled/archived objects if there are no matching open objects" logic, fixing T5306.

Test Plan:
- Used normal typeaheads.
- Used global search.
- Searched for a prefix shared by open and archived projects, didn't see the archived ones until the open ones were exhausted.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5306, T4420

Differential Revision: https://secure.phabricator.com/D9899

+127 -117
+27 -26
resources/celerity/map.php
··· 8 8 return array( 9 9 'names' => array( 10 10 'core.pkg.css' => 'c2c68e64', 11 - 'core.pkg.js' => '80884e9b', 11 + 'core.pkg.js' => '0095fb2c', 12 12 'darkconsole.pkg.js' => 'df001cab', 13 13 'differential.pkg.css' => '4a93db37', 14 14 'differential.pkg.js' => '7528cfc9', ··· 450 450 'rsrc/js/core/KeyboardShortcutManager.js' => 'ad7a69ca', 451 451 'rsrc/js/core/MultirowRowManager.js' => '41e47dea', 452 452 'rsrc/js/core/Notification.js' => '0c6946e7', 453 - 'rsrc/js/core/Prefab.js' => '41ed7994', 453 + 'rsrc/js/core/Prefab.js' => 'c11bac49', 454 454 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 455 455 'rsrc/js/core/TextAreaUtils.js' => 'b3ec3cfc', 456 456 'rsrc/js/core/ToolTip.js' => '3915d490', ··· 485 485 'rsrc/js/core/behavior-remarkup-preview.js' => 'f7379f45', 486 486 'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e', 487 487 'rsrc/js/core/behavior-reveal-content.js' => '60821bc7', 488 - 'rsrc/js/core/behavior-search-typeahead.js' => '5a376f34', 488 + 'rsrc/js/core/behavior-search-typeahead.js' => 'd712ac5f', 489 489 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', 490 490 'rsrc/js/core/behavior-toggle-class.js' => 'e566f52c', 491 491 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', ··· 629 629 'javelin-behavior-phabricator-oncopy' => '2926fff2', 630 630 'javelin-behavior-phabricator-remarkup-assist' => 'e32d14ab', 631 631 'javelin-behavior-phabricator-reveal-content' => '60821bc7', 632 - 'javelin-behavior-phabricator-search-typeahead' => '5a376f34', 632 + 'javelin-behavior-phabricator-search-typeahead' => 'd712ac5f', 633 633 'javelin-behavior-phabricator-show-all-transactions' => '7c273581', 634 634 'javelin-behavior-phabricator-tooltips' => '3ee3408b', 635 635 'javelin-behavior-phabricator-transaction-comment-form' => '9f7309fb', ··· 737 737 'phabricator-notification-menu-css' => '8ae4a008', 738 738 'phabricator-object-selector-css' => '029a133d', 739 739 'phabricator-phtize' => 'd254d646', 740 - 'phabricator-prefab' => '41ed7994', 740 + 'phabricator-prefab' => 'c11bac49', 741 741 'phabricator-profile-css' => 'b459416e', 742 742 'phabricator-remarkup-css' => 'ad4c0676', 743 743 'phabricator-search-results-css' => 'f240504c', ··· 1126 1126 2 => 'javelin-dom', 1127 1127 3 => 'javelin-util', 1128 1128 ), 1129 - '41ed7994' => array( 1130 - 0 => 'javelin-install', 1131 - 1 => 'javelin-util', 1132 - 2 => 'javelin-dom', 1133 - 3 => 'javelin-typeahead', 1134 - 4 => 'javelin-tokenizer', 1135 - 5 => 'javelin-typeahead-preloaded-source', 1136 - 6 => 'javelin-typeahead-ondemand-source', 1137 - 7 => 'javelin-dom', 1138 - 8 => 'javelin-stratcom', 1139 - 9 => 'javelin-util', 1140 - ), 1141 1129 '44168bad' => array( 1142 1130 0 => 'javelin-behavior', 1143 1131 1 => 'javelin-dom', ··· 1232 1220 2 => 'javelin-vector', 1233 1221 3 => 'javelin-dom', 1234 1222 ), 1235 - '5a376f34' => array( 1236 - 0 => 'javelin-behavior', 1237 - 1 => 'javelin-typeahead-ondemand-source', 1238 - 2 => 'javelin-typeahead', 1239 - 3 => 'javelin-dom', 1240 - 4 => 'javelin-uri', 1241 - 5 => 'javelin-util', 1242 - 6 => 'javelin-stratcom', 1243 - ), 1244 1223 '5bc2cb21' => array( 1245 1224 0 => 'javelin-behavior', 1246 1225 1 => 'javelin-stratcom', ··· 1690 1669 2 => 'javelin-util', 1691 1670 3 => 'phabricator-shaped-request', 1692 1671 ), 1672 + 'c11bac49' => array( 1673 + 0 => 'javelin-install', 1674 + 1 => 'javelin-util', 1675 + 2 => 'javelin-dom', 1676 + 3 => 'javelin-typeahead', 1677 + 4 => 'javelin-tokenizer', 1678 + 5 => 'javelin-typeahead-preloaded-source', 1679 + 6 => 'javelin-typeahead-ondemand-source', 1680 + 7 => 'javelin-dom', 1681 + 8 => 'javelin-stratcom', 1682 + 9 => 'javelin-util', 1683 + ), 1693 1684 'c4569c05' => array( 1694 1685 0 => 'javelin-magical-init', 1695 1686 1 => 'javelin-install', ··· 1763 1754 1 => 'javelin-request', 1764 1755 2 => 'javelin-stratcom', 1765 1756 3 => 'javelin-dom', 1757 + ), 1758 + 'd712ac5f' => array( 1759 + 0 => 'javelin-behavior', 1760 + 1 => 'javelin-typeahead-ondemand-source', 1761 + 2 => 'javelin-typeahead', 1762 + 3 => 'javelin-dom', 1763 + 4 => 'javelin-uri', 1764 + 5 => 'javelin-util', 1765 + 6 => 'javelin-stratcom', 1766 + 7 => 'phabricator-prefab', 1766 1767 ), 1767 1768 'd75709e6' => array( 1768 1769 0 => 'javelin-behavior',
+86 -76
webroot/rsrc/js/core/Prefab.js
··· 31 31 return select; 32 32 }, 33 33 34 + 34 35 /** 35 36 * Build a Phabricator tokenizer out of a configuration with application 36 37 * sorting, datasource and placeholder rules. ··· 142 143 }); 143 144 }; 144 145 145 - var render_icon = function(icon) { 146 - return JX.$N( 147 - 'span', 148 - {className: 'phui-icon-view phui-font-fa ' + icon}); 149 - }; 150 - 151 146 datasource.setSortHandler(JX.bind(datasource, sort_handler)); 152 - 153 - // Don't show any closed objects until the query is specific enough that 154 - // it only selects closed objects. Specifically, if the result list had 155 - // any open objects, remove all the closed objects from the list. 156 - var filter_handler = function(value, list) { 157 - // Look for any open result. 158 - var has_open = false; 159 - var ii; 160 - for (ii = 0; ii < list.length; ii++) { 161 - if (!list[ii].closed) { 162 - has_open = true; 163 - break; 164 - } 165 - } 166 - 167 - if (!has_open) { 168 - // Everything is closed, so just use it as-is. 169 - return list; 170 - } 171 - 172 - // Otherwise, only display the open results. 173 - var results = []; 174 - for (ii = 0; ii < list.length; ii++) { 175 - if (!list[ii].closed) { 176 - results.push(list[ii]); 177 - } 178 - } 179 - 180 - return results; 181 - }; 182 - 183 - datasource.setFilterHandler(filter_handler); 184 - 185 - datasource.setTransformer( 186 - function(object) { 187 - var closed = object[9]; 188 - var closed_ui; 189 - if (closed) { 190 - closed_ui = JX.$N( 191 - 'div', 192 - {className: 'tokenizer-closed'}, 193 - closed); 194 - } 195 - 196 - var icon = object[8]; 197 - var icon_ui; 198 - if (icon) { 199 - icon_ui = render_icon(icon); 200 - } 201 - 202 - var display = JX.$N( 203 - 'div', 204 - {className: 'tokenizer-result'}, 205 - [icon_ui, object[0], closed_ui]); 206 - if (closed) { 207 - JX.DOM.alterClass(display, 'tokenizer-result-closed', true); 208 - } 209 - 210 - return { 211 - name: object[0], 212 - display: display, 213 - uri: object[1], 214 - id: object[2], 215 - priority: object[3], 216 - priorityType: object[7], 217 - icon: icon, 218 - closed: closed 219 - }; 220 - }); 147 + datasource.setFilterHandler(JX.Prefab.filterClosedResults); 148 + datasource.setTransformer(JX.Prefab.transformDatasourceResults); 221 149 222 150 var typeahead = new JX.Typeahead( 223 151 root, ··· 238 166 return value; 239 167 } 240 168 241 - icon = render_icon(icon); 169 + icon = JX.Prefab._renderIcon(icon); 242 170 243 171 // TODO: Maybe we should render these closed tags in grey? Figure out 244 172 // how we're going to use color. ··· 263 191 return { 264 192 tokenizer: tokenizer 265 193 }; 194 + }, 195 + 196 + /** 197 + * Filter callback for tokenizers and typeaheads which filters out closed 198 + * or disabled objects unless they are the only options. 199 + */ 200 + filterClosedResults: function(value, list) { 201 + // Look for any open result. 202 + var has_open = false; 203 + var ii; 204 + for (ii = 0; ii < list.length; ii++) { 205 + if (!list[ii].closed) { 206 + has_open = true; 207 + break; 208 + } 209 + } 210 + 211 + if (!has_open) { 212 + // Everything is closed, so just use it as-is. 213 + return list; 214 + } 215 + 216 + // Otherwise, only display the open results. 217 + var results = []; 218 + for (ii = 0; ii < list.length; ii++) { 219 + if (!list[ii].closed) { 220 + results.push(list[ii]); 221 + } 222 + } 223 + 224 + return results; 225 + }, 226 + 227 + /** 228 + * Transform results from a wire format into a usable format in a standard 229 + * way. 230 + */ 231 + transformDatasourceResults: function(fields) { 232 + var closed = fields[9]; 233 + var closed_ui; 234 + if (closed) { 235 + closed_ui = JX.$N( 236 + 'div', 237 + {className: 'tokenizer-closed'}, 238 + closed); 239 + } 240 + 241 + var icon = fields[8]; 242 + var icon_ui; 243 + if (icon) { 244 + icon_ui = JX.Prefab._renderIcon(icon); 245 + } 246 + 247 + var display = JX.$N( 248 + 'div', 249 + {className: 'tokenizer-result'}, 250 + [icon_ui, fields[4] || fields[0], closed_ui]); 251 + if (closed) { 252 + JX.DOM.alterClass(display, 'tokenizer-result-closed', true); 253 + } 254 + 255 + return { 256 + name: fields[0], 257 + displayName: fields[4] || fields[0], 258 + display: display, 259 + uri: fields[1], 260 + id: fields[2], 261 + priority: fields[3], 262 + priorityType: fields[7], 263 + imageURI: fields[6], 264 + icon: icon, 265 + closed: closed, 266 + type: fields[5], 267 + sprite: fields[10] 268 + }; 269 + }, 270 + 271 + _renderIcon: function(icon) { 272 + return JX.$N( 273 + 'span', 274 + {className: 'phui-icon-view phui-font-fa ' + icon}); 266 275 } 276 + 267 277 } 268 278 269 279 });
+14 -15
webroot/rsrc/js/core/behavior-search-typeahead.js
··· 7 7 * javelin-uri 8 8 * javelin-util 9 9 * javelin-stratcom 10 + * phabricator-prefab 10 11 */ 11 12 12 13 JX.behavior('phabricator-search-typeahead', function(config) { ··· 14 15 var datasource = new JX.TypeaheadOnDemandSource(config.src); 15 16 16 17 function transform(object) { 18 + object = JX.Prefab.transformDatasourceResults(object); 19 + 17 20 var attr = { 18 21 className: 'phabricator-main-search-typeahead-result' 19 22 }; 20 23 21 - if (object[6]) { 22 - attr.style = {backgroundImage: 'url('+object[6]+')'}; 24 + if (object.imageURI) { 25 + attr.style = {backgroundImage: 'url('+object.imageURI+')'}; 23 26 } 24 27 25 28 var render = JX.$N( 26 29 'span', 27 30 attr, 28 31 [ 29 - JX.$N('span', {className: object[10]}), 30 - JX.$N('span', {className: 'result-name'}, object[4] || object[0]), 31 - JX.$N('span', {className: 'result-type'}, object[5]) 32 + JX.$N('span', {className: object.sprite}), 33 + JX.$N('span', {className: 'result-name'}, object.displayName), 34 + JX.$N('span', {className: 'result-type'}, object.type) 32 35 ]); 33 36 34 - return { 35 - name: object[0], 36 - display: render, 37 - uri: object[1], 38 - id: object[2], 39 - priority: object[3], 40 - type: object[7] 41 - }; 37 + object.display = render; 38 + 39 + return object; 42 40 } 43 41 44 42 datasource.setTransformer(transform); ··· 76 74 } 77 75 78 76 list.sort(function(u, v) { 79 - var u_type = type_priority[u.type] || 999; 80 - var v_type = type_priority[v.type] || 999; 77 + var u_type = type_priority[u.priorityType] || 999; 78 + var v_type = type_priority[v.priorityType] || 999; 81 79 82 80 if (u_type != v_type) { 83 81 return u_type - v_type; ··· 120 118 }; 121 119 122 120 datasource.setSortHandler(JX.bind(datasource, sort_handler)); 121 + datasource.setFilterHandler(JX.Prefab.filterClosedResults); 123 122 datasource.setMaximumResultCount(config.limit); 124 123 125 124 var typeahead = new JX.Typeahead(JX.$(config.id), JX.$(config.input));