@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
at upstream/main 496 lines 11 kB view raw
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}