@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 AphrontDialogView
4 extends AphrontView
5 implements AphrontResponseProducerInterface {
6
7 private $title;
8 private $shortTitle;
9 private $submitButton;
10 private $cancelURI;
11 private $cancelText = 'Cancel';
12 private $submitURI;
13 private $hidden = array();
14 private $class;
15 private $renderAsForm = true;
16 private $formID;
17 private $footers = array();
18 private $isStandalone;
19 private $method = 'POST';
20 private $disableWorkflowOnSubmit;
21 private $disableWorkflowOnCancel;
22 private $width = 'default';
23 private $errors = array();
24 private $flush;
25 private $validationException;
26 private $objectList;
27 private $resizeX;
28 private $resizeY;
29
30
31 const WIDTH_DEFAULT = 'default';
32 const WIDTH_FORM = 'form';
33 const WIDTH_FULL = 'full';
34
35 public function setMethod($method) {
36 $this->method = $method;
37 return $this;
38 }
39
40 public function setIsStandalone($is_standalone) {
41 $this->isStandalone = $is_standalone;
42 return $this;
43 }
44
45 public function setErrors(array $errors) {
46 $this->errors = $errors;
47 return $this;
48 }
49
50 public function getIsStandalone() {
51 return $this->isStandalone;
52 }
53
54 /**
55 * Set the URI associated to the Submit Button
56 *
57 * If you want a normal link and not any form submission,
58 * see also: setDisableWorkflowOnSubmit(false).
59 *
60 * @param string $uri
61 * @return self
62 */
63 public function setSubmitURI($uri) {
64 $this->submitURI = $uri;
65 return $this;
66 }
67
68 public function setTitle($title) {
69 $this->title = $title;
70 return $this;
71 }
72
73 public function getTitle() {
74 return $this->title;
75 }
76
77 public function setShortTitle($short_title) {
78 $this->shortTitle = $short_title;
79 return $this;
80 }
81
82 public function getShortTitle() {
83 return $this->shortTitle;
84 }
85
86 public function setResizeY($resize_y) {
87 $this->resizeY = $resize_y;
88 return $this;
89 }
90
91 public function getResizeY() {
92 return $this->resizeY;
93 }
94
95 public function setResizeX($resize_x) {
96 $this->resizeX = $resize_x;
97 return $this;
98 }
99
100 public function getResizeX() {
101 return $this->resizeX;
102 }
103
104 /**
105 * Add a Submit Button and specify its text
106 *
107 * If you want to associate an URI for this Button,
108 * see also: setSubmitURI().
109 *
110 * @param string $text Text shown for that button
111 * @return self
112 */
113 public function addSubmitButton($text = null) {
114 if (!$text) {
115 $text = pht('Okay');
116 }
117
118 $this->submitButton = $text;
119 return $this;
120 }
121
122 public function addCancelButton($uri, $text = null) {
123 if (!$text) {
124 $text = pht('Cancel');
125 }
126
127 $this->cancelURI = $uri;
128 $this->cancelText = $text;
129 return $this;
130 }
131
132 public function addFooter($footer) {
133 $this->footers[] = $footer;
134 return $this;
135 }
136
137 public function addHiddenInput($key, $value) {
138 if (is_array($value)) {
139 foreach ($value as $hidden_key => $hidden_value) {
140 $this->hidden[] = array($key.'['.$hidden_key.']', $hidden_value);
141 }
142 } else {
143 $this->hidden[] = array($key, $value);
144 }
145 return $this;
146 }
147
148 public function setClass($class) {
149 $this->class = $class;
150 return $this;
151 }
152
153 public function setFlush($flush) {
154 $this->flush = $flush;
155 return $this;
156 }
157
158 public function setRenderDialogAsDiv() {
159 // TODO: This API is awkward.
160 $this->renderAsForm = false;
161 return $this;
162 }
163
164 public function setFormID($id) {
165 $this->formID = $id;
166 return $this;
167 }
168
169 public function setWidth($width) {
170 $this->width = $width;
171 return $this;
172 }
173
174 public function setObjectList(PHUIObjectItemListView $list) {
175 $this->objectList = true;
176 $box = id(new PHUIObjectBoxView())
177 ->setObjectList($list);
178 return $this->appendChild($box);
179 }
180
181 public function appendRemarkup($remarkup) {
182 $viewer = $this->getViewer();
183 $view = new PHUIRemarkupView($viewer, $remarkup);
184
185 $view_tag = phutil_tag(
186 'div',
187 array(
188 'class' => 'aphront-dialog-view-paragraph',
189 ),
190 $view);
191
192 return $this->appendChild($view_tag);
193 }
194
195 public function appendParagraph($paragraph) {
196 return $this->appendParagraphTag($paragraph);
197 }
198
199 public function appendCommand($command) {
200 $command_tag = phutil_tag('tt', array(), $command);
201 return $this->appendParagraphTag(
202 $command_tag,
203 'aphront-dialog-view-command');
204 }
205
206 private function appendParagraphTag($content, $classes = null) {
207 if ($classes) {
208 $classes = (array)$classes;
209 } else {
210 $classes = array();
211 }
212
213 array_unshift($classes, 'aphront-dialog-view-paragraph');
214
215 $paragraph_tag = phutil_tag(
216 'p',
217 array(
218 'class' => implode(' ', $classes),
219 ),
220 $content);
221
222 return $this->appendChild($paragraph_tag);
223 }
224
225
226 public function appendList(array $items) {
227 $listitems = array();
228 foreach ($items as $item) {
229 $listitems[] = phutil_tag(
230 'li',
231 array(
232 'class' => 'remarkup-list-item',
233 ),
234 $item);
235 }
236 return $this->appendChild(
237 phutil_tag(
238 'ul',
239 array(
240 'class' => 'remarkup-list',
241 ),
242 $listitems));
243 }
244
245 public function appendForm(AphrontFormView $form) {
246 return $this->appendChild($form->buildLayoutView());
247 }
248
249 /**
250 * Enable or Disable a Workflow on Submit
251 *
252 * For example, if your Submit Button should be a normal link,
253 * without activating any Workflow, you can set false.
254 * @param bool $disable_workflow_on_submit
255 * @return self
256 */
257 public function setDisableWorkflowOnSubmit($disable_workflow_on_submit) {
258 $this->disableWorkflowOnSubmit = $disable_workflow_on_submit;
259 return $this;
260 }
261
262 public function getDisableWorkflowOnSubmit() {
263 return $this->disableWorkflowOnSubmit;
264 }
265
266 public function setDisableWorkflowOnCancel($disable_workflow_on_cancel) {
267 $this->disableWorkflowOnCancel = $disable_workflow_on_cancel;
268 return $this;
269 }
270
271 public function getDisableWorkflowOnCancel() {
272 return $this->disableWorkflowOnCancel;
273 }
274
275 public function setValidationException(
276 ?PhabricatorApplicationTransactionValidationException $ex = null) {
277 $this->validationException = $ex;
278 return $this;
279 }
280
281 public function render() {
282 require_celerity_resource('aphront-dialog-view-css');
283
284 $buttons = array();
285 if ($this->submitButton) {
286 $meta = array();
287 if ($this->disableWorkflowOnSubmit) {
288 $meta['disableWorkflow'] = true;
289 }
290
291 $buttons[] = javelin_tag(
292 'button',
293 array(
294 'name' => '__submit__',
295 'sigil' => '__default__',
296 'type' => 'submit',
297 'meta' => $meta,
298 ),
299 $this->submitButton);
300 }
301
302 if ($this->cancelURI) {
303 $meta = array();
304 if ($this->disableWorkflowOnCancel) {
305 $meta['disableWorkflow'] = true;
306 }
307
308 $buttons[] = javelin_tag(
309 'a',
310 array(
311 'href' => $this->cancelURI,
312 'class' => 'button button-grey',
313 'name' => '__cancel__',
314 'sigil' => 'jx-workflow-button',
315 'meta' => $meta,
316 ),
317 $this->cancelText);
318 }
319
320 if (!$this->hasViewer()) {
321 throw new Exception(
322 pht(
323 'You must call %s when rendering an %s.',
324 'setViewer()',
325 self::class));
326 }
327
328 $classes = array();
329 $classes[] = 'aphront-dialog-view';
330 $classes[] = $this->class;
331 if ($this->flush) {
332 $classes[] = 'aphront-dialog-flush';
333 }
334
335 switch ($this->width) {
336 case self::WIDTH_FORM:
337 case self::WIDTH_FULL:
338 $classes[] = 'aphront-dialog-view-width-'.$this->width;
339 break;
340 case self::WIDTH_DEFAULT:
341 break;
342 default:
343 throw new Exception(
344 pht(
345 "Unknown dialog width '%s'!",
346 $this->width));
347 }
348
349 if ($this->isStandalone) {
350 $classes[] = 'aphront-dialog-view-standalone';
351 }
352
353 if ($this->objectList) {
354 $classes[] = 'aphront-dialog-object-list';
355 }
356
357 $attributes = array(
358 'class' => implode(' ', $classes),
359 'sigil' => 'jx-dialog',
360 'role' => 'dialog',
361 );
362
363 $form_attributes = array(
364 'action' => $this->submitURI,
365 'method' => $this->method,
366 'id' => $this->formID,
367 );
368
369 $hidden_inputs = array();
370 $hidden_inputs[] = phutil_tag(
371 'input',
372 array(
373 'type' => 'hidden',
374 'name' => '__dialog__',
375 'value' => '1',
376 ));
377
378 foreach ($this->hidden as $desc) {
379 list($key, $value) = $desc;
380 $hidden_inputs[] = javelin_tag(
381 'input',
382 array(
383 'type' => 'hidden',
384 'name' => $key,
385 'value' => $value,
386 'sigil' => 'aphront-dialog-application-input',
387 ));
388 }
389
390 if (!$this->renderAsForm) {
391 $buttons = array(
392 phabricator_form(
393 $this->getViewer(),
394 $form_attributes,
395 array_merge($hidden_inputs, $buttons)),
396 );
397 }
398
399 $children = $this->renderChildren();
400
401 $errors = $this->errors;
402
403 $ex = $this->validationException;
404 $exception_errors = null;
405 if ($ex) {
406 foreach ($ex->getErrors() as $error) {
407 $errors[] = $error->getMessage();
408 }
409 }
410
411 if ($errors) {
412 $children = array(
413 id(new PHUIInfoView())->setErrors($errors),
414 $children,
415 );
416 }
417
418 $header = new PHUIHeaderView();
419 $header->setHeader($this->title);
420
421 $footer = null;
422 if ($this->footers) {
423 $footer = phutil_tag(
424 'div',
425 array(
426 'class' => 'aphront-dialog-foot',
427 ),
428 $this->footers);
429 }
430
431 $resize = null;
432 if ($this->resizeX || $this->resizeY) {
433 $resize = javelin_tag(
434 'div',
435 array(
436 'class' => 'aphront-dialog-resize',
437 'sigil' => 'jx-dialog-resize',
438 'meta' => array(
439 'resizeX' => $this->resizeX,
440 'resizeY' => $this->resizeY,
441 ),
442 ));
443 }
444
445 $tail = null;
446 if ($buttons || $footer) {
447 $tail = phutil_tag(
448 'div',
449 array(
450 'class' => 'aphront-dialog-tail grouped',
451 ),
452 array(
453 $buttons,
454 $footer,
455 $resize,
456 ));
457 }
458
459 $content = array(
460 phutil_tag(
461 'div',
462 array(
463 'class' => 'aphront-dialog-head',
464 ),
465 $header),
466 phutil_tag('div',
467 array(
468 'class' => 'aphront-dialog-body grouped',
469 ),
470 $children),
471 $tail,
472 );
473
474 if ($this->renderAsForm) {
475 return phabricator_form(
476 $this->getViewer(),
477 $form_attributes + $attributes,
478 array($hidden_inputs, $content));
479 } else {
480 return javelin_tag(
481 'div',
482 $attributes,
483 $content);
484 }
485 }
486
487
488/* -( AphrontResponseProducerInterface )----------------------------------- */
489
490
491 public function produceAphrontResponse() {
492 return id(new AphrontDialogResponse())
493 ->setDialog($this);
494 }
495
496}