From 340a293870c53e196dbe91ebc9aebbfdcbafbbe4 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sun, 16 Feb 2014 13:15:37 -0800 Subject: [PATCH] Fix an async display issue for tokenizer/typeahead results Summary: Ref T4420. After the changes to the tokenizer, I sometimes do this: - Type something like "diff" into a project typeahead. - Select "differential". - A fraction of a second later, the typeahead pops back open. This is because I selected the result from a partial query (like "diff" running against the "di" results) and then the full results of the "diff" query came back to the browser. Instead, when showing results, require that the current state match the state that the results are for: don't show "dog" results if the tokenizer now reads "cat", for whatever reason. Test Plan: Added a 1s delay to results, typed "a", then typed "m" and selected a result in less than a second. Prior to the patch, the tokenizer would pop back open with "am" results afterward. Now, it doesn't. Reviewers: btrahan, chad Reviewed By: chad CC: aran Maniphest Tasks: T4420 Differential Revision: https://secure.phabricator.com/D8250 --- resources/celerity/map.php | 54 +++++++++---------- .../lib/control/typeahead/Typeahead.js | 22 +++++++- .../source/TypeaheadCompositeSource.js | 4 +- .../typeahead/source/TypeaheadSource.js | 2 +- 4 files changed, 50 insertions(+), 32 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 96e5790f4a..17b8e93a78 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -14,7 +14,7 @@ return array( 'differential.pkg.js' => '322ea941', 'diffusion.pkg.css' => '3783278d', 'diffusion.pkg.js' => '7b51e80a', - 'javelin.pkg.js' => 'c7ef4e11', + 'javelin.pkg.js' => '133881a7', 'maniphest.pkg.css' => 'f1887d71', 'maniphest.pkg.js' => '1e8f11af', 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', @@ -208,12 +208,12 @@ return array( 'rsrc/externals/javelin/lib/__tests__/behavior.js' => 'c1d75ee6', 'rsrc/externals/javelin/lib/behavior.js' => '8a3ed18b', 'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => '1c1a6cdf', - 'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => 'd99e27f7', + 'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => 'caab854b', 'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => '5f850b5c', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => 'dbd9cd11', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '0136cec1', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '7383383f', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => 'e9b95df3', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '5e18d309', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '62e18640', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => 'c2b8bf64', 'rsrc/externals/raphael/g.raphael.js' => '40dde778', 'rsrc/externals/raphael/g.raphael.line.js' => '40da039e', @@ -642,12 +642,12 @@ return array( 'javelin-resource' => '356de121', 'javelin-stratcom' => 'c293f7b9', 'javelin-tokenizer' => '1c1a6cdf', - 'javelin-typeahead' => 'd99e27f7', - 'javelin-typeahead-composite-source' => 'dbd9cd11', + 'javelin-typeahead' => 'caab854b', + 'javelin-typeahead-composite-source' => '0136cec1', 'javelin-typeahead-normalizer' => '5f850b5c', 'javelin-typeahead-ondemand-source' => '7383383f', 'javelin-typeahead-preloaded-source' => 'e9b95df3', - 'javelin-typeahead-source' => '5e18d309', + 'javelin-typeahead-source' => '62e18640', 'javelin-typeahead-static-source' => 'c2b8bf64', 'javelin-uri' => 'd9a9b862', 'javelin-util' => '7501647b', @@ -799,6 +799,12 @@ return array( ), 'requires' => array( + '0136cec1' => + array( + 0 => 'javelin-install', + 1 => 'javelin-typeahead-source', + 2 => 'javelin-util', + ), '029a133d' => array( 0 => 'aphront-dialog-view-css', @@ -1163,13 +1169,6 @@ return array( 3 => 'javelin-stratcom', 4 => 'javelin-vector', ), - '5e18d309' => - array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-dom', - 3 => 'javelin-typeahead-normalizer', - ), '5f004630' => array( 0 => 'javelin-behavior', @@ -1191,6 +1190,13 @@ return array( 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), + '62e18640' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-dom', + 3 => 'javelin-typeahead-normalizer', + ), '63f9ad59' => array( 0 => 'javelin-install', @@ -1677,6 +1683,13 @@ return array( 0 => 'javelin-install', 1 => 'javelin-util', ), + 'caab854b' => + array( + 0 => 'javelin-install', + 1 => 'javelin-dom', + 2 => 'javelin-vector', + 3 => 'javelin-util', + ), 'cd9e7094' => array( 0 => 'javelin-behavior', @@ -1760,13 +1773,6 @@ return array( 7 => 'phabricator-dropdown-menu', 8 => 'phabricator-menu-item', ), - 'd99e27f7' => - array( - 0 => 'javelin-install', - 1 => 'javelin-dom', - 2 => 'javelin-vector', - 3 => 'javelin-util', - ), 'd9a9b862' => array( 0 => 'javelin-install', @@ -1785,12 +1791,6 @@ return array( 0 => 'javelin-behavior', 1 => 'javelin-dom', ), - 'dbd9cd11' => - array( - 0 => 'javelin-install', - 1 => 'javelin-typeahead-source', - 2 => 'javelin-util', - ), 'dd7e8ef5' => array( 0 => 'javelin-behavior', diff --git a/webroot/rsrc/externals/javelin/lib/control/typeahead/Typeahead.js b/webroot/rsrc/externals/javelin/lib/control/typeahead/Typeahead.js index edadb10dbd..98a3adc7db 100644 --- a/webroot/rsrc/externals/javelin/lib/control/typeahead/Typeahead.js +++ b/webroot/rsrc/externals/javelin/lib/control/typeahead/Typeahead.js @@ -230,10 +230,28 @@ JX.install('Typeahead', { * in response to events from the datasource you have configured. * * @task control - * @param list List of #### tags to show as suggestions/results. + * @param list List of #### tags to show as suggestions/results. + * @param string The query this result list corresponds to. * @return void */ - showResults : function(results) { + showResults : function(results, value) { + if (value != this._value) { + // This result list is for an old query, and no longer represents + // the input state of the typeahead. + + // For example, the user may have typed "dog", and then they delete + // their query and type "cat", and then the "dog" results arrive from + // the source. + + // Another case is that the user made a selection in a tokenizer, + // and then results returned. However, the typeahead is now empty, and + // we don't want to pop it back open. + + // In all cases, just throw these results away. They are no longer + // relevant. + return; + } + var obj = {show: results}; var e = this.invoke('show', obj); diff --git a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js index d2d2afc3cc..950d6876c7 100644 --- a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js +++ b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js @@ -50,9 +50,9 @@ JX.install('TypeaheadCompositeSource', { } }, - childResultsReady : function(nodes) { + childResultsReady : function(nodes, value) { this.results = this.mergeResults(this.results || [], nodes); - this.invoke('resultsready', this.results); + this.invoke('resultsready', this.results, value); }, childComplete : function() { diff --git a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js index 254d6b90f1..5947ffef88 100644 --- a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js +++ b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js @@ -292,7 +292,7 @@ JX.install('TypeaheadSource', { this.filterAndSortHits(value, hits); var nodes = this.renderNodes(value, hits); - this.invoke('resultsready', nodes); + this.invoke('resultsready', nodes, value); if (!partial) { this.invoke('complete'); }