@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class AphrontFormTokenizerControl extends AphrontFormControl {
4
5 private $datasource;
6 private $disableBehavior;
7 private $limit;
8 private $placeholder;
9 private $handles;
10 private $initialValue;
11
12 public function setDatasource(PhabricatorTypeaheadDatasource $datasource) {
13 $this->datasource = $datasource;
14 return $this;
15 }
16
17 public function setDisableBehavior($disable) {
18 $this->disableBehavior = $disable;
19 return $this;
20 }
21
22 protected function getCustomControlClass() {
23 return 'aphront-form-control-tokenizer';
24 }
25
26 public function setLimit($limit) {
27 $this->limit = $limit;
28 return $this;
29 }
30
31 public function setPlaceholder($placeholder) {
32 $this->placeholder = $placeholder;
33 return $this;
34 }
35
36 public function setInitialValue(array $initial_value) {
37 $this->initialValue = $initial_value;
38 return $this;
39 }
40
41 public function getInitialValue() {
42 return $this->initialValue;
43 }
44
45 public function willRender() {
46 // Load the handles now so we'll get a bulk load later on when we actually
47 // render them.
48 $this->loadHandles();
49 }
50
51 protected function renderInput() {
52 $name = $this->getName();
53
54 $handles = $this->loadHandles();
55 $handles = iterator_to_array($handles);
56
57 if ($this->getID()) {
58 $id = $this->getID();
59 } else {
60 $id = celerity_generate_unique_node_id();
61 }
62
63 $datasource = $this->datasource;
64 if (!$datasource) {
65 throw new Exception(
66 pht('You must set a datasource to use a TokenizerControl.'));
67 }
68 $datasource->setViewer($this->getUser());
69
70 $placeholder = null;
71 if (!phutil_nonempty_string($this->placeholder)) {
72 $placeholder = $datasource->getPlaceholderText();
73 }
74
75 $values = nonempty($this->getValue(), array());
76 $tokens = $datasource->renderTokens($values);
77
78 foreach ($tokens as $token) {
79 $token->setInputName($this->getName());
80 }
81
82 $template = id(new AphrontTokenizerTemplateView())
83 ->setName($name)
84 ->setID($id)
85 ->setValue($tokens);
86
87 $initial_value = $this->getInitialValue();
88 if ($initial_value !== null) {
89 $template->setInitialValue($initial_value);
90 }
91
92 $username = null;
93 if ($this->hasViewer()) {
94 $username = $this->getViewer()->getUsername();
95 }
96
97 $datasource_uri = $datasource->getDatasourceURI();
98 $browse_uri = $datasource->getBrowseURI();
99 if ($browse_uri) {
100 $template->setBrowseURI($browse_uri);
101 }
102
103 if (!$this->disableBehavior) {
104 Javelin::initBehavior('aphront-basic-tokenizer', array(
105 'id' => $id,
106 'src' => $datasource_uri,
107 'value' => mpull($tokens, 'getValue', 'getKey'),
108 'icons' => mpull($tokens, 'getIcon', 'getKey'),
109 'types' => mpull($tokens, 'getTokenType', 'getKey'),
110 'colors' => mpull($tokens, 'getColor', 'getKey'),
111 'availabilityColors' => mpull(
112 $tokens,
113 'getAvailabilityColor',
114 'getKey'),
115 'limit' => $this->limit,
116 'username' => $username,
117 'placeholder' => $placeholder,
118 'browseURI' => $browse_uri,
119 'disabled' => $this->getDisabled(),
120 ));
121 }
122
123 return $template->render();
124 }
125
126 private function loadHandles() {
127 if ($this->handles === null) {
128 $viewer = $this->getUser();
129 if (!$viewer) {
130 throw new Exception(
131 pht(
132 'Call %s before rendering tokenizers. '.
133 'Use %s on %s to do this easily.',
134 'setUser()',
135 'appendControl()',
136 'AphrontFormView'));
137 }
138
139 $values = nonempty($this->getValue(), array());
140
141 $phids = array();
142 foreach ($values as $value) {
143 if (!PhabricatorTypeaheadDatasource::isFunctionToken($value)) {
144 $phids[] = $value;
145 }
146 }
147
148 $this->handles = $viewer->loadHandles($phids);
149 }
150
151 return $this->handles;
152 }
153
154}