2011-01-16 13:51:39 -08:00
|
|
|
<?php
|
|
|
|
|
2015-09-01 15:52:52 -07:00
|
|
|
final class AphrontDialogView
|
|
|
|
extends AphrontView
|
|
|
|
implements AphrontResponseProducerInterface {
|
2011-01-16 13:51:39 -08:00
|
|
|
|
|
|
|
private $title;
|
2014-03-21 14:40:05 -07:00
|
|
|
private $shortTitle;
|
2011-01-16 13:51:39 -08:00
|
|
|
private $submitButton;
|
|
|
|
private $cancelURI;
|
2011-05-28 11:36:00 -07:00
|
|
|
private $cancelText = 'Cancel';
|
2011-01-16 13:51:39 -08:00
|
|
|
private $submitURI;
|
2011-02-01 16:42:36 -08:00
|
|
|
private $hidden = array();
|
2011-02-16 22:14:09 -08:00
|
|
|
private $class;
|
2011-02-17 14:32:01 -08:00
|
|
|
private $renderAsForm = true;
|
|
|
|
private $formID;
|
2013-06-16 16:31:14 -07:00
|
|
|
private $footers = array();
|
|
|
|
private $isStandalone;
|
2013-06-20 14:13:53 -07:00
|
|
|
private $method = 'POST';
|
2014-03-12 18:17:11 -07:00
|
|
|
private $disableWorkflowOnSubmit;
|
|
|
|
private $disableWorkflowOnCancel;
|
|
|
|
private $width = 'default';
|
2014-06-12 13:22:12 -07:00
|
|
|
private $errors = array();
|
2014-06-07 21:43:04 -07:00
|
|
|
private $flush;
|
2014-06-12 13:22:12 -07:00
|
|
|
private $validationException;
|
2015-10-27 19:32:35 +00:00
|
|
|
private $objectList;
|
2016-06-20 17:29:56 -07:00
|
|
|
private $resizeX;
|
|
|
|
private $resizeY;
|
2014-06-12 13:22:12 -07:00
|
|
|
|
2013-06-20 14:13:53 -07:00
|
|
|
|
2014-03-12 18:17:11 -07:00
|
|
|
const WIDTH_DEFAULT = 'default';
|
|
|
|
const WIDTH_FORM = 'form';
|
|
|
|
const WIDTH_FULL = 'full';
|
2013-06-20 14:13:53 -07:00
|
|
|
|
|
|
|
public function setMethod($method) {
|
|
|
|
$this->method = $method;
|
|
|
|
return $this;
|
|
|
|
}
|
2013-06-16 16:31:14 -07:00
|
|
|
|
|
|
|
public function setIsStandalone($is_standalone) {
|
|
|
|
$this->isStandalone = $is_standalone;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-04-03 11:23:03 -07:00
|
|
|
public function setErrors(array $errors) {
|
|
|
|
$this->errors = $errors;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-06-16 16:31:14 -07:00
|
|
|
public function getIsStandalone() {
|
|
|
|
return $this->isStandalone;
|
|
|
|
}
|
2011-02-01 16:42:36 -08:00
|
|
|
|
2011-01-16 13:51:39 -08:00
|
|
|
public function setSubmitURI($uri) {
|
|
|
|
$this->submitURI = $uri;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setTitle($title) {
|
|
|
|
$this->title = $title;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getTitle() {
|
|
|
|
return $this->title;
|
|
|
|
}
|
|
|
|
|
2014-03-21 14:40:05 -07:00
|
|
|
public function setShortTitle($short_title) {
|
|
|
|
$this->shortTitle = $short_title;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getShortTitle() {
|
|
|
|
return $this->shortTitle;
|
|
|
|
}
|
|
|
|
|
2016-06-20 17:29:56 -07:00
|
|
|
public function setResizeY($resize_y) {
|
|
|
|
$this->resizeY = $resize_y;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getResizeY() {
|
|
|
|
return $this->resizeY;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setResizeX($resize_x) {
|
|
|
|
$this->resizeX = $resize_x;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getResizeX() {
|
|
|
|
return $this->resizeX;
|
|
|
|
}
|
|
|
|
|
2013-03-01 15:37:32 -08:00
|
|
|
public function addSubmitButton($text = null) {
|
|
|
|
if (!$text) {
|
|
|
|
$text = pht('Okay');
|
|
|
|
}
|
|
|
|
|
2011-01-16 13:51:39 -08:00
|
|
|
$this->submitButton = $text;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-03-01 15:37:32 -08:00
|
|
|
public function addCancelButton($uri, $text = null) {
|
|
|
|
if (!$text) {
|
|
|
|
$text = pht('Cancel');
|
|
|
|
}
|
|
|
|
|
2011-01-16 13:51:39 -08:00
|
|
|
$this->cancelURI = $uri;
|
2011-05-28 11:36:00 -07:00
|
|
|
$this->cancelText = $text;
|
2011-01-16 13:51:39 -08:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-06-16 16:31:14 -07:00
|
|
|
public function addFooter($footer) {
|
|
|
|
$this->footers[] = $footer;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-02-01 16:42:36 -08:00
|
|
|
public function addHiddenInput($key, $value) {
|
Improve behavior when user submits a no-op action in Differential
Summary:
See T730 and the slightly-less-pretty version of this in D1398.
When a user takes an action in Differential that has no effect (for instance,
accepting an already-accepted revision), prompt them:
Action Has No Effect
You can not accept this revision because it has already been accepted.
Do you want to post the feedback anyway, as a normal comment?
[Cancel] [Post as Comment]
If they have no comment text, the dialog only says "Cancel".
I think this is probably the best way to balance all the concerns here -- it
might occasionally be a little annoying, but that should be rare, and it should
never be confusing (the current workflow is extremely confusing).
This also fixes the issue where you can add all sorts of CCs who are already
part of the revision, either explicitly or via mentions.
Test Plan:
Posted some has-effect and has-no-effect comments, made different
choices in the dialog, everything seems to work OK?
Reviewers: vrana, btrahan, jungejason
Reviewed By: vrana
CC: aran, vrana
Maniphest Tasks: T730
Differential Revision: https://secure.phabricator.com/D1403
2012-01-14 11:39:22 -08:00
|
|
|
if (is_array($value)) {
|
|
|
|
foreach ($value as $hidden_key => $hidden_value) {
|
|
|
|
$this->hidden[] = array($key.'['.$hidden_key.']', $hidden_value);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$this->hidden[] = array($key, $value);
|
|
|
|
}
|
2011-02-01 16:42:36 -08:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-02-16 22:14:09 -08:00
|
|
|
public function setClass($class) {
|
|
|
|
$this->class = $class;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-06-07 21:43:04 -07:00
|
|
|
public function setFlush($flush) {
|
|
|
|
$this->flush = $flush;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-02-17 14:32:01 -08:00
|
|
|
public function setRenderDialogAsDiv() {
|
|
|
|
// TODO: This API is awkward.
|
|
|
|
$this->renderAsForm = false;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setFormID($id) {
|
|
|
|
$this->formID = $id;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-06-09 15:28:29 -07:00
|
|
|
public function setWidth($width) {
|
|
|
|
$this->width = $width;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-10-27 19:32:35 +00:00
|
|
|
public function setObjectList(PHUIObjectItemListView $list) {
|
|
|
|
$this->objectList = true;
|
|
|
|
$box = id(new PHUIObjectBoxView())
|
|
|
|
->setObjectList($list);
|
|
|
|
return $this->appendChild($box);
|
|
|
|
}
|
|
|
|
|
2019-09-08 09:45:53 -07:00
|
|
|
public function appendRemarkup($remarkup) {
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
$view = new PHUIRemarkupView($viewer, $remarkup);
|
|
|
|
|
|
|
|
$view_tag = phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'aphront-dialog-view-paragraph',
|
|
|
|
),
|
|
|
|
$view);
|
|
|
|
|
|
|
|
return $this->appendChild($view_tag);
|
|
|
|
}
|
|
|
|
|
Improve handling of email verification and "activated" accounts
Summary:
Small step forward which improves existing stuff or lays groudwork for future stuff:
- Currently, to check for email verification, we have to single-query the email address on every page. Instead, denoramlize it into the user object.
- Migrate all the existing users.
- When the user verifies an email, mark them as `isEmailVerified` if the email is their primary email.
- Just make the checks look at the `isEmailVerified` field.
- Add a new check, `isUserActivated()`, to cover email-verified plus disabled. Currently, a non-verified-but-not-disabled user could theoretically use Conduit over SSH, if anyone deployed it. Tighten that up.
- Add an `isApproved` flag, which is always true for now. In a future diff, I want to add a default-on admin approval queue for new accounts, to prevent configuration mistakes. The way it will work is:
- When the queue is enabled, registering users are created with `isApproved = false`.
- Admins are sent an email, "[Phabricator] New User Approval (alincoln)", telling them that a new user is waiting for approval.
- They go to the web UI and approve the user.
- Manually-created accounts are auto-approved.
- The email will have instructions for disabling the queue.
I think this queue will be helpful for new installs and give them peace of mind, and when you go to disable it we have a better opportunity to warn you about exactly what that means.
Generally, I want to improve the default safety of registration, since if you just blindly coast through the path of least resistance right now your install ends up pretty open, and realistically few installs are on VPNs.
Test Plan:
- Ran migration, verified `isEmailVerified` populated correctly.
- Created a new user, checked DB for verified (not verified).
- Verified, checked DB (now verified).
- Used Conduit, People, Diffusion.
Reviewers: btrahan
Reviewed By: btrahan
CC: chad, aran
Differential Revision: https://secure.phabricator.com/D7572
2013-11-12 14:37:04 -08:00
|
|
|
public function appendParagraph($paragraph) {
|
2019-08-02 09:15:06 -07:00
|
|
|
return $this->appendParagraphTag($paragraph);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function appendCommand($command) {
|
|
|
|
$command_tag = phutil_tag('tt', array(), $command);
|
|
|
|
return $this->appendParagraphTag(
|
|
|
|
$command_tag,
|
|
|
|
'aphront-dialog-view-command');
|
|
|
|
}
|
|
|
|
|
|
|
|
private function appendParagraphTag($content, $classes = null) {
|
|
|
|
if ($classes) {
|
|
|
|
$classes = (array)$classes;
|
|
|
|
} else {
|
|
|
|
$classes = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
array_unshift($classes, 'aphront-dialog-view-paragraph');
|
|
|
|
|
|
|
|
$paragraph_tag = phutil_tag(
|
|
|
|
'p',
|
|
|
|
array(
|
|
|
|
'class' => implode(' ', $classes),
|
|
|
|
),
|
|
|
|
$content);
|
|
|
|
|
|
|
|
return $this->appendChild($paragraph_tag);
|
Improve handling of email verification and "activated" accounts
Summary:
Small step forward which improves existing stuff or lays groudwork for future stuff:
- Currently, to check for email verification, we have to single-query the email address on every page. Instead, denoramlize it into the user object.
- Migrate all the existing users.
- When the user verifies an email, mark them as `isEmailVerified` if the email is their primary email.
- Just make the checks look at the `isEmailVerified` field.
- Add a new check, `isUserActivated()`, to cover email-verified plus disabled. Currently, a non-verified-but-not-disabled user could theoretically use Conduit over SSH, if anyone deployed it. Tighten that up.
- Add an `isApproved` flag, which is always true for now. In a future diff, I want to add a default-on admin approval queue for new accounts, to prevent configuration mistakes. The way it will work is:
- When the queue is enabled, registering users are created with `isApproved = false`.
- Admins are sent an email, "[Phabricator] New User Approval (alincoln)", telling them that a new user is waiting for approval.
- They go to the web UI and approve the user.
- Manually-created accounts are auto-approved.
- The email will have instructions for disabling the queue.
I think this queue will be helpful for new installs and give them peace of mind, and when you go to disable it we have a better opportunity to warn you about exactly what that means.
Generally, I want to improve the default safety of registration, since if you just blindly coast through the path of least resistance right now your install ends up pretty open, and realistically few installs are on VPNs.
Test Plan:
- Ran migration, verified `isEmailVerified` populated correctly.
- Created a new user, checked DB for verified (not verified).
- Verified, checked DB (now verified).
- Used Conduit, People, Diffusion.
Reviewers: btrahan
Reviewed By: btrahan
CC: chad, aran
Differential Revision: https://secure.phabricator.com/D7572
2013-11-12 14:37:04 -08:00
|
|
|
}
|
|
|
|
|
2019-08-02 09:15:06 -07:00
|
|
|
|
2015-06-29 12:49:21 -07:00
|
|
|
public function appendList(array $items) {
|
|
|
|
$listitems = array();
|
|
|
|
foreach ($items as $item) {
|
|
|
|
$listitems[] = phutil_tag(
|
|
|
|
'li',
|
|
|
|
array(
|
|
|
|
'class' => 'remarkup-list-item',
|
|
|
|
),
|
|
|
|
$item);
|
|
|
|
}
|
|
|
|
return $this->appendChild(
|
|
|
|
phutil_tag(
|
|
|
|
'ul',
|
|
|
|
array(
|
|
|
|
'class' => 'remarkup-list',
|
|
|
|
),
|
|
|
|
$listitems));
|
|
|
|
}
|
|
|
|
|
2014-10-10 16:57:05 -07:00
|
|
|
public function appendForm(AphrontFormView $form) {
|
|
|
|
return $this->appendChild($form->buildLayoutView());
|
|
|
|
}
|
|
|
|
|
2014-03-12 18:17:11 -07:00
|
|
|
public function setDisableWorkflowOnSubmit($disable_workflow_on_submit) {
|
|
|
|
$this->disableWorkflowOnSubmit = $disable_workflow_on_submit;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getDisableWorkflowOnSubmit() {
|
|
|
|
return $this->disableWorkflowOnSubmit;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setDisableWorkflowOnCancel($disable_workflow_on_cancel) {
|
|
|
|
$this->disableWorkflowOnCancel = $disable_workflow_on_cancel;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getDisableWorkflowOnCancel() {
|
|
|
|
return $this->disableWorkflowOnCancel;
|
|
|
|
}
|
|
|
|
|
2014-06-12 13:22:12 -07:00
|
|
|
public function setValidationException(
|
|
|
|
PhabricatorApplicationTransactionValidationException $ex = null) {
|
|
|
|
$this->validationException = $ex;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-05-20 07:06:07 +10:00
|
|
|
public function render() {
|
2011-01-25 11:31:40 -08:00
|
|
|
require_celerity_resource('aphront-dialog-view-css');
|
2011-01-16 13:51:39 -08:00
|
|
|
|
|
|
|
$buttons = array();
|
|
|
|
if ($this->submitButton) {
|
2014-03-12 18:17:11 -07:00
|
|
|
$meta = array();
|
|
|
|
if ($this->disableWorkflowOnSubmit) {
|
|
|
|
$meta['disableWorkflow'] = true;
|
|
|
|
}
|
|
|
|
|
2013-01-25 12:57:17 -08:00
|
|
|
$buttons[] = javelin_tag(
|
2011-02-04 17:53:14 -08:00
|
|
|
'button',
|
|
|
|
array(
|
|
|
|
'name' => '__submit__',
|
|
|
|
'sigil' => '__default__',
|
2014-03-12 11:26:43 -07:00
|
|
|
'type' => 'submit',
|
2014-03-12 18:17:11 -07:00
|
|
|
'meta' => $meta,
|
2011-02-04 17:53:14 -08:00
|
|
|
),
|
2013-01-25 12:57:17 -08:00
|
|
|
$this->submitButton);
|
2011-01-16 13:51:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->cancelURI) {
|
2014-03-12 18:17:11 -07:00
|
|
|
$meta = array();
|
|
|
|
if ($this->disableWorkflowOnCancel) {
|
|
|
|
$meta['disableWorkflow'] = true;
|
|
|
|
}
|
|
|
|
|
2013-01-25 12:57:17 -08:00
|
|
|
$buttons[] = javelin_tag(
|
2011-01-16 13:51:39 -08:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $this->cancelURI,
|
2017-06-05 20:14:34 +00:00
|
|
|
'class' => 'button button-grey',
|
2011-02-01 16:42:36 -08:00
|
|
|
'name' => '__cancel__',
|
|
|
|
'sigil' => 'jx-workflow-button',
|
2014-03-12 18:17:11 -07:00
|
|
|
'meta' => $meta,
|
2011-01-16 13:51:39 -08:00
|
|
|
),
|
2013-01-25 12:57:17 -08:00
|
|
|
$this->cancelText);
|
2011-01-16 13:51:39 -08:00
|
|
|
}
|
|
|
|
|
2016-03-06 06:26:34 -08:00
|
|
|
if (!$this->hasViewer()) {
|
2011-02-01 16:42:36 -08:00
|
|
|
throw new Exception(
|
2015-05-14 06:50:28 +10:00
|
|
|
pht(
|
|
|
|
'You must call %s when rendering an %s.',
|
2016-03-06 06:26:34 -08:00
|
|
|
'setViewer()',
|
2015-05-14 06:50:28 +10:00
|
|
|
__CLASS__));
|
2011-02-01 16:42:36 -08:00
|
|
|
}
|
2011-02-17 14:32:01 -08:00
|
|
|
|
2015-10-27 19:32:35 +00:00
|
|
|
$classes = array();
|
|
|
|
$classes[] = 'aphront-dialog-view';
|
|
|
|
$classes[] = $this->class;
|
2014-06-07 21:43:04 -07:00
|
|
|
if ($this->flush) {
|
2015-10-27 19:32:35 +00:00
|
|
|
$classes[] = 'aphront-dialog-flush';
|
2014-06-07 21:43:04 -07:00
|
|
|
}
|
2011-02-17 14:32:01 -08:00
|
|
|
|
2011-06-09 15:28:29 -07:00
|
|
|
switch ($this->width) {
|
|
|
|
case self::WIDTH_FORM:
|
2012-12-11 14:01:51 -08:00
|
|
|
case self::WIDTH_FULL:
|
2015-10-27 19:32:35 +00:00
|
|
|
$classes[] = 'aphront-dialog-view-width-'.$this->width;
|
2011-06-09 15:28:29 -07:00
|
|
|
break;
|
|
|
|
case self::WIDTH_DEFAULT:
|
|
|
|
break;
|
|
|
|
default:
|
2015-06-09 23:06:52 +10:00
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
"Unknown dialog width '%s'!",
|
|
|
|
$this->width));
|
2011-06-09 15:28:29 -07:00
|
|
|
}
|
|
|
|
|
2013-06-16 16:31:14 -07:00
|
|
|
if ($this->isStandalone) {
|
2015-10-27 19:32:35 +00:00
|
|
|
$classes[] = 'aphront-dialog-view-standalone';
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->objectList) {
|
|
|
|
$classes[] = 'aphront-dialog-object-list';
|
2013-06-16 16:31:14 -07:00
|
|
|
}
|
|
|
|
|
2011-02-17 14:32:01 -08:00
|
|
|
$attributes = array(
|
2015-10-27 19:32:35 +00:00
|
|
|
'class' => implode(' ', $classes),
|
2011-02-17 14:32:01 -08:00
|
|
|
'sigil' => 'jx-dialog',
|
2016-05-31 12:15:23 -07:00
|
|
|
'role' => 'dialog',
|
2011-02-17 14:32:01 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
$form_attributes = array(
|
|
|
|
'action' => $this->submitURI,
|
2013-06-20 14:13:53 -07:00
|
|
|
'method' => $this->method,
|
2011-02-17 14:32:01 -08:00
|
|
|
'id' => $this->formID,
|
|
|
|
);
|
2011-02-01 16:42:36 -08:00
|
|
|
|
|
|
|
$hidden_inputs = array();
|
2013-02-13 14:50:15 -08:00
|
|
|
$hidden_inputs[] = phutil_tag(
|
|
|
|
'input',
|
|
|
|
array(
|
|
|
|
'type' => 'hidden',
|
|
|
|
'name' => '__dialog__',
|
|
|
|
'value' => '1',
|
|
|
|
));
|
|
|
|
|
2011-02-17 14:32:01 -08:00
|
|
|
foreach ($this->hidden as $desc) {
|
|
|
|
list($key, $value) = $desc;
|
2013-01-25 12:57:17 -08:00
|
|
|
$hidden_inputs[] = javelin_tag(
|
2011-02-01 16:42:36 -08:00
|
|
|
'input',
|
|
|
|
array(
|
|
|
|
'type' => 'hidden',
|
|
|
|
'name' => $key,
|
|
|
|
'value' => $value,
|
2014-10-08 00:01:04 +11:00
|
|
|
'sigil' => 'aphront-dialog-application-input',
|
2011-02-01 16:42:36 -08:00
|
|
|
));
|
|
|
|
}
|
2011-02-16 22:14:09 -08:00
|
|
|
|
2011-02-17 14:32:01 -08:00
|
|
|
if (!$this->renderAsForm) {
|
2015-08-11 22:36:15 +10:00
|
|
|
$buttons = array(
|
|
|
|
phabricator_form(
|
2016-03-06 06:26:34 -08:00
|
|
|
$this->getViewer(),
|
2015-08-11 22:36:15 +10:00
|
|
|
$form_attributes,
|
|
|
|
array_merge($hidden_inputs, $buttons)),
|
2014-10-08 00:01:04 +11:00
|
|
|
);
|
2011-02-17 14:32:01 -08:00
|
|
|
}
|
|
|
|
|
2013-02-13 14:50:15 -08:00
|
|
|
$children = $this->renderChildren();
|
|
|
|
|
2014-06-12 13:22:12 -07:00
|
|
|
$errors = $this->errors;
|
|
|
|
|
|
|
|
$ex = $this->validationException;
|
|
|
|
$exception_errors = null;
|
|
|
|
if ($ex) {
|
|
|
|
foreach ($ex->getErrors() as $error) {
|
|
|
|
$errors[] = $error->getMessage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($errors) {
|
2014-04-03 11:23:03 -07:00
|
|
|
$children = array(
|
2015-03-01 14:45:56 -08:00
|
|
|
id(new PHUIInfoView())->setErrors($errors),
|
2014-10-08 00:01:04 +11:00
|
|
|
$children,
|
|
|
|
);
|
2014-04-03 11:23:03 -07:00
|
|
|
}
|
|
|
|
|
2015-05-18 10:00:15 -07:00
|
|
|
$header = new PHUIHeaderView();
|
|
|
|
$header->setHeader($this->title);
|
2013-04-09 15:50:48 -07:00
|
|
|
|
2013-06-16 16:31:14 -07:00
|
|
|
$footer = null;
|
|
|
|
if ($this->footers) {
|
|
|
|
$footer = phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'aphront-dialog-foot',
|
|
|
|
),
|
|
|
|
$this->footers);
|
|
|
|
}
|
|
|
|
|
2016-06-20 17:29:56 -07:00
|
|
|
$resize = null;
|
|
|
|
if ($this->resizeX || $this->resizeY) {
|
|
|
|
$resize = javelin_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'aphront-dialog-resize',
|
|
|
|
'sigil' => 'jx-dialog-resize',
|
|
|
|
'meta' => array(
|
|
|
|
'resizeX' => $this->resizeX,
|
|
|
|
'resizeY' => $this->resizeY,
|
|
|
|
),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2015-02-19 08:45:37 -08:00
|
|
|
$tail = null;
|
|
|
|
if ($buttons || $footer) {
|
|
|
|
$tail = phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'aphront-dialog-tail grouped',
|
|
|
|
),
|
|
|
|
array(
|
|
|
|
$buttons,
|
|
|
|
$footer,
|
2016-06-20 17:29:56 -07:00
|
|
|
$resize,
|
2015-02-19 08:45:37 -08:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2013-06-16 16:31:14 -07:00
|
|
|
$content = array(
|
|
|
|
phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'aphront-dialog-head',
|
|
|
|
),
|
|
|
|
$header),
|
2013-05-30 08:30:56 -07:00
|
|
|
phutil_tag('div',
|
2013-06-16 16:31:14 -07:00
|
|
|
array(
|
Replace the "Choose Subtype" radio buttons dialog with a simpler "big stuff you click" sort of UI
Summary:
Ref T13222. Fixes T12588. See PHI683. In several cases, we present the user with a choice between multiple major options: Alamnac service types, Drydock blueprint types, Repository VCS types, Herald rule types, etc.
Today, we generally do this with radio buttons and a "Submit" button. This isn't terrible, but often it means users have to click twice (once on the radio; once on submit) when a single click would be sufficient. The radio click target can also be small.
In other cases, we have a container with a link and we'd like to link the entire container: notifications, the `/drydock/` console, etc. We'd like to just link the entire container, but this causes some problems:
- It's not legal to link block eleements like `<a><div> ... </div></a>` and some browsers actually get upset about it.
- We can `<a><span> ... </span></a>` instead, then turn the `<span>` into a block element with CSS -- and this sometimes works, but also has some drawbacks:
- It's not great to do that for screenreaders, since the readable text in the link isn't necessarily very meaningful.
- We can't have any other links inside the element (e.g., details or documentation).
- We can `<form><button> ... </button></form>` instead, but this has its own set of problems:
- You can't right-click to interact with a button in the same way you can with a link.
- Also not great for screenreaders.
Instead, try adding a `linked-container` behavior which just means "when users click this element, pretend they clicked the first link inside it".
This gives us natural HTML (real, legal HTML with actual `<a>` tags) and good screenreader behavior, but allows the effective link target to be visually larger than just the link.
If no issues crop up with this, I'd plan to eventually use this technique in more places (Repositories, Herald, Almanac, Drydock, Notifications menu, etc).
Test Plan:
{F6053035}
- Left-clicked and command-left-clicked the new JS fanciness, got sensible behaviors.
Reviewers: amckinley
Reviewed By: amckinley
Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam
Maniphest Tasks: T13222, T12588
Differential Revision: https://secure.phabricator.com/D19855
2018-12-07 06:04:07 -08:00
|
|
|
'class' => 'aphront-dialog-body grouped',
|
2013-06-16 16:31:14 -07:00
|
|
|
),
|
|
|
|
$children),
|
2015-02-19 08:45:37 -08:00
|
|
|
$tail,
|
2013-06-16 16:31:14 -07:00
|
|
|
);
|
2011-02-17 14:32:01 -08:00
|
|
|
|
|
|
|
if ($this->renderAsForm) {
|
2013-02-13 14:50:15 -08:00
|
|
|
return phabricator_form(
|
2016-03-06 06:26:34 -08:00
|
|
|
$this->getViewer(),
|
2011-02-17 14:32:01 -08:00
|
|
|
$form_attributes + $attributes,
|
2013-02-13 14:50:15 -08:00
|
|
|
array($hidden_inputs, $content));
|
2011-02-17 14:32:01 -08:00
|
|
|
} else {
|
2013-02-13 14:50:15 -08:00
|
|
|
return javelin_tag(
|
2011-02-17 14:32:01 -08:00
|
|
|
'div',
|
|
|
|
$attributes,
|
|
|
|
$content);
|
|
|
|
}
|
2011-01-16 13:51:39 -08:00
|
|
|
}
|
|
|
|
|
2015-09-01 15:52:52 -07:00
|
|
|
|
|
|
|
/* -( AphrontResponseProducerInterface )----------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function produceAphrontResponse() {
|
|
|
|
return id(new AphrontDialogResponse())
|
|
|
|
->setDialog($this);
|
|
|
|
}
|
|
|
|
|
2011-01-16 13:51:39 -08:00
|
|
|
}
|