diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -8,7 +8,7 @@ return array( 'names' => array( 'core.pkg.css' => 'c2c68e64', - 'core.pkg.js' => '80884e9b', + 'core.pkg.js' => '0095fb2c', 'darkconsole.pkg.js' => 'df001cab', 'differential.pkg.css' => '4a93db37', 'differential.pkg.js' => '7528cfc9', @@ -450,7 +450,7 @@ 'rsrc/js/core/KeyboardShortcutManager.js' => 'ad7a69ca', 'rsrc/js/core/MultirowRowManager.js' => '41e47dea', 'rsrc/js/core/Notification.js' => '0c6946e7', - 'rsrc/js/core/Prefab.js' => '41ed7994', + 'rsrc/js/core/Prefab.js' => 'c11bac49', 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 'rsrc/js/core/TextAreaUtils.js' => 'b3ec3cfc', 'rsrc/js/core/ToolTip.js' => '3915d490', @@ -485,7 +485,7 @@ 'rsrc/js/core/behavior-remarkup-preview.js' => 'f7379f45', 'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e', 'rsrc/js/core/behavior-reveal-content.js' => '60821bc7', - 'rsrc/js/core/behavior-search-typeahead.js' => '5a376f34', + 'rsrc/js/core/behavior-search-typeahead.js' => 'd712ac5f', 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', 'rsrc/js/core/behavior-toggle-class.js' => 'e566f52c', 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', @@ -629,7 +629,7 @@ 'javelin-behavior-phabricator-oncopy' => '2926fff2', 'javelin-behavior-phabricator-remarkup-assist' => 'e32d14ab', 'javelin-behavior-phabricator-reveal-content' => '60821bc7', - 'javelin-behavior-phabricator-search-typeahead' => '5a376f34', + 'javelin-behavior-phabricator-search-typeahead' => 'd712ac5f', 'javelin-behavior-phabricator-show-all-transactions' => '7c273581', 'javelin-behavior-phabricator-tooltips' => '3ee3408b', 'javelin-behavior-phabricator-transaction-comment-form' => '9f7309fb', @@ -737,7 +737,7 @@ 'phabricator-notification-menu-css' => '8ae4a008', 'phabricator-object-selector-css' => '029a133d', 'phabricator-phtize' => 'd254d646', - 'phabricator-prefab' => '41ed7994', + 'phabricator-prefab' => 'c11bac49', 'phabricator-profile-css' => 'b459416e', 'phabricator-remarkup-css' => 'ad4c0676', 'phabricator-search-results-css' => 'f240504c', @@ -1126,18 +1126,6 @@ 2 => 'javelin-dom', 3 => 'javelin-util', ), - '41ed7994' => array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-dom', - 3 => 'javelin-typeahead', - 4 => 'javelin-tokenizer', - 5 => 'javelin-typeahead-preloaded-source', - 6 => 'javelin-typeahead-ondemand-source', - 7 => 'javelin-dom', - 8 => 'javelin-stratcom', - 9 => 'javelin-util', - ), '44168bad' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', @@ -1232,15 +1220,6 @@ 2 => 'javelin-vector', 3 => 'javelin-dom', ), - '5a376f34' => array( - 0 => 'javelin-behavior', - 1 => 'javelin-typeahead-ondemand-source', - 2 => 'javelin-typeahead', - 3 => 'javelin-dom', - 4 => 'javelin-uri', - 5 => 'javelin-util', - 6 => 'javelin-stratcom', - ), '5bc2cb21' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', @@ -1690,6 +1669,18 @@ 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), + 'c11bac49' => array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-dom', + 3 => 'javelin-typeahead', + 4 => 'javelin-tokenizer', + 5 => 'javelin-typeahead-preloaded-source', + 6 => 'javelin-typeahead-ondemand-source', + 7 => 'javelin-dom', + 8 => 'javelin-stratcom', + 9 => 'javelin-util', + ), 'c4569c05' => array( 0 => 'javelin-magical-init', 1 => 'javelin-install', @@ -1764,6 +1755,16 @@ 2 => 'javelin-stratcom', 3 => 'javelin-dom', ), + 'd712ac5f' => array( + 0 => 'javelin-behavior', + 1 => 'javelin-typeahead-ondemand-source', + 2 => 'javelin-typeahead', + 3 => 'javelin-dom', + 4 => 'javelin-uri', + 5 => 'javelin-util', + 6 => 'javelin-stratcom', + 7 => 'phabricator-prefab', + ), 'd75709e6' => array( 0 => 'javelin-behavior', 1 => 'javelin-workflow', diff --git a/webroot/rsrc/js/core/Prefab.js b/webroot/rsrc/js/core/Prefab.js --- a/webroot/rsrc/js/core/Prefab.js +++ b/webroot/rsrc/js/core/Prefab.js @@ -31,6 +31,7 @@ return select; }, + /** * Build a Phabricator tokenizer out of a configuration with application * sorting, datasource and placeholder rules. @@ -142,82 +143,9 @@ }); }; - var render_icon = function(icon) { - return JX.$N( - 'span', - {className: 'phui-icon-view phui-font-fa ' + icon}); - }; - datasource.setSortHandler(JX.bind(datasource, sort_handler)); - - // Don't show any closed objects until the query is specific enough that - // it only selects closed objects. Specifically, if the result list had - // any open objects, remove all the closed objects from the list. - var filter_handler = function(value, list) { - // Look for any open result. - var has_open = false; - var ii; - for (ii = 0; ii < list.length; ii++) { - if (!list[ii].closed) { - has_open = true; - break; - } - } - - if (!has_open) { - // Everything is closed, so just use it as-is. - return list; - } - - // Otherwise, only display the open results. - var results = []; - for (ii = 0; ii < list.length; ii++) { - if (!list[ii].closed) { - results.push(list[ii]); - } - } - - return results; - }; - - datasource.setFilterHandler(filter_handler); - - datasource.setTransformer( - function(object) { - var closed = object[9]; - var closed_ui; - if (closed) { - closed_ui = JX.$N( - 'div', - {className: 'tokenizer-closed'}, - closed); - } - - var icon = object[8]; - var icon_ui; - if (icon) { - icon_ui = render_icon(icon); - } - - var display = JX.$N( - 'div', - {className: 'tokenizer-result'}, - [icon_ui, object[0], closed_ui]); - if (closed) { - JX.DOM.alterClass(display, 'tokenizer-result-closed', true); - } - - return { - name: object[0], - display: display, - uri: object[1], - id: object[2], - priority: object[3], - priorityType: object[7], - icon: icon, - closed: closed - }; - }); + datasource.setFilterHandler(JX.Prefab.filterClosedResults); + datasource.setTransformer(JX.Prefab.transformDatasourceResults); var typeahead = new JX.Typeahead( root, @@ -238,7 +166,7 @@ return value; } - icon = render_icon(icon); + icon = JX.Prefab._renderIcon(icon); // TODO: Maybe we should render these closed tags in grey? Figure out // how we're going to use color. @@ -263,7 +191,89 @@ return { tokenizer: tokenizer }; + }, + + /** + * Filter callback for tokenizers and typeaheads which filters out closed + * or disabled objects unless they are the only options. + */ + filterClosedResults: function(value, list) { + // Look for any open result. + var has_open = false; + var ii; + for (ii = 0; ii < list.length; ii++) { + if (!list[ii].closed) { + has_open = true; + break; + } + } + + if (!has_open) { + // Everything is closed, so just use it as-is. + return list; + } + + // Otherwise, only display the open results. + var results = []; + for (ii = 0; ii < list.length; ii++) { + if (!list[ii].closed) { + results.push(list[ii]); + } + } + + return results; + }, + + /** + * Transform results from a wire format into a usable format in a standard + * way. + */ + transformDatasourceResults: function(fields) { + var closed = fields[9]; + var closed_ui; + if (closed) { + closed_ui = JX.$N( + 'div', + {className: 'tokenizer-closed'}, + closed); + } + + var icon = fields[8]; + var icon_ui; + if (icon) { + icon_ui = JX.Prefab._renderIcon(icon); + } + + var display = JX.$N( + 'div', + {className: 'tokenizer-result'}, + [icon_ui, fields[4] || fields[0], closed_ui]); + if (closed) { + JX.DOM.alterClass(display, 'tokenizer-result-closed', true); + } + + return { + name: fields[0], + displayName: fields[4] || fields[0], + display: display, + uri: fields[1], + id: fields[2], + priority: fields[3], + priorityType: fields[7], + imageURI: fields[6], + icon: icon, + closed: closed, + type: fields[5], + sprite: fields[10] + }; + }, + + _renderIcon: function(icon) { + return JX.$N( + 'span', + {className: 'phui-icon-view phui-font-fa ' + icon}); } + } }); diff --git a/webroot/rsrc/js/core/behavior-search-typeahead.js b/webroot/rsrc/js/core/behavior-search-typeahead.js --- a/webroot/rsrc/js/core/behavior-search-typeahead.js +++ b/webroot/rsrc/js/core/behavior-search-typeahead.js @@ -7,6 +7,7 @@ * javelin-uri * javelin-util * javelin-stratcom + * phabricator-prefab */ JX.behavior('phabricator-search-typeahead', function(config) { @@ -14,31 +15,28 @@ var datasource = new JX.TypeaheadOnDemandSource(config.src); function transform(object) { + object = JX.Prefab.transformDatasourceResults(object); + var attr = { className: 'phabricator-main-search-typeahead-result' }; - if (object[6]) { - attr.style = {backgroundImage: 'url('+object[6]+')'}; + if (object.imageURI) { + attr.style = {backgroundImage: 'url('+object.imageURI+')'}; } var render = JX.$N( 'span', attr, [ - JX.$N('span', {className: object[10]}), - JX.$N('span', {className: 'result-name'}, object[4] || object[0]), - JX.$N('span', {className: 'result-type'}, object[5]) + JX.$N('span', {className: object.sprite}), + JX.$N('span', {className: 'result-name'}, object.displayName), + JX.$N('span', {className: 'result-type'}, object.type) ]); - return { - name: object[0], - display: render, - uri: object[1], - id: object[2], - priority: object[3], - type: object[7] - }; + object.display = render; + + return object; } datasource.setTransformer(transform); @@ -76,8 +74,8 @@ } list.sort(function(u, v) { - var u_type = type_priority[u.type] || 999; - var v_type = type_priority[v.type] || 999; + var u_type = type_priority[u.priorityType] || 999; + var v_type = type_priority[v.priorityType] || 999; if (u_type != v_type) { return u_type - v_type; @@ -120,6 +118,7 @@ }; datasource.setSortHandler(JX.bind(datasource, sort_handler)); + datasource.setFilterHandler(JX.Prefab.filterClosedResults); datasource.setMaximumResultCount(config.limit); var typeahead = new JX.Typeahead(JX.$(config.id), JX.$(config.input));