Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15394379
D15039.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D15039.id.diff
View Options
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' => '3a97c8b9',
- 'core.pkg.js' => '5813273d',
+ 'core.pkg.js' => '573e6664',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '2de124c9',
'differential.pkg.js' => 'f83532f8',
@@ -249,9 +249,9 @@
'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => '70baed2f',
'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => 'e6e25838',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd',
- 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '8b3fd187',
+ 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '013ffff9',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0',
- 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '2818f5ce',
+ 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '1bc11c4a',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa',
'rsrc/externals/raphael/g.raphael.js' => '40dde778',
'rsrc/externals/raphael/g.raphael.line.js' => '40da039e',
@@ -507,7 +507,7 @@
'rsrc/js/phui/behavior-phui-object-box-tabs.js' => '2bfa2836',
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
- 'rsrc/js/phuix/PHUIXAutocomplete.js' => '5582787f',
+ 'rsrc/js/phuix/PHUIXAutocomplete.js' => '0abdd4a8',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
'rsrc/js/phuix/PHUIXFormControl.js' => '8fba1997',
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
@@ -709,9 +709,9 @@
'javelin-typeahead' => '70baed2f',
'javelin-typeahead-composite-source' => '503e17fd',
'javelin-typeahead-normalizer' => 'e6e25838',
- 'javelin-typeahead-ondemand-source' => '8b3fd187',
+ 'javelin-typeahead-ondemand-source' => '013ffff9',
'javelin-typeahead-preloaded-source' => '54f314a0',
- 'javelin-typeahead-source' => '2818f5ce',
+ 'javelin-typeahead-source' => '1bc11c4a',
'javelin-typeahead-static-source' => '6c0e62fa',
'javelin-uri' => 'c989ade3',
'javelin-util' => '93cc50d6',
@@ -836,7 +836,7 @@
'phui-workpanel-view-css' => 'adec7699',
'phuix-action-list-view' => 'b5c256b8',
'phuix-action-view' => '8cf6d262',
- 'phuix-autocomplete' => '5582787f',
+ 'phuix-autocomplete' => '0abdd4a8',
'phuix-dropdown-menu' => 'bd4c8dca',
'phuix-form-control-view' => '8fba1997',
'phuix-icon-view' => 'bff6884b',
@@ -863,6 +863,12 @@
'unhandled-exception-css' => '4c96257a',
),
'requires' => array(
+ '013ffff9' => array(
+ 'javelin-install',
+ 'javelin-util',
+ 'javelin-request',
+ 'javelin-typeahead-source',
+ ),
'01774ab2' => array(
'javelin-dom',
'javelin-util',
@@ -911,6 +917,12 @@
'javelin-dom',
'javelin-router',
),
+ '0abdd4a8' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ 'phuix-icon-view',
+ 'phabricator-prefab',
+ ),
'0b7a4f6e' => array(
'javelin-behavior',
'javelin-typeahead-ondemand-source',
@@ -950,6 +962,12 @@
'javelin-util',
'phabricator-keyboard-shortcut-manager',
),
+ '1bc11c4a' => array(
+ 'javelin-install',
+ 'javelin-util',
+ 'javelin-dom',
+ 'javelin-typeahead-normalizer',
+ ),
'1d298e3a' => array(
'javelin-install',
'javelin-util',
@@ -1009,12 +1027,6 @@
'phabricator-drag-and-drop-file-upload',
'phabricator-draggable-list',
),
- '2818f5ce' => array(
- 'javelin-install',
- 'javelin-util',
- 'javelin-dom',
- 'javelin-typeahead-normalizer',
- ),
'2926fff2' => array(
'javelin-behavior',
'javelin-dom',
@@ -1198,12 +1210,6 @@
'javelin-request',
'javelin-typeahead-source',
),
- '5582787f' => array(
- 'javelin-install',
- 'javelin-dom',
- 'phuix-icon-view',
- 'phabricator-prefab',
- ),
'558829c2' => array(
'javelin-stratcom',
'javelin-behavior',
@@ -1489,12 +1495,6 @@
'javelin-stratcom',
'javelin-vector',
),
- '8b3fd187' => array(
- 'javelin-install',
- 'javelin-util',
- 'javelin-request',
- 'javelin-typeahead-source',
- ),
'8bdb2835' => array(
'phui-fontkit-css',
),
diff --git a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js
--- a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js
+++ b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js
@@ -38,7 +38,7 @@
lastChange : null,
haveData : null,
- didChange : function(raw_value) {
+ didChange : function(raw_value, force) {
this.lastChange = JX.now();
var value = this.normalize(raw_value);
@@ -59,10 +59,19 @@
}
this.waitForResults();
- setTimeout(
- JX.bind(this, this.sendRequest, this.lastChange, value, raw_value),
- this.getQueryDelay()
- );
+
+ var send_request = JX.bind(
+ this,
+ this.sendRequest,
+ this.lastChange,
+ value,
+ raw_value);
+
+ if (force) {
+ send_request();
+ } else {
+ setTimeout(send_request, this.getQueryDelay());
+ }
}
},
diff --git a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js
--- a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js
+++ b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js
@@ -289,7 +289,7 @@
this.filterAndSortHits(value, hits);
var nodes = this.renderNodes(value, hits);
- this.invoke('resultsready', nodes, value);
+ this.invoke('resultsready', nodes, value, partial);
if (!partial) {
this.invoke('complete');
}
diff --git a/webroot/rsrc/js/phuix/PHUIXAutocomplete.js b/webroot/rsrc/js/phuix/PHUIXAutocomplete.js
--- a/webroot/rsrc/js/phuix/PHUIXAutocomplete.js
+++ b/webroot/rsrc/js/phuix/PHUIXAutocomplete.js
@@ -12,6 +12,7 @@
this._map = {};
this._datasources = {};
this._listNodes = [];
+ this._resultMap = {};
},
members: {
@@ -35,6 +36,7 @@
_x: null,
_y: null,
_visible: false,
+ _resultMap: null,
setArea: function(area) {
this._area = area;
@@ -205,7 +207,30 @@
}
},
- _onresults: function(code, nodes, value) {
+ _onresults: function(code, nodes, value, partial) {
+ // Even if these results are out of date, we still want to fill in the
+ // result map so we can terminate things later.
+ if (!partial) {
+ if (!this._resultMap[code]) {
+ this._resultMap[code] = {};
+ }
+
+ var hits = [];
+ for (var ii = 0; ii < nodes.length; ii++) {
+ var result = this._datasources[code].getResult(nodes[ii].rel);
+ if (!result) {
+ hits = null;
+ break;
+ }
+
+ hits.push(result.autocomplete);
+ }
+
+ if (hits !== null) {
+ this._resultMap[code][value] = hits;
+ }
+ }
+
if (code !== this._active) {
return;
}
@@ -214,6 +239,13 @@
return;
}
+ if (this._isTerminatedString(value)) {
+ if (this._hasUnrefinableResults(value)) {
+ this._deactivate();
+ return;
+ }
+ }
+
var list = this._getListNode();
JX.DOM.setContent(list, nodes);
@@ -291,6 +323,59 @@
return ['#', '@', ',', '!', '?'];
},
+ _getTerminators: function() {
+ return [' ', ':', ',', '.', '!', '?'];
+ },
+
+ _isTerminatedString: function(string) {
+ var terminators = this._getTerminators();
+ for (var ii = 0; ii < terminators.length; ii++) {
+ var term = terminators[ii];
+ if (string.substring(string.length - term.length) == term) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ _hasUnrefinableResults: function(query) {
+ if (!this._resultMap[this._active]) {
+ return false;
+ }
+
+ var map = this._resultMap[this._active];
+
+ for (var ii = 1; ii < query.length; ii++) {
+ var prefix = query.substring(0, ii);
+ if (map.hasOwnProperty(prefix)) {
+ var results = map[prefix];
+
+ // If any prefix of the query has no results, the full query also
+ // has no results so we can not refine them.
+ if (!results.length) {
+ return true;
+ }
+
+ // If there is exactly one match and the it is a prefix of the query,
+ // we can safely assume the user just typed out the right result
+ // from memory and doesn't need to refine it.
+ if (results.length == 1) {
+ // Strip the first character off, like a "#" or "@".
+ var result = results[0].substring(1);
+
+ if (query.length >= result.length) {
+ if (query.substring(0, result.length) === result) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ },
+
_trim: function(str) {
var suffixes = this._getSuffixes();
for (var ii = 0; ii < suffixes.length; ii++) {
@@ -416,7 +501,32 @@
}
}
- this._datasource.didChange(trim);
+ // If the input is terminated by a space or another word-terminating
+ // punctuation mark, we're going to deactivate if the results can not
+ // be refined by addding more words.
+
+ // The idea is that if you type "@alan ab", you're allowed to keep
+ // editing "ab" until you type a space, period, or other terminator,
+ // since you might not be sure how to spell someone's last name or the
+ // second word of a project.
+
+ // Once you do terminate a word, if the words you have have entered match
+ // nothing or match only one exact match, we can safely deactivate and
+ // assume you're just typing text because further words could never
+ // refine the result set.
+
+ var force;
+ if (this._isTerminatedString(text)) {
+ if (this._hasUnrefinableResults(text)) {
+ this._deactivate();
+ return;
+ }
+ force = true;
+ } else {
+ force = false;
+ }
+
+ this._datasource.didChange(trim, force);
this._x = x;
this._y = y;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 16, 11:50 PM (2 d, 7 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7224673
Default Alt Text
D15039.id.diff (10 KB)
Attached To
Mode
D15039: Hide the autocompleter intelligently when you ignore it and keep typing
Attached
Detach File
Event Timeline
Log In to Comment