diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -528,7 +528,7 @@ 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 'rsrc/js/phuix/PHUIXActionView.js' => '442efd08', - 'rsrc/js/phuix/PHUIXAutocomplete.js' => 'e0731603', + 'rsrc/js/phuix/PHUIXAutocomplete.js' => 'bb19ed2c', 'rsrc/js/phuix/PHUIXButtonView.js' => '8a91e1ac', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '04b2ae03', 'rsrc/js/phuix/PHUIXExample.js' => '68af71ca', @@ -881,7 +881,7 @@ 'phui-workpanel-view-css' => 'a3a63478', 'phuix-action-list-view' => 'b5c256b8', 'phuix-action-view' => '442efd08', - 'phuix-autocomplete' => 'e0731603', + 'phuix-autocomplete' => 'bb19ed2c', 'phuix-button-view' => '8a91e1ac', 'phuix-dropdown-menu' => '04b2ae03', 'phuix-form-control-view' => '16ad6224', @@ -1868,6 +1868,12 @@ 'javelin-uri', 'phabricator-notification', ), + 'bb19ed2c' => array( + 'javelin-install', + 'javelin-dom', + 'phuix-icon-view', + 'phabricator-prefab', + ), 'bcaccd64' => array( 'javelin-behavior', 'javelin-behavior-device', @@ -2033,12 +2039,6 @@ 'javelin-typeahead-ondemand-source', 'javelin-dom', ), - 'e0731603' => array( - 'javelin-install', - 'javelin-dom', - 'phuix-icon-view', - 'phabricator-prefab', - ), 'e1d25dfb' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/applications/phriction/typeahead/PhrictionDocumentDatasource.php b/src/applications/phriction/typeahead/PhrictionDocumentDatasource.php --- a/src/applications/phriction/typeahead/PhrictionDocumentDatasource.php +++ b/src/applications/phriction/typeahead/PhrictionDocumentDatasource.php @@ -68,6 +68,7 @@ $title = $content->getTitle(); $sprite = 'phabricator-search-icon phui-font-fa phui-icon-view fa-book'; + $autocomplete = '[[ '.$slug.' ]]'; $result = id(new PhabricatorTypeaheadResult()) ->setName($title) @@ -77,6 +78,7 @@ ->setDisplayType($slug) ->setPriorityType('wiki') ->setImageSprite($sprite) + ->setAutocomplete($autocomplete) ->setClosed($closed); $results[] = $result; diff --git a/src/view/form/control/PhabricatorRemarkupControl.php b/src/view/form/control/PhabricatorRemarkupControl.php --- a/src/view/form/control/PhabricatorRemarkupControl.php +++ b/src/view/form/control/PhabricatorRemarkupControl.php @@ -72,6 +72,8 @@ 'autocomplete' => 1, )); + $phriction_datasource = new PhrictionDocumentDatasource(); + Javelin::initBehavior( 'phabricator-remarkup-assist', array( @@ -118,6 +120,18 @@ '/', ), ), + 91 => array( // "[" + 'datasourceURI' => $phriction_datasource->getDatasourceURI(), + 'headerIcon' => 'fa-book', + 'headerText' => pht('Find Document:'), + 'hintText' => $phriction_datasource->getPlaceholderText(), + 'cancel' => array( + ':', // Cancel on "http:" and similar. + '|', + ']', + ), + 'prefix' => '^\\[*', + ), ), )); Javelin::initBehavior('phabricator-tooltips', array()); 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 @@ -335,7 +335,9 @@ _getCancelCharacters: function() { // The "." character does not cancel because of projects named // "node.js" or "blog.mycompany.com". - return ['#', '@', ',', '!', '?', '{', '}']; + var defaults = ['#', '@', ',', '!', '?', '{', '}']; + + return this._map[this._active].cancel || defaults; }, _getTerminators: function() { @@ -498,8 +500,6 @@ this._cursorHead, this._cursorTail); - this._value = text; - var pixels = JX.TextAreaUtils.getPixelDimensions( area, range.start, @@ -517,6 +517,24 @@ var trim = this._trim(text); + // If this rule has a prefix pattern, like the "[[ document ]]" rule, + // require it match and throw it away before we begin suggesting + // results. The autocomplete remains active, it's just dormant until + // the user gives us more to work with. + var prefix = this._map[this._active].prefix; + if (prefix) { + var pattern = new RegExp(prefix); + if (!trim.match(pattern)) { + return; + } + trim = trim.replace(pattern, ''); + trim = trim.trim(); + } + + // Store the current value now that we've finished mutating the text. + // This needs to match what we pass to the typeahead datasource. + this._value = trim; + // Deactivate immediately if a user types a character that we are // reasonably sure means they don't want to use the autocomplete. For // example, "##" is almost certainly a header or monospaced text, not