diff --git a/externals/javelin b/externals/javelin index 14e180d5d3..fb9944cff2 160000 --- a/externals/javelin +++ b/externals/javelin @@ -1 +1 @@ -Subproject commit 14e180d5d316d496886730cb6a41d1b36de16ec1 +Subproject commit fb9944cff2e2398ace77d2556f8b65edf88ebd58 diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 6667ce0c5c..112f78e245 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -154,7 +154,7 @@ celerity_register_resource_map(array( ), 'aphront-typeahead-control-css' => array( - 'uri' => '/res/a05236a6/rsrc/css/aphront/typeahead.css', + 'uri' => '/res/311e8830/rsrc/css/aphront/typeahead.css', 'type' => 'css', 'requires' => array( @@ -357,18 +357,12 @@ celerity_register_resource_map(array( ), 'javelin-behavior-aphront-basic-tokenizer' => array( - 'uri' => '/res/69a085d3/rsrc/js/application/core/behavior-tokenizer.js', + 'uri' => '/res/cf049052/rsrc/js/application/core/behavior-tokenizer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', - 1 => 'javelin-typeahead', - 2 => 'javelin-tokenizer', - 3 => 'javelin-typeahead-preloaded-source', - 4 => 'javelin-typeahead-ondemand-source', - 5 => 'javelin-dom', - 6 => 'javelin-stratcom', - 7 => 'javelin-util', + 1 => 'phabricator-prefab', ), 'disk' => '/rsrc/js/application/core/behavior-tokenizer.js', ), @@ -488,15 +482,13 @@ celerity_register_resource_map(array( ), 'javelin-behavior-differential-add-reviewers-and-ccs' => array( - 'uri' => '/res/eb142486/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js', + 'uri' => '/res/27be3f81/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', - 2 => 'javelin-tokenizer', - 3 => 'javelin-typeahead', - 4 => 'javelin-typeahead-preloaded-source', + 2 => 'phabricator-prefab', ), 'disk' => '/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js', ), @@ -739,15 +731,13 @@ celerity_register_resource_map(array( ), 'javelin-behavior-maniphest-transaction-controls' => array( - 'uri' => '/res/33bd237a/rsrc/js/application/maniphest/behavior-transaction-controls.js', + 'uri' => '/res/62465554/rsrc/js/application/maniphest/behavior-transaction-controls.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-behavior', 1 => 'javelin-dom', - 2 => 'javelin-tokenizer', - 3 => 'javelin-typeahead', - 4 => 'javelin-typeahead-preloaded-source', + 2 => 'phabricator-prefab', ), 'disk' => '/rsrc/js/application/maniphest/behavior-transaction-controls.js', ), @@ -1148,7 +1138,7 @@ celerity_register_resource_map(array( ), 'javelin-tokenizer' => array( - 'uri' => '/res/aa86949c/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js', + 'uri' => '/res/a8275d0d/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js', 'type' => 'js', 'requires' => array( @@ -1161,7 +1151,7 @@ celerity_register_resource_map(array( ), 'javelin-typeahead' => array( - 'uri' => '/res/75d4b342/rsrc/js/javelin/lib/control/typeahead/Typeahead.js', + 'uri' => '/res/2f694700/rsrc/js/javelin/lib/control/typeahead/Typeahead.js', 'type' => 'js', 'requires' => array( @@ -1224,7 +1214,7 @@ celerity_register_resource_map(array( ), 'javelin-typeahead-source' => array( - 'uri' => '/res/e99c0c1d/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js', + 'uri' => '/res/ff342bbb/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js', 'type' => 'js', 'requires' => array( @@ -1616,13 +1606,20 @@ celerity_register_resource_map(array( ), 'phabricator-prefab' => array( - 'uri' => '/res/5784a112/rsrc/js/application/core/Prefab.js', + 'uri' => '/res/956c8474/rsrc/js/application/core/Prefab.js', 'type' => 'js', 'requires' => 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', ), 'disk' => '/rsrc/js/application/core/Prefab.js', ), @@ -1941,74 +1938,7 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/09c86840/differential.pkg.css', 'type' => 'css', ), - '0ed3e020' => - array( - 'name' => 'maniphest.pkg.js', - 'symbols' => - array( - 0 => 'javelin-behavior-maniphest-batch-selector', - 1 => 'javelin-behavior-maniphest-transaction-controls', - 2 => 'javelin-behavior-maniphest-transaction-preview', - 3 => 'javelin-behavior-maniphest-transaction-expand', - ), - 'uri' => '/res/pkg/0ed3e020/maniphest.pkg.js', - 'type' => 'js', - ), - '2b5d58e9' => - array( - 'name' => 'core.pkg.css', - 'symbols' => - array( - 0 => 'phabricator-core-css', - 1 => 'phabricator-core-buttons-css', - 2 => 'phabricator-standard-page-view', - 3 => 'aphront-dialog-view-css', - 4 => 'aphront-form-view-css', - 5 => 'aphront-panel-view-css', - 6 => 'aphront-side-nav-view-css', - 7 => 'aphront-table-view-css', - 8 => 'aphront-crumbs-view-css', - 9 => 'aphront-tokenizer-control-css', - 10 => 'aphront-typeahead-control-css', - 11 => 'aphront-list-filter-view-css', - 12 => 'phabricator-directory-css', - 13 => 'phabricator-jump-nav', - 14 => 'phabricator-app-buttons-css', - 15 => 'phabricator-remarkup-css', - 16 => 'syntax-highlighting-css', - 17 => 'aphront-pager-view-css', - 18 => 'phabricator-transaction-view-css', - ), - 'uri' => '/res/pkg/2b5d58e9/core.pkg.css', - 'type' => 'css', - ), - '2e291441' => - array( - 'name' => 'differential.pkg.js', - 'symbols' => - array( - 0 => 'phabricator-drag-and-drop-file-upload', - 1 => 'phabricator-shaped-request', - 2 => 'javelin-behavior-differential-feedback-preview', - 3 => 'javelin-behavior-differential-edit-inline-comments', - 4 => 'javelin-behavior-differential-populate', - 5 => 'javelin-behavior-differential-show-more', - 6 => 'javelin-behavior-differential-diff-radios', - 7 => 'javelin-behavior-differential-accept-with-errors', - 8 => 'javelin-behavior-differential-comment-jump', - 9 => 'javelin-behavior-differential-add-reviewers-and-ccs', - 10 => 'javelin-behavior-differential-keyboard-navigation', - 11 => 'javelin-behavior-aphront-drag-and-drop', - 12 => 'javelin-behavior-aphront-drag-and-drop-textarea', - 13 => 'javelin-behavior-phabricator-object-selector', - 14 => 'differential-inline-comment-editor', - 15 => 'javelin-behavior-differential-dropdown-menus', - 16 => 'javelin-behavior-buoyant', - ), - 'uri' => '/res/pkg/2e291441/differential.pkg.js', - 'type' => 'js', - ), - '3e7cc9b3' => + '2af849fb' => array( 'name' => 'typeahead.pkg.js', 'symbols' => @@ -2021,7 +1951,7 @@ celerity_register_resource_map(array( 5 => 'javelin-tokenizer', 6 => 'javelin-behavior-aphront-basic-tokenizer', ), - 'uri' => '/res/pkg/3e7cc9b3/typeahead.pkg.js', + 'uri' => '/res/pkg/2af849fb/typeahead.pkg.js', 'type' => 'js', ), '4fbae2af' => @@ -2053,6 +1983,73 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/61f9d480/diffusion.pkg.css', 'type' => 'css', ), + '78e8854e' => + array( + 'name' => 'core.pkg.css', + 'symbols' => + array( + 0 => 'phabricator-core-css', + 1 => 'phabricator-core-buttons-css', + 2 => 'phabricator-standard-page-view', + 3 => 'aphront-dialog-view-css', + 4 => 'aphront-form-view-css', + 5 => 'aphront-panel-view-css', + 6 => 'aphront-side-nav-view-css', + 7 => 'aphront-table-view-css', + 8 => 'aphront-crumbs-view-css', + 9 => 'aphront-tokenizer-control-css', + 10 => 'aphront-typeahead-control-css', + 11 => 'aphront-list-filter-view-css', + 12 => 'phabricator-directory-css', + 13 => 'phabricator-jump-nav', + 14 => 'phabricator-app-buttons-css', + 15 => 'phabricator-remarkup-css', + 16 => 'syntax-highlighting-css', + 17 => 'aphront-pager-view-css', + 18 => 'phabricator-transaction-view-css', + ), + 'uri' => '/res/pkg/78e8854e/core.pkg.css', + 'type' => 'css', + ), + '86fc0b0c' => + array( + 'name' => 'maniphest.pkg.js', + 'symbols' => + array( + 0 => 'javelin-behavior-maniphest-batch-selector', + 1 => 'javelin-behavior-maniphest-transaction-controls', + 2 => 'javelin-behavior-maniphest-transaction-preview', + 3 => 'javelin-behavior-maniphest-transaction-expand', + ), + 'uri' => '/res/pkg/86fc0b0c/maniphest.pkg.js', + 'type' => 'js', + ), + 'e8b28c4a' => + array( + 'name' => 'differential.pkg.js', + 'symbols' => + array( + 0 => 'phabricator-drag-and-drop-file-upload', + 1 => 'phabricator-shaped-request', + 2 => 'javelin-behavior-differential-feedback-preview', + 3 => 'javelin-behavior-differential-edit-inline-comments', + 4 => 'javelin-behavior-differential-populate', + 5 => 'javelin-behavior-differential-show-more', + 6 => 'javelin-behavior-differential-diff-radios', + 7 => 'javelin-behavior-differential-accept-with-errors', + 8 => 'javelin-behavior-differential-comment-jump', + 9 => 'javelin-behavior-differential-add-reviewers-and-ccs', + 10 => 'javelin-behavior-differential-keyboard-navigation', + 11 => 'javelin-behavior-aphront-drag-and-drop', + 12 => 'javelin-behavior-aphront-drag-and-drop-textarea', + 13 => 'javelin-behavior-phabricator-object-selector', + 14 => 'differential-inline-comment-editor', + 15 => 'javelin-behavior-differential-dropdown-menus', + 16 => 'javelin-behavior-buoyant', + ), + 'uri' => '/res/pkg/e8b28c4a/differential.pkg.js', + 'type' => 'js', + ), 31583232 => array( 'name' => 'maniphest.pkg.css', @@ -2092,20 +2089,20 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => '31583232', - 'aphront-crumbs-view-css' => '2b5d58e9', - 'aphront-dialog-view-css' => '2b5d58e9', - 'aphront-form-view-css' => '2b5d58e9', + 'aphront-crumbs-view-css' => '78e8854e', + 'aphront-dialog-view-css' => '78e8854e', + 'aphront-form-view-css' => '78e8854e', 'aphront-headsup-action-list-view-css' => '09c86840', - 'aphront-list-filter-view-css' => '2b5d58e9', - 'aphront-pager-view-css' => '2b5d58e9', - 'aphront-panel-view-css' => '2b5d58e9', - 'aphront-side-nav-view-css' => '2b5d58e9', - 'aphront-table-view-css' => '2b5d58e9', - 'aphront-tokenizer-control-css' => '2b5d58e9', - 'aphront-typeahead-control-css' => '2b5d58e9', + 'aphront-list-filter-view-css' => '78e8854e', + 'aphront-pager-view-css' => '78e8854e', + 'aphront-panel-view-css' => '78e8854e', + 'aphront-side-nav-view-css' => '78e8854e', + 'aphront-table-view-css' => '78e8854e', + 'aphront-tokenizer-control-css' => '78e8854e', + 'aphront-typeahead-control-css' => '78e8854e', 'differential-changeset-view-css' => '09c86840', 'differential-core-view-css' => '09c86840', - 'differential-inline-comment-editor' => '2e291441', + 'differential-inline-comment-editor' => 'e8b28c4a', 'differential-local-commits-view-css' => '09c86840', 'differential-revision-add-comment-css' => '09c86840', 'differential-revision-comment-css' => '09c86840', @@ -2115,28 +2112,28 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => '09c86840', 'diffusion-commit-view-css' => '61f9d480', 'javelin-behavior' => '4fbae2af', - 'javelin-behavior-aphront-basic-tokenizer' => '3e7cc9b3', - 'javelin-behavior-aphront-drag-and-drop' => '2e291441', - 'javelin-behavior-aphront-drag-and-drop-textarea' => '2e291441', + 'javelin-behavior-aphront-basic-tokenizer' => '2af849fb', + 'javelin-behavior-aphront-drag-and-drop' => 'e8b28c4a', + 'javelin-behavior-aphront-drag-and-drop-textarea' => 'e8b28c4a', 'javelin-behavior-aphront-form-disable-on-submit' => '95944588', - 'javelin-behavior-buoyant' => '2e291441', - 'javelin-behavior-differential-accept-with-errors' => '2e291441', - 'javelin-behavior-differential-add-reviewers-and-ccs' => '2e291441', - 'javelin-behavior-differential-comment-jump' => '2e291441', - 'javelin-behavior-differential-diff-radios' => '2e291441', - 'javelin-behavior-differential-dropdown-menus' => '2e291441', - 'javelin-behavior-differential-edit-inline-comments' => '2e291441', - 'javelin-behavior-differential-feedback-preview' => '2e291441', - 'javelin-behavior-differential-keyboard-navigation' => '2e291441', - 'javelin-behavior-differential-populate' => '2e291441', - 'javelin-behavior-differential-show-more' => '2e291441', - 'javelin-behavior-maniphest-batch-selector' => '0ed3e020', - 'javelin-behavior-maniphest-transaction-controls' => '0ed3e020', - 'javelin-behavior-maniphest-transaction-expand' => '0ed3e020', - 'javelin-behavior-maniphest-transaction-preview' => '0ed3e020', + 'javelin-behavior-buoyant' => 'e8b28c4a', + 'javelin-behavior-differential-accept-with-errors' => 'e8b28c4a', + 'javelin-behavior-differential-add-reviewers-and-ccs' => 'e8b28c4a', + 'javelin-behavior-differential-comment-jump' => 'e8b28c4a', + 'javelin-behavior-differential-diff-radios' => 'e8b28c4a', + 'javelin-behavior-differential-dropdown-menus' => 'e8b28c4a', + 'javelin-behavior-differential-edit-inline-comments' => 'e8b28c4a', + 'javelin-behavior-differential-feedback-preview' => 'e8b28c4a', + 'javelin-behavior-differential-keyboard-navigation' => 'e8b28c4a', + 'javelin-behavior-differential-populate' => 'e8b28c4a', + 'javelin-behavior-differential-show-more' => 'e8b28c4a', + 'javelin-behavior-maniphest-batch-selector' => '86fc0b0c', + 'javelin-behavior-maniphest-transaction-controls' => '86fc0b0c', + 'javelin-behavior-maniphest-transaction-expand' => '86fc0b0c', + 'javelin-behavior-maniphest-transaction-preview' => '86fc0b0c', 'javelin-behavior-phabricator-autofocus' => '95944588', 'javelin-behavior-phabricator-keyboard-shortcuts' => '95944588', - 'javelin-behavior-phabricator-object-selector' => '2e291441', + 'javelin-behavior-phabricator-object-selector' => 'e8b28c4a', 'javelin-behavior-phabricator-watch-anchor' => '95944588', 'javelin-behavior-refresh-csrf' => '95944588', 'javelin-behavior-workflow' => '95944588', @@ -2147,12 +2144,12 @@ celerity_register_resource_map(array( 'javelin-mask' => '95944588', 'javelin-request' => '4fbae2af', 'javelin-stratcom' => '4fbae2af', - 'javelin-tokenizer' => '3e7cc9b3', - 'javelin-typeahead' => '3e7cc9b3', - 'javelin-typeahead-normalizer' => '3e7cc9b3', - 'javelin-typeahead-ondemand-source' => '3e7cc9b3', - 'javelin-typeahead-preloaded-source' => '3e7cc9b3', - 'javelin-typeahead-source' => '3e7cc9b3', + 'javelin-tokenizer' => '2af849fb', + 'javelin-typeahead' => '2af849fb', + 'javelin-typeahead-normalizer' => '2af849fb', + 'javelin-typeahead-ondemand-source' => '2af849fb', + 'javelin-typeahead-preloaded-source' => '2af849fb', + 'javelin-typeahead-source' => '2af849fb', 'javelin-uri' => '4fbae2af', 'javelin-util' => '4fbae2af', 'javelin-vector' => '4fbae2af', @@ -2160,23 +2157,23 @@ celerity_register_resource_map(array( 'maniphest-task-detail-css' => '31583232', 'maniphest-task-summary-css' => '31583232', 'maniphest-transaction-detail-css' => '31583232', - 'phabricator-app-buttons-css' => '2b5d58e9', + 'phabricator-app-buttons-css' => '78e8854e', 'phabricator-content-source-view-css' => '09c86840', - 'phabricator-core-buttons-css' => '2b5d58e9', - 'phabricator-core-css' => '2b5d58e9', - 'phabricator-directory-css' => '2b5d58e9', - 'phabricator-drag-and-drop-file-upload' => '2e291441', + 'phabricator-core-buttons-css' => '78e8854e', + 'phabricator-core-css' => '78e8854e', + 'phabricator-directory-css' => '78e8854e', + 'phabricator-drag-and-drop-file-upload' => 'e8b28c4a', 'phabricator-dropdown-menu' => '95944588', - 'phabricator-jump-nav' => '2b5d58e9', + 'phabricator-jump-nav' => '78e8854e', 'phabricator-keyboard-shortcut' => '95944588', 'phabricator-keyboard-shortcut-manager' => '95944588', 'phabricator-menu-item' => '95944588', 'phabricator-object-selector-css' => '09c86840', 'phabricator-paste-file-upload' => '95944588', - 'phabricator-remarkup-css' => '2b5d58e9', - 'phabricator-shaped-request' => '2e291441', - 'phabricator-standard-page-view' => '2b5d58e9', - 'phabricator-transaction-view-css' => '2b5d58e9', - 'syntax-highlighting-css' => '2b5d58e9', + 'phabricator-remarkup-css' => '78e8854e', + 'phabricator-shaped-request' => 'e8b28c4a', + 'phabricator-standard-page-view' => '78e8854e', + 'phabricator-transaction-view-css' => '78e8854e', + 'syntax-highlighting-css' => '78e8854e', ), )); diff --git a/src/applications/differential/view/addcomment/DifferentialAddCommentView.php b/src/applications/differential/view/addcomment/DifferentialAddCommentView.php index 1527e81ee2..5d8c57a581 100644 --- a/src/applications/differential/view/addcomment/DifferentialAddCommentView.php +++ b/src/applications/differential/view/addcomment/DifferentialAddCommentView.php @@ -128,12 +128,14 @@ final class DifferentialAddCommentView extends AphrontView { 'src' => '/typeahead/common/users/', 'row' => 'add-reviewers', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), + 'placeholder' => 'Type a user name...', ), 'add-ccs-tokenizer' => array( 'actions' => array('add_ccs' => 1), 'src' => '/typeahead/common/mailable/', 'row' => 'add-ccs', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), + 'placeholder' => 'Type a user or mailing list...', ), ), 'select' => 'comment-action', diff --git a/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php index 7341064208..86b2188ffa 100644 --- a/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php @@ -450,6 +450,7 @@ final class ManiphestTaskDetailController extends ManiphestController { 'id' => 'projects-tokenizer', 'src' => '/typeahead/common/projects/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), + 'placeholder' => 'Type a project name...', ), ManiphestTransactionType::TYPE_OWNER => array( 'id' => 'assign-tokenizer', @@ -457,11 +458,13 @@ final class ManiphestTaskDetailController extends ManiphestController { 'value' => $default_claim, 'limit' => 1, 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), + 'placeholder' => 'Type a user name...', ), ManiphestTransactionType::TYPE_CCS => array( 'id' => 'cc-tokenizer', 'src' => '/typeahead/common/mailable/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), + 'placeholder' => 'Type a user or mailing list...', ), ), )); diff --git a/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php b/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php index efe62ce180..c07e0a7820 100644 --- a/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php +++ b/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php @@ -390,6 +390,7 @@ final class ManiphestTaskEditController extends ManiphestController { ->setLabel('Assigned To') ->setName('assigned_to') ->setValue($assigned_value) + ->setUser($user) ->setDatasource('/typeahead/common/users/') ->setLimit(1)) ->appendChild( @@ -397,6 +398,7 @@ final class ManiphestTaskEditController extends ManiphestController { ->setLabel('CC') ->setName('cc') ->setValue($cc_value) + ->setUser($user) ->setDatasource('/typeahead/common/mailable/')) ->appendChild( id(new AphrontFormSelectControl()) diff --git a/src/view/form/control/tokenizer/AphrontFormTokenizerControl.php b/src/view/form/control/tokenizer/AphrontFormTokenizerControl.php index bef0b2827c..70d0ca7913 100644 --- a/src/view/form/control/tokenizer/AphrontFormTokenizerControl.php +++ b/src/view/form/control/tokenizer/AphrontFormTokenizerControl.php @@ -22,6 +22,7 @@ class AphrontFormTokenizerControl extends AphrontFormControl { private $disableBehavior; private $limit; private $user; + private $placeholder; public function setDatasource($datasource) { $this->datasource = $datasource; @@ -47,6 +48,11 @@ class AphrontFormTokenizerControl extends AphrontFormControl { return $this; } + public function setPlaceholder($placeholder) { + $this->placeholder = $placeholder; + return $this; + } + protected function renderInput() { $name = $this->getName(); $values = nonempty($this->getValue(), array()); @@ -57,6 +63,11 @@ class AphrontFormTokenizerControl extends AphrontFormControl { $id = celerity_generate_unique_node_id(); } + $placeholder = null; + if (!$this->placeholder) { + $placeholder = $this->getDefaultPlaceholder(); + } + $template = new AphrontTokenizerTemplateView(); $template->setName($name); $template->setID($id); @@ -69,17 +80,43 @@ class AphrontFormTokenizerControl extends AphrontFormControl { if (!$this->disableBehavior) { Javelin::initBehavior('aphront-basic-tokenizer', array( - 'id' => $id, - 'src' => $this->datasource, - 'value' => $values, - 'limit' => $this->limit, - 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), - 'username' => $username, + 'id' => $id, + 'src' => $this->datasource, + 'value' => $values, + 'limit' => $this->limit, + 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), + 'username' => $username, + 'placeholder' => $placeholder, )); } return $template->render(); } + private function getDefaultPlaceholder() { + $datasource = $this->datasource; + + $matches = null; + if (!preg_match('@^/typeahead/common/(.*)/$@', $datasource, $matches)) { + return null; + } + + $request = $matches[1]; + + $map = array( + 'users' => 'Type a user name...', + 'searchowner' => 'Type a user name...', + 'accounts' => 'Type a user name...', + 'mailable' => 'Type a user or mailing list...', + 'searchproject' => 'Type a project name...', + 'projects' => 'Type a project name...', + 'repositories' => 'Type a repository name...', + 'packages' => 'Type a package name...', + 'arcanistproject' => 'Type an arc project name...', + ); + + return idx($map, $request); + } + } diff --git a/webroot/rsrc/css/aphront/typeahead.css b/webroot/rsrc/css/aphront/typeahead.css index b3a7b18142..0cbd5d14c8 100644 --- a/webroot/rsrc/css/aphront/typeahead.css +++ b/webroot/rsrc/css/aphront/typeahead.css @@ -42,3 +42,7 @@ table.jx-typeahead input { font-size: 13px; padding: 2px; } + +input.jx-typeahead-placeholder { + color: #888888; +} diff --git a/webroot/rsrc/js/application/core/Prefab.js b/webroot/rsrc/js/application/core/Prefab.js index fedbb35843..9f2fc008cc 100644 --- a/webroot/rsrc/js/application/core/Prefab.js +++ b/webroot/rsrc/js/application/core/Prefab.js @@ -3,6 +3,13 @@ * @requires javelin-install * javelin-util * javelin-dom + * javelin-typeahead + * javelin-tokenizer + * javelin-typeahead-preloaded-source + * javelin-typeahead-ondemand-source + * javelin-dom + * javelin-stratcom + * javelin-util * @javelin */ @@ -22,6 +29,107 @@ JX.install('Prefab', { } select.value = select.value || JX.keys(map)[0]; return select; + }, + + /** + * Build a Phabricator tokenizer out of a configuration with application + * sorting, datasource and placeholder rules. + * + * - `id` Root tokenizer ID. + * - `src` Datasource URI. + * - `ondemand` Optional, use an ondemand source. + * - `value` Optional, initial value. + * - `limit` Optional, token limit. + * - `placeholder` Optional, placeholder text. + * - `username` Optional, username to sort first (i.e., viewer). + * + */ + buildTokenizer : function(config) { + var root = JX.$(config.id); + + var datasource; + if (config.ondemand) { + datasource = new JX.TypeaheadOnDemandSource(config.src); + } else { + datasource = new JX.TypeaheadPreloadedSource(config.src); + } + + // Sort results so that the viewing user always comes up first; after + // that, prefer unixname matches to realname matches. + + var sort_handler = function(value, list, cmp) { + var priority_hits = {}; + var self_hits = {}; + + var tokens = this.tokenize(value); + + for (var ii = 0; ii < list.length; ii++) { + var item = list[ii]; + if (!item.priority) { + continue; + } + + if (config.username && item.priority == config.username) { + self_hits[item.id] = true; + } + + for (var jj = 0; jj < tokens.length; jj++) { + if (item.priority.substr(0, tokens[jj].length) == tokens[jj]) { + priority_hits[item.id] = true; + } + } + } + + list.sort(function(u, v) { + if (self_hits[u.id] != self_hits[v.id]) { + return self_hits[v.id] ? 1 : -1; + } + + if (priority_hits[u.id] != priority_hits[v.id]) { + return priority_hits[v.id] ? 1 : -1; + } + + return cmp(u, v); + }); + }; + + datasource.setSortHandler(JX.bind(datasource, sort_handler)); + datasource.setTransformer( + function(object) { + return { + name: object[0], + display: object[0], + uri: object[1], + id: object[2], + priority: object[3] + }; + }); + + var typeahead = new JX.Typeahead( + root, + JX.DOM.find(root, 'input', 'tokenizer-input')); + typeahead.setDatasource(datasource); + + var tokenizer = new JX.Tokenizer(root); + tokenizer.setTypeahead(typeahead); + + if (config.placeholder) { + tokenizer.setPlaceholder(config.placeholder); + } + + if (config.limit) { + tokenizer.setLimit(config.limit); + } + + if (config.value) { + tokenizer.setInitialValue(config.value); + } + + JX.Stratcom.addData(root, {'tokenizer' : tokenizer}); + + return { + tokenizer: tokenizer + }; } } diff --git a/webroot/rsrc/js/application/core/behavior-tokenizer.js b/webroot/rsrc/js/application/core/behavior-tokenizer.js index fe02ac4a67..ec7bc4a7cd 100644 --- a/webroot/rsrc/js/application/core/behavior-tokenizer.js +++ b/webroot/rsrc/js/application/core/behavior-tokenizer.js @@ -1,94 +1,9 @@ /** * @provides javelin-behavior-aphront-basic-tokenizer * @requires javelin-behavior - * javelin-typeahead - * javelin-tokenizer - * javelin-typeahead-preloaded-source - * javelin-typeahead-ondemand-source - * javelin-dom - * javelin-stratcom - * javelin-util + * phabricator-prefab */ JX.behavior('aphront-basic-tokenizer', function(config) { - var root = JX.$(config.id); - - var datasource; - if (config.ondemand) { - datasource = new JX.TypeaheadOnDemandSource(config.src); - } else { - datasource = new JX.TypeaheadPreloadedSource(config.src); - } - - // Sort results so that the viewing user always comes up first; after that, - // prefer unixname matches to realname matches. - - var sort_handler = function(value, list, cmp) { - var priority_hits = {}; - var self_hits = {}; - - var tokens = this.tokenize(value); - - for (var ii = 0; ii < list.length; ii++) { - var item = list[ii]; - if (!item.priority) { - continue; - } - - if (config.username && item.priority == config.username) { - self_hits[item.id] = true; - } - - for (var jj = 0; jj < tokens.length; jj++) { - if (item.priority.substr(0, tokens[jj].length) == tokens[jj]) { - priority_hits[item.id] = true; - } - } - } - - list.sort(function(u, v) { - if (self_hits[u.id] != self_hits[v.id]) { - return self_hits[v.id] ? 1 : -1; - } - - if (priority_hits[u.id] != priority_hits[v.id]) { - return priority_hits[v.id] ? 1 : -1; - } - - return cmp(u, v); - }); - }; - - datasource.setSortHandler(JX.bind(datasource, sort_handler)); - datasource.setTransformer( - function(object) { - return { - name : object[0], - display : object[0], - uri : object[1], - id : object[2], - priority : object[3] - }; - }); - - var typeahead = new JX.Typeahead( - root, - JX.DOM.find(root, 'input', 'tokenizer-input')); - typeahead.setDatasource(datasource); - - var tokenizer = new JX.Tokenizer(root); - tokenizer.setTypeahead(typeahead); - - if (config.limit) { - tokenizer.setLimit(config.limit); - } - - if (config.value) { - tokenizer.setInitialValue(config.value); - } - - JX.Stratcom.addData(root, {'tokenizer' : tokenizer}); - - tokenizer.start(); - + JX.Prefab.buildTokenizer(config).tokenizer.start(); }); diff --git a/webroot/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js b/webroot/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js index d9d6187d06..6c2d72b6b5 100644 --- a/webroot/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js +++ b/webroot/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js @@ -2,42 +2,22 @@ * @provides javelin-behavior-differential-add-reviewers-and-ccs * @requires javelin-behavior * javelin-dom - * javelin-tokenizer - * javelin-typeahead - * javelin-typeahead-preloaded-source + * phabricator-prefab */ JX.behavior('differential-add-reviewers-and-ccs', function(config) { - function buildTokenizer(id, props) { - var root = JX.$(id); - - var datasource; - if (props.ondemand) { - datasource = new JX.TypeaheadOnDemandSource(props.src); - } else { - datasource = new JX.TypeaheadPreloadedSource(props.src); - } - - var typeahead = new JX.Typeahead(root); - typeahead.setDatasource(datasource); - - var tokenizer = new JX.Tokenizer(root); - tokenizer.setTypeahead(typeahead); - - JX.Stratcom.addData(root, {'tokenizer' : tokenizer}); - - tokenizer.start(); - - return tokenizer; - } - var dynamic = {}; for (var k in config.dynamic) { - props = config.dynamic[k]; + var props = config.dynamic[k]; + props.id = k; + + var tokenizer = JX.Prefab.buildTokenizer(props).tokenizer; + tokenizer.start(); + dynamic[k] = { row : JX.$(props.row), - tokenizer : buildTokenizer(k, props), + tokenizer : tokenizer, actions : props.actions }; } diff --git a/webroot/rsrc/js/application/maniphest/behavior-transaction-controls.js b/webroot/rsrc/js/application/maniphest/behavior-transaction-controls.js index 40f90a5849..b532f9b0b6 100644 --- a/webroot/rsrc/js/application/maniphest/behavior-transaction-controls.js +++ b/webroot/rsrc/js/application/maniphest/behavior-transaction-controls.js @@ -2,9 +2,7 @@ * @provides javelin-behavior-maniphest-transaction-controls * @requires javelin-behavior * javelin-dom - * javelin-tokenizer - * javelin-typeahead - * javelin-typeahead-preloaded-source + * phabricator-prefab */ JX.behavior('maniphest-transaction-controls', function(config) { @@ -13,35 +11,8 @@ JX.behavior('maniphest-transaction-controls', function(config) { for (var k in config.tokenizers) { var tconfig = config.tokenizers[k]; - var root = JX.$(tconfig.id); - - var datasource; - if (tconfig.ondemand) { - datasource = new JX.TypeaheadOnDemandSource(tconfig.src); - } else { - datasource = new JX.TypeaheadPreloadedSource(tconfig.src); - } - - var typeahead = new JX.Typeahead(root); - typeahead.setDatasource(datasource); - - var tokenizer = new JX.Tokenizer(root); - tokenizer.setTypeahead(typeahead); - - if (tconfig.limit) { - tokenizer.setLimit(tconfig.limit); - } - - tokenizer.start(); - - - if (tconfig.value) { - for (var jj in tconfig.value) { - tokenizer.addToken(jj, tconfig.value[jj]); - } - } - - tokenizers[k] = tokenizer; + tokenizers[k] = JX.Prefab.buildTokenizer(tconfig).tokenizer; + tokenizers[k].start() } JX.DOM.listen(