From a4261f41c2b7bf7e88ea7791c6ffcde78622224c Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 16 Apr 2015 14:46:10 -0700 Subject: [PATCH] Make browse action available for dynamic/JS-driven tokenizers Summary: Ref T5750. This makes browse work for all of the dynamic tokenizers in Herald, Policies, batch editor, etc. Test Plan: Used tokenizers in Herald, Policies, Batch editor. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5750 Differential Revision: https://secure.phabricator.com/D12442 --- .../controller/HeraldRuleController.php | 3 ++ .../PhabricatorMailingListDatasource.php | 17 ++++----- .../ManiphestBatchEditController.php | 21 +++++++---- ...PhabricatorLegalpadSignaturePolicyRule.php | 8 +--- .../policy/rule/PhabricatorPolicyRule.php | 10 +++++ .../rule/PhabricatorProjectsPolicyRule.php | 8 +--- .../rule/PhabricatorUsersPolicyRule.php | 8 +--- .../control/AphrontTokenizerTemplateView.php | 37 +++++++++++-------- webroot/rsrc/css/aphront/tokenizer.css | 10 ++++- .../lib/control/tokenizer/Tokenizer.js | 1 + .../js/application/herald/HeraldRuleEditor.js | 14 +++---- .../maniphest/behavior-batch-editor.js | 12 ++---- .../policy/behavior-policy-rule-editor.js | 13 ++++--- webroot/rsrc/js/core/Prefab.js | 11 ++++++ 14 files changed, 95 insertions(+), 78 deletions(-) diff --git a/src/applications/herald/controller/HeraldRuleController.php b/src/applications/herald/controller/HeraldRuleController.php index c16a45b47e..6780693031 100644 --- a/src/applications/herald/controller/HeraldRuleController.php +++ b/src/applications/herald/controller/HeraldRuleController.php @@ -605,9 +605,12 @@ final class HeraldRuleController extends HeraldController { ); foreach ($sources as $key => $source) { + $source->setViewer($this->getViewer()); + $sources[$key] = array( 'uri' => $source->getDatasourceURI(), 'placeholder' => $source->getPlaceholderText(), + 'browseURI' => $source->getBrowseURI(), ); } diff --git a/src/applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php b/src/applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php index c08da2a30d..b9435e0b4a 100644 --- a/src/applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php +++ b/src/applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php @@ -3,11 +3,6 @@ final class PhabricatorMailingListDatasource extends PhabricatorTypeaheadDatasource { - public function isBrowsable() { - // TODO: Make this browsable if we don't delete it before then. - return false; - } - public function getPlaceholderText() { return pht('Type a mailing list name...'); } @@ -20,11 +15,10 @@ final class PhabricatorMailingListDatasource $viewer = $this->getViewer(); $raw_query = $this->getRawQuery(); - $results = array(); + $query = id(new PhabricatorMailingListQuery()); + $lists = $this->executeQuery($query); - $lists = id(new PhabricatorMailingListQuery()) - ->setViewer($viewer) - ->execute(); + $results = array(); foreach ($lists as $list) { $results[] = id(new PhabricatorTypeaheadResult()) ->setName($list->getName()) @@ -32,7 +26,10 @@ final class PhabricatorMailingListDatasource ->setPHID($list->getPHID()); } - return $results; + // TODO: It would be slightly preferable to do this as part of the query, + // this is just simpler for the moment. + + return $this->filterResultsAgainstTokens($results); } } diff --git a/src/applications/maniphest/controller/ManiphestBatchEditController.php b/src/applications/maniphest/controller/ManiphestBatchEditController.php index f22269c10e..f604d58d0c 100644 --- a/src/applications/maniphest/controller/ManiphestBatchEditController.php +++ b/src/applications/maniphest/controller/ManiphestBatchEditController.php @@ -65,7 +65,9 @@ final class ManiphestBatchEditController extends ManiphestController { $projects_source = new PhabricatorProjectDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); + $mailable_source->setViewer($user); $owner_source = new PhabricatorTypeaheadOwnerDatasource(); + $owner_source->setViewer($user); require_celerity_resource('maniphest-batch-editor'); Javelin::initBehavior( @@ -75,17 +77,20 @@ final class ManiphestBatchEditController extends ManiphestController { 'tokenizerTemplate' => $template, 'sources' => array( 'project' => array( - 'src' => $projects_source->getDatasourceURI(), - 'placeholder' => $projects_source->getPlaceholderText(), + 'src' => $projects_source->getDatasourceURI(), + 'placeholder' => $projects_source->getPlaceholderText(), + 'browseURI' => $projects_source->getBrowseURI(), ), 'owner' => array( - 'src' => $owner_source->getDatasourceURI(), - 'placeholder' => $owner_source->getPlaceholderText(), - 'limit' => 1, + 'src' => $owner_source->getDatasourceURI(), + 'placeholder' => $owner_source->getPlaceholderText(), + 'browseURI' => $owner_source->getBrowseURI(), + 'limit' => 1, ), - 'cc' => array( - 'src' => $mailable_source->getDatasourceURI(), - 'placeholder' => $mailable_source->getPlaceholderText(), + 'cc' => array( + 'src' => $mailable_source->getDatasourceURI(), + 'placeholder' => $mailable_source->getPlaceholderText(), + 'browseURI' => $mailable_source->getBrowseURI(), ), ), 'input' => 'batch-form-actions', diff --git a/src/applications/policy/rule/PhabricatorLegalpadSignaturePolicyRule.php b/src/applications/policy/rule/PhabricatorLegalpadSignaturePolicyRule.php index 14d207b4d8..9797d5ef80 100644 --- a/src/applications/policy/rule/PhabricatorLegalpadSignaturePolicyRule.php +++ b/src/applications/policy/rule/PhabricatorLegalpadSignaturePolicyRule.php @@ -40,13 +40,7 @@ final class PhabricatorLegalpadSignaturePolicyRule } public function getValueControlTemplate() { - $datasource = new LegalpadDocumentDatasource(); - - return array( - 'markup' => new AphrontTokenizerTemplateView(), - 'uri' => $datasource->getDatasourceURI(), - 'placeholder' => $datasource->getPlaceholderText(), - ); + return $this->getDatasourceTemplate(new LegalpadDocumentDatasource()); } public function getRuleOrder() { diff --git a/src/applications/policy/rule/PhabricatorPolicyRule.php b/src/applications/policy/rule/PhabricatorPolicyRule.php index 6540d797df..eaa04e1e9e 100644 --- a/src/applications/policy/rule/PhabricatorPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorPolicyRule.php @@ -22,6 +22,16 @@ abstract class PhabricatorPolicyRule { return null; } + protected function getDatasourceTemplate( + PhabricatorTypeaheadDatasource $datasource) { + return array( + 'markup' => new AphrontTokenizerTemplateView(), + 'uri' => $datasource->getDatasourceURI(), + 'placeholder' => $datasource->getPlaceholderText(), + 'browseURI' => $datasource->getBrowseURI(), + ); + } + public function getRuleOrder() { return 500; } diff --git a/src/applications/policy/rule/PhabricatorProjectsPolicyRule.php b/src/applications/policy/rule/PhabricatorProjectsPolicyRule.php index 7bd75495c8..eca97ce37d 100644 --- a/src/applications/policy/rule/PhabricatorProjectsPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorProjectsPolicyRule.php @@ -38,13 +38,7 @@ final class PhabricatorProjectsPolicyRule extends PhabricatorPolicyRule { } public function getValueControlTemplate() { - $projects_source = new PhabricatorProjectDatasource(); - - return array( - 'markup' => new AphrontTokenizerTemplateView(), - 'uri' => $projects_source->getDatasourceURI(), - 'placeholder' => $projects_source->getPlaceholderText(), - ); + return $this->getDatasourceTemplate(new PhabricatorProjectDatasource()); } public function getRuleOrder() { diff --git a/src/applications/policy/rule/PhabricatorUsersPolicyRule.php b/src/applications/policy/rule/PhabricatorUsersPolicyRule.php index 03be81e064..c60e43abb6 100644 --- a/src/applications/policy/rule/PhabricatorUsersPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorUsersPolicyRule.php @@ -20,13 +20,7 @@ final class PhabricatorUsersPolicyRule extends PhabricatorPolicyRule { } public function getValueControlTemplate() { - $users_datasource = new PhabricatorPeopleDatasource(); - - return array( - 'markup' => new AphrontTokenizerTemplateView(), - 'uri' => $users_datasource->getDatasourceURI(), - 'placeholder' => $users_datasource->getPlaceholderText(), - ); + return $this->getDatasourceTemplate(new PhabricatorPeopleDatasource()); } public function getRuleOrder() { diff --git a/src/view/control/AphrontTokenizerTemplateView.php b/src/view/control/AphrontTokenizerTemplateView.php index 009f3e134e..f0e34f2b1e 100644 --- a/src/view/control/AphrontTokenizerTemplateView.php +++ b/src/view/control/AphrontTokenizerTemplateView.php @@ -67,35 +67,40 @@ final class AphrontTokenizerTemplateView extends AphrontView { $content[] = $input; $content[] = phutil_tag('div', array('style' => 'clear: both;'), ''); - $container = phutil_tag( + $container = javelin_tag( 'div', array( 'id' => $id, 'class' => 'jx-tokenizer-container', + 'sigil' => 'tokenizer-container', ), $content); - $browse = null; - if ($this->browseURI) { - $icon = id(new PHUIIconView()) - ->setIconFont('fa-list-ul'); + $icon = id(new PHUIIconView()) + ->setIconFont('fa-list-ul'); - // TODO: This thing is ugly and the ugliness is not intentional. - // We have to give it text or PHUIButtonView collapses. It should likely - // just be an icon and look more integrated into the input. - $browse = id(new PHUIButtonView()) - ->setTag('a') - ->setIcon($icon) - ->addSigil('tokenizer-browse') - ->setColor(PHUIButtonView::GREY) - ->setSize(PHUIButtonView::SMALL) - ->setText(pht('Browse...')); + // TODO: This thing is ugly and the ugliness is not intentional. + // We have to give it text or PHUIButtonView collapses. It should likely + // just be an icon and look more integrated into the input. + $browse = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon($icon) + ->addSigil('tokenizer-browse') + ->setColor(PHUIButtonView::GREY) + ->setSize(PHUIButtonView::SMALL) + ->setText(pht('Browse...')); + + $classes = array(); + $classes[] = 'jx-tokenizer-frame'; + + if ($this->browseURI) { + $classes[] = 'has-browse'; } $frame = javelin_tag( 'table', array( - 'class' => 'jx-tokenizer-frame', + 'class' => implode(' ', $classes), 'sigil' => 'tokenizer-frame', ), phutil_tag( diff --git a/webroot/rsrc/css/aphront/tokenizer.css b/webroot/rsrc/css/aphront/tokenizer.css index 074f54e5d8..2056c88c31 100644 --- a/webroot/rsrc/css/aphront/tokenizer.css +++ b/webroot/rsrc/css/aphront/tokenizer.css @@ -109,7 +109,15 @@ a.jx-tokenizer-token:hover { width: 100%; } -.jx-tokenizer-frame-input { +.jx-tokenizer-frame .jx-tokenizer-frame-browse { + display: none; +} + +.has-browse .jx-tokenizer-frame-browse { + display: table-cell; +} + +.jx-tokenizer-frame td.jx-tokenizer-frame-input { width: 100%; } diff --git a/webroot/rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js b/webroot/rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js index bdde22fb88..93e540ece3 100644 --- a/webroot/rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js +++ b/webroot/rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js @@ -85,6 +85,7 @@ JX.install('Tokenizer', { } if (this._frame) { + JX.DOM.alterClass(this._frame, 'has-browse', !!this.getBrowseURI()); JX.DOM.listen( this._frame, 'click', diff --git a/webroot/rsrc/js/application/herald/HeraldRuleEditor.js b/webroot/rsrc/js/application/herald/HeraldRuleEditor.js index 36f28bc865..abf645ba29 100644 --- a/webroot/rsrc/js/application/herald/HeraldRuleEditor.js +++ b/webroot/rsrc/js/application/herald/HeraldRuleEditor.js @@ -277,25 +277,21 @@ JX.install('HeraldRuleEditor', { }, _newTokenizer : function(type) { - var template = JX.$N( - 'div', - JX.$H(this._config.template.markup)); - template = template.firstChild; - template.id = ''; - var tokenizerConfig = { - root : template, src : this._config.template.source[type].uri, placeholder: this._config.template.source[type].placeholder, + browseURI: this._config.template.source[type].browseURI, icons : this._config.template.icons, username : this._config.username }; - var build = JX.Prefab.buildTokenizer(tokenizerConfig); + var build = JX.Prefab.newTokenizerFromTemplate( + this._config.template.markup, + tokenizerConfig); build.tokenizer.start(); return [ - template, + build.node, function() { return build.tokenizer.getTokens(); }, diff --git a/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js b/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js index 6b7768615f..5cf568ce2c 100644 --- a/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js +++ b/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js @@ -136,18 +136,14 @@ JX.behavior('maniphest-batch-editor', function(config) { }); function build_tokenizer(tconfig) { - var template = JX.$N('div', JX.$H(config.tokenizerTemplate)).firstChild; - template.id = ''; - - var build_config = JX.copy({}, tconfig); - build_config.root = template; - - var built = JX.Prefab.buildTokenizer(build_config); + var built = JX.Prefab.newTokenizerFromTemplate( + config.tokenizerTemplate, + JX.copy({}, tconfig)); built.tokenizer.start(); return { object: built.tokenizer, - template: template + template: built.node }; } diff --git a/webroot/rsrc/js/application/policy/behavior-policy-rule-editor.js b/webroot/rsrc/js/application/policy/behavior-policy-rule-editor.js index 3da2cdad5c..fd790644a1 100644 --- a/webroot/rsrc/js/application/policy/behavior-policy-rule-editor.js +++ b/webroot/rsrc/js/application/policy/behavior-policy-rule-editor.js @@ -118,17 +118,20 @@ JX.behavior('policy-rule-editor', function(config) { switch (type) { case 'tokenizer': - node = JX.$H(template.markup).getNode(); - node.id = ''; - var options = { - root: node, src: template.uri, placeholder: template.placeholder, + browseURI: template.browseURI, limit: template.limit }; - var tokenizer = JX.Prefab.buildTokenizer(options).tokenizer; + var build = JX.Prefab.newTokenizerFromTemplate( + template.markup, + options); + + node = build.node; + + var tokenizer = build.tokenizer; tokenizer.start(); get_fn = function() { return JX.keys(tokenizer.getTokens()); }; diff --git a/webroot/rsrc/js/core/Prefab.js b/webroot/rsrc/js/core/Prefab.js index 70e7e5946e..5856322fd3 100644 --- a/webroot/rsrc/js/core/Prefab.js +++ b/webroot/rsrc/js/core/Prefab.js @@ -31,6 +31,17 @@ JX.install('Prefab', { return select; }, + newTokenizerFromTemplate: function(markup, config) { + var template = JX.$H(markup).getFragment().firstChild; + var container = JX.DOM.find(template, 'div', 'tokenizer-container'); + + container.id = ''; + config.root = container; + + var build = JX.Prefab.buildTokenizer(config); + build.node = template; + return build; + }, /** * Build a Phabricator tokenizer out of a configuration with application