diff --git a/resources/celerity/map.php b/resources/celerity/map.php index a08f04658e..fc3961604b 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,7 +10,7 @@ return array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => '15191c65', 'core.pkg.css' => 'e4f098a5', - 'core.pkg.js' => '3ac6e174', + 'core.pkg.js' => 'bd19de1c', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '113e692c', 'differential.pkg.js' => 'f6d809c0', @@ -506,7 +506,7 @@ return array( 'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e', 'rsrc/js/core/behavior-reveal-content.js' => '60821bc7', 'rsrc/js/core/behavior-scrollbar.js' => '834a1173', - 'rsrc/js/core/behavior-search-typeahead.js' => 'd0a99ab4', + 'rsrc/js/core/behavior-search-typeahead.js' => 'c3e917d9', 'rsrc/js/core/behavior-select-content.js' => 'bf5374ef', 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', 'rsrc/js/core/behavior-setup-check-https.js' => '491416b3', @@ -663,7 +663,7 @@ return array( 'javelin-behavior-phabricator-oncopy' => '2926fff2', 'javelin-behavior-phabricator-remarkup-assist' => 'acd29eee', 'javelin-behavior-phabricator-reveal-content' => '60821bc7', - 'javelin-behavior-phabricator-search-typeahead' => 'd0a99ab4', + 'javelin-behavior-phabricator-search-typeahead' => 'c3e917d9', 'javelin-behavior-phabricator-show-older-transactions' => '8f29b364', 'javelin-behavior-phabricator-tooltips' => 'c420b0b9', 'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6', @@ -1918,6 +1918,17 @@ return array( 'javelin-dom', 'javelin-vector', ), + 'c3e917d9' => array( + 'javelin-behavior', + 'javelin-typeahead-ondemand-source', + 'javelin-typeahead', + 'javelin-dom', + 'javelin-uri', + 'javelin-util', + 'javelin-stratcom', + 'phabricator-prefab', + 'phuix-icon-view', + ), 'c420b0b9' => array( 'javelin-behavior', 'javelin-behavior-device', @@ -1969,17 +1980,6 @@ return array( 'phabricator-notification', 'conpherence-thread-manager', ), - 'd0a99ab4' => array( - 'javelin-behavior', - 'javelin-typeahead-ondemand-source', - 'javelin-typeahead', - 'javelin-dom', - 'javelin-uri', - 'javelin-util', - 'javelin-stratcom', - 'phabricator-prefab', - 'phuix-icon-view', - ), 'd0c516d5' => array( 'javelin-behavior', 'javelin-dom', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index c2ee4966c1..29a957ae6e 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4855,6 +4855,7 @@ phutil_register_library_map(array( 'PhrictionController' => 'applications/phriction/controller/PhrictionController.php', 'PhrictionCreateConduitAPIMethod' => 'applications/phriction/conduit/PhrictionCreateConduitAPIMethod.php', 'PhrictionDAO' => 'applications/phriction/storage/PhrictionDAO.php', + 'PhrictionDatasourceEngineExtension' => 'applications/phriction/engineextension/PhrictionDatasourceEngineExtension.php', 'PhrictionDeleteController' => 'applications/phriction/controller/PhrictionDeleteController.php', 'PhrictionDiffController' => 'applications/phriction/controller/PhrictionDiffController.php', 'PhrictionDocument' => 'applications/phriction/storage/PhrictionDocument.php', @@ -4862,6 +4863,7 @@ phutil_register_library_map(array( 'PhrictionDocumentContentHeraldField' => 'applications/phriction/herald/PhrictionDocumentContentHeraldField.php', 'PhrictionDocumentContentTransaction' => 'applications/phriction/xaction/PhrictionDocumentContentTransaction.php', 'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php', + 'PhrictionDocumentDatasource' => 'applications/phriction/typeahead/PhrictionDocumentDatasource.php', 'PhrictionDocumentDeleteTransaction' => 'applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php', 'PhrictionDocumentFerretEngine' => 'applications/phriction/search/PhrictionDocumentFerretEngine.php', 'PhrictionDocumentFulltextEngine' => 'applications/phriction/search/PhrictionDocumentFulltextEngine.php', @@ -10777,6 +10779,7 @@ phutil_register_library_map(array( 'PhrictionController' => 'PhabricatorController', 'PhrictionCreateConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionDAO' => 'PhabricatorLiskDAO', + 'PhrictionDatasourceEngineExtension' => 'PhabricatorDatasourceEngineExtension', 'PhrictionDeleteController' => 'PhrictionController', 'PhrictionDiffController' => 'PhrictionController', 'PhrictionDocument' => array( @@ -10796,6 +10799,7 @@ phutil_register_library_map(array( 'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField', 'PhrictionDocumentContentTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentController' => 'PhrictionController', + 'PhrictionDocumentDatasource' => 'PhabricatorTypeaheadDatasource', 'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentTransactionType', 'PhrictionDocumentFerretEngine' => 'PhabricatorFerretEngine', 'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine', diff --git a/src/applications/phriction/engineextension/PhrictionDatasourceEngineExtension.php b/src/applications/phriction/engineextension/PhrictionDatasourceEngineExtension.php new file mode 100644 index 0000000000..af262d541d --- /dev/null +++ b/src/applications/phriction/engineextension/PhrictionDatasourceEngineExtension.php @@ -0,0 +1,56 @@ +getViewer(); + + // Send "w" to Phriction. + if (preg_match('/^w\z/i', $query)) { + return '/w/'; + } + + // Send "w " to a search for similar wiki documents. + $matches = null; + if (preg_match('/^w\s+(.+)\z/i', $query, $matches)) { + $raw_query = $matches[1]; + + $engine = id(new PhrictionDocument()) + ->newFerretEngine(); + + $compiler = id(new PhutilSearchQueryCompiler()) + ->setEnableFunctions(true); + + $raw_tokens = $compiler->newTokens($raw_query); + + $fulltext_tokens = array(); + foreach ($raw_tokens as $raw_token) { + $fulltext_token = id(new PhabricatorFulltextToken()) + ->setToken($raw_token); + $fulltext_tokens[] = $fulltext_token; + } + + $documents = id(new PhrictionDocumentQuery()) + ->setViewer($viewer) + ->withFerretConstraint($engine, $fulltext_tokens) + ->execute(); + if (count($documents) == 1) { + return head($documents)->getURI(); + } else { + // More than one match, jump to search. + return urisprintf( + '/phriction/?order=relevance&query=%s#R', + $raw_query); + } + } + + return null; + } +} diff --git a/src/applications/phriction/storage/PhrictionDocument.php b/src/applications/phriction/storage/PhrictionDocument.php index 58d7cbee4a..729d3e4ca5 100644 --- a/src/applications/phriction/storage/PhrictionDocument.php +++ b/src/applications/phriction/storage/PhrictionDocument.php @@ -149,6 +149,10 @@ final class PhrictionDocument extends PhrictionDAO return $this; } + public function getURI() { + return self::getSlugURI($this->getSlug()); + } + /* -( Status )------------------------------------------------------------- */ diff --git a/src/applications/phriction/typeahead/PhrictionDocumentDatasource.php b/src/applications/phriction/typeahead/PhrictionDocumentDatasource.php new file mode 100644 index 0000000000..dc6af6de7a --- /dev/null +++ b/src/applications/phriction/typeahead/PhrictionDocumentDatasource.php @@ -0,0 +1,88 @@ +getViewer(); + + $raw_query = $this->getRawQuery(); + + $engine = id(new PhrictionDocument()) + ->newFerretEngine(); + + $compiler = id(new PhutilSearchQueryCompiler()) + ->setEnableFunctions(true); + + $raw_tokens = $compiler->newTokens($raw_query); + + $fulltext_tokens = array(); + foreach ($raw_tokens as $raw_token) { + + // This is a little hacky and could maybe be cleaner. We're treating + // every search term as though the user had entered "title:dog" insead + // of "dog". + + $alternate_token = PhutilSearchQueryToken::newFromDictionary( + array( + 'quoted' => $raw_token->isQuoted(), + 'value' => $raw_token->getValue(), + 'operator' => PhutilSearchQueryCompiler::OPERATOR_SUBSTRING, + 'function' => 'title', + )); + + $fulltext_token = id(new PhabricatorFulltextToken()) + ->setToken($alternate_token); + $fulltext_tokens[] = $fulltext_token; + } + + $documents = id(new PhrictionDocumentQuery()) + ->setViewer($viewer) + ->withFerretConstraint($engine, $fulltext_tokens) + ->needContent(true) + ->execute(); + + $results = array(); + foreach ($documents as $document) { + $content = $document->getContent(); + + if (!$document->isActive()) { + $closed = $document->getStatusDisplayName(); + } else { + $closed = null; + } + + $slug = $document->getSlug(); + $title = $content->getTitle(); + + $sprite = 'phabricator-search-icon phui-font-fa phui-icon-view fa-book'; + + $result = id(new PhabricatorTypeaheadResult()) + ->setName($title) + ->setDisplayName($title) + ->setURI($document->getURI()) + ->setPHID($document->getPHID()) + ->setDisplayType($slug) + ->setPriorityType('wiki') + ->setImageSprite($sprite) + ->setClosed($closed); + + $results[] = $result; + } + + return $results; + } + +} diff --git a/webroot/rsrc/js/core/behavior-search-typeahead.js b/webroot/rsrc/js/core/behavior-search-typeahead.js index ddcc2e6aaa..0f5b4d1639 100644 --- a/webroot/rsrc/js/core/behavior-search-typeahead.js +++ b/webroot/rsrc/js/core/behavior-search-typeahead.js @@ -70,6 +70,7 @@ JX.behavior('phabricator-search-typeahead', function(config) { 'proj', 'user', 'repo', + 'wiki', 'symb', 'misc' ];