diff --git a/src/applications/conpherence/controller/ConpherenceNewController.php b/src/applications/conpherence/controller/ConpherenceNewController.php index dad9a95608..1a600a7fee 100644 --- a/src/applications/conpherence/controller/ConpherenceNewController.php +++ b/src/applications/conpherence/controller/ConpherenceNewController.php @@ -1,100 +1,101 @@ getRequest(); $user = $request->getUser(); $title = pht('New Message'); $participants = array(); $participant_prefill = null; $message = ''; $e_participants = null; $e_message = null; // this comes from ajax requests from all over. should be a single phid. if ($request->isFormPost()) { $participants = $request->getArr('participants'); $message = $request->getStr('message'); list($error_codes, $conpherence) = ConpherenceEditor::createConpherence( $user, $participants, $conpherence_title = null, $message, PhabricatorContentSource::newFromRequest($request)); if ($error_codes) { foreach ($error_codes as $error_code) { switch ($error_code) { case ConpherenceEditor::ERROR_EMPTY_MESSAGE: $e_message = true; break; case ConpherenceEditor::ERROR_EMPTY_PARTICIPANTS: $e_participants = true; break; } } } else { $uri = $this->getApplicationURI($conpherence->getID()); return id(new AphrontRedirectResponse()) ->setURI($uri); } } else { $participant_prefill = $request->getStr('participant'); if ($participant_prefill) { $participants[] = $participant_prefill; } } $participant_handles = array(); if ($participants) { $participant_handles = id(new PhabricatorHandleQuery()) ->setViewer($user) ->withPHIDs($participants) ->execute(); } $submit_uri = $this->getApplicationURI('new/'); $cancel_uri = $this->getApplicationURI(); // TODO - we can get a better cancel_uri once we get better at crazy // ajax jonx T2086 if ($participant_prefill) { $handle = $participant_handles[$participant_prefill]; $cancel_uri = $handle->getURI(); } $dialog = id(new AphrontDialogView()) ->setWidth(AphrontDialogView::WIDTH_FORM) ->setUser($user) ->setTitle($title) ->addCancelButton($cancel_uri) ->addSubmitButton(pht('Send Message')); $form = id(new PHUIFormLayoutView()) ->setUser($user) ->setFullWidth(true) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('participants') ->setValue($participant_handles) ->setUser($user) ->setDatasource(new PhabricatorPeopleDatasource()) ->setLabel(pht('To')) ->setError($e_participants)) ->appendChild( id(new PhabricatorRemarkupControl()) - ->setName('message') - ->setValue($message) - ->setLabel(pht('Message')) - ->setError($e_message)); + ->setUser($user) + ->setName('message') + ->setValue($message) + ->setLabel(pht('Message')) + ->setError($e_message)); $dialog->appendChild($form); return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/applications/differential/customfield/DifferentialRevertPlanField.php b/src/applications/differential/customfield/DifferentialRevertPlanField.php index 8934bc01cb..6b159d9d86 100644 --- a/src/applications/differential/customfield/DifferentialRevertPlanField.php +++ b/src/applications/differential/customfield/DifferentialRevertPlanField.php @@ -1,150 +1,151 @@ getFieldName(); } public function getStyleForPropertyView() { return 'block'; } public function getIconForPropertyView() { return PHUIPropertyListView::ICON_TESTPLAN; } public function renderPropertyViewValue(array $handles) { if (!strlen($this->getValue())) { return null; } return PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff()) ->setPreserveLinebreaks(true) ->setContent($this->getValue()), 'default', $this->getViewer()); } public function shouldAppearInGlobalSearch() { return true; } public function updateAbstractDocument( PhabricatorSearchAbstractDocument $document) { if (strlen($this->getValue())) { $document->addField('rvrt', $this->getValue()); } } public function shouldAppearInEditView() { return true; } public function shouldAppearInApplicationTransactions() { return true; } public function getOldValueForApplicationTransactions() { return $this->getValue(); } public function getNewValueForApplicationTransactions() { return $this->getValue(); } public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getStr($this->getFieldKey())); } public function renderEditControl(array $handles) { return id(new PhabricatorRemarkupControl()) + ->setUser($this->getViewer()) ->setName($this->getFieldKey()) ->setValue($this->getValue()) ->setLabel($this->getFieldName()); } public function getApplicationTransactionTitle( PhabricatorApplicationTransaction $xaction) { $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the revert plan for this revision.', $xaction->renderHandleLink($author_phid)); } public function getApplicationTransactionTitleForFeed( PhabricatorApplicationTransaction $xaction, PhabricatorFeedStory $story) { $object_phid = $xaction->getObjectPHID(); $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the revert plan for %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid)); } public function getApplicationTransactionHasChangeDetails( PhabricatorApplicationTransaction $xaction) { return true; } public function getApplicationTransactionChangeDetails( PhabricatorApplicationTransaction $xaction, PhabricatorUser $viewer) { return $xaction->renderTextCorpusChangeDetails( $viewer, $xaction->getOldValue(), $xaction->getNewValue()); } public function getApplicationTransactionRemarkupBlocks( PhabricatorApplicationTransaction $xaction) { return array($xaction->getNewValue()); } public function shouldAppearInCommitMessage() { return true; } public function renderCommitMessageValue(array $handles) { return $this->getValue(); } public function shouldAppearInConduitDictionary() { return true; } } diff --git a/src/applications/differential/customfield/DifferentialSummaryField.php b/src/applications/differential/customfield/DifferentialSummaryField.php index 8498ae5234..f0f06341fc 100644 --- a/src/applications/differential/customfield/DifferentialSummaryField.php +++ b/src/applications/differential/customfield/DifferentialSummaryField.php @@ -1,171 +1,172 @@ getID()) { return null; } return $revision->getSummary(); } protected function writeValueToRevision( DifferentialRevision $revision, $value) { $revision->setSummary($value); } public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getStr($this->getFieldKey())); } public function renderEditControl(array $handles) { return id(new PhabricatorRemarkupControl()) + ->setUser($this->getViewer()) ->setName($this->getFieldKey()) ->setValue($this->getValue()) ->setError($this->getFieldError()) ->setLabel($this->getFieldName()); } public function getApplicationTransactionTitle( PhabricatorApplicationTransaction $xaction) { $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the summary for this revision.', $xaction->renderHandleLink($author_phid)); } public function getApplicationTransactionTitleForFeed( PhabricatorApplicationTransaction $xaction, PhabricatorFeedStory $story) { $object_phid = $xaction->getObjectPHID(); $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the summary for %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid)); } public function getApplicationTransactionHasChangeDetails( PhabricatorApplicationTransaction $xaction) { return true; } public function getApplicationTransactionChangeDetails( PhabricatorApplicationTransaction $xaction, PhabricatorUser $viewer) { return $xaction->renderTextCorpusChangeDetails( $viewer, $xaction->getOldValue(), $xaction->getNewValue()); } public function shouldHideInApplicationTransactions( PhabricatorApplicationTransaction $xaction) { return ($xaction->getOldValue() === null); } public function shouldAppearInGlobalSearch() { return true; } public function updateAbstractDocument( PhabricatorSearchAbstractDocument $document) { if (strlen($this->getValue())) { $document->addField('body', $this->getValue()); } } public function shouldAppearInPropertyView() { return true; } public function renderPropertyViewLabel() { return $this->getFieldName(); } public function getStyleForPropertyView() { return 'block'; } public function getIconForPropertyView() { return PHUIPropertyListView::ICON_SUMMARY; } public function renderPropertyViewValue(array $handles) { if (!strlen($this->getValue())) { return null; } return PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff()) ->setPreserveLinebreaks(true) ->setContent($this->getValue()), 'default', $this->getViewer()); } public function getApplicationTransactionRemarkupBlocks( PhabricatorApplicationTransaction $xaction) { return array($xaction->getNewValue()); } public function shouldAppearInCommitMessage() { return true; } public function shouldAppearInCommitMessageTemplate() { return true; } public function shouldOverwriteWhenCommitMessageIsEdited() { return true; } public function shouldAppearInTransactionMail() { return true; } public function updateTransactionMailBody( PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { if (!$editor->getIsNewObject()) { return; } $summary = $this->getValue(); if (!strlen(trim($summary))) { return; } $body->addTextSection(pht('REVISION SUMMARY'), $summary); } } diff --git a/src/applications/differential/customfield/DifferentialTestPlanField.php b/src/applications/differential/customfield/DifferentialTestPlanField.php index efc3bfc1a0..aef7937330 100644 --- a/src/applications/differential/customfield/DifferentialTestPlanField.php +++ b/src/applications/differential/customfield/DifferentialTestPlanField.php @@ -1,202 +1,203 @@ getID()) { return null; } return $revision->getTestPlan(); } protected function writeValueToRevision( DifferentialRevision $revision, $value) { $revision->setTestPlan($value); } protected function isCoreFieldRequired() { return PhabricatorEnv::getEnvConfig('differential.require-test-plan-field'); } public function canDisableField() { return true; } protected function getCoreFieldRequiredErrorString() { return pht( 'You must provide a test plan. Describe the actions you performed '. 'to verify the behavior of this change.'); } public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getStr($this->getFieldKey())); } public function renderEditControl(array $handles) { return id(new PhabricatorRemarkupControl()) + ->setUser($this->getViewer()) ->setName($this->getFieldKey()) ->setValue($this->getValue()) ->setError($this->getFieldError()) ->setLabel($this->getFieldName()); } public function getApplicationTransactionTitle( PhabricatorApplicationTransaction $xaction) { $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the test plan for this revision.', $xaction->renderHandleLink($author_phid)); } public function getApplicationTransactionTitleForFeed( PhabricatorApplicationTransaction $xaction, PhabricatorFeedStory $story) { $object_phid = $xaction->getObjectPHID(); $author_phid = $xaction->getAuthorPHID(); $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); return pht( '%s updated the test plan for %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid)); } public function getApplicationTransactionHasChangeDetails( PhabricatorApplicationTransaction $xaction) { return true; } public function getApplicationTransactionChangeDetails( PhabricatorApplicationTransaction $xaction, PhabricatorUser $viewer) { return $xaction->renderTextCorpusChangeDetails( $viewer, $xaction->getOldValue(), $xaction->getNewValue()); } public function shouldHideInApplicationTransactions( PhabricatorApplicationTransaction $xaction) { return ($xaction->getOldValue() === null); } public function shouldAppearInGlobalSearch() { return true; } public function updateAbstractDocument( PhabricatorSearchAbstractDocument $document) { if (strlen($this->getValue())) { $document->addField('plan', $this->getValue()); } } public function shouldAppearInPropertyView() { return true; } public function renderPropertyViewLabel() { return $this->getFieldName(); } public function getStyleForPropertyView() { return 'block'; } public function getIconForPropertyView() { return PHUIPropertyListView::ICON_TESTPLAN; } public function renderPropertyViewValue(array $handles) { if (!strlen($this->getValue())) { return null; } return PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff()) ->setPreserveLinebreaks(true) ->setContent($this->getValue()), 'default', $this->getViewer()); } public function getApplicationTransactionRemarkupBlocks( PhabricatorApplicationTransaction $xaction) { return array($xaction->getNewValue()); } public function shouldAppearInCommitMessage() { return true; } public function shouldAppearInCommitMessageTemplate() { return true; } public function shouldOverwriteWhenCommitMessageIsEdited() { return true; } public function getCommitMessageLabels() { return array( 'Test Plan', 'Testplan', 'Tested', 'Tests', ); } public function validateCommitMessageValue($value) { if (!strlen($value) && $this->isCoreFieldRequired()) { throw new DifferentialFieldValidationException( $this->getCoreFieldRequiredErrorString()); } } public function shouldAppearInTransactionMail() { return true; } public function updateTransactionMailBody( PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { if (!$editor->getIsNewObject()) { return; } $test_plan = $this->getValue(); if (!strlen(trim($test_plan))) { return; } $body->addTextSection(pht('TEST PLAN'), $test_plan); } } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php index 4457df8d23..d29aeb0be6 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryEditBasicController.php @@ -1,171 +1,172 @@ getRequest(); $user = $request->getUser(); $drequest = $this->diffusionRequest; $repository = $drequest->getRepository(); $repository = id(new PhabricatorRepositoryQuery()) ->setViewer($user) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->needProjectPHIDs(true) ->withIDs(array($repository->getID())) ->executeOne(); if (!$repository) { return new Aphront404Response(); } $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); $v_name = $repository->getName(); $v_desc = $repository->getDetail('description'); $v_clone_name = $repository->getDetail('clone-name'); $e_name = true; $errors = array(); if ($request->isFormPost()) { $v_name = $request->getStr('name'); $v_desc = $request->getStr('description'); $v_projects = $request->getArr('projectPHIDs'); if ($repository->isHosted()) { $v_clone_name = $request->getStr('cloneName'); } if (!strlen($v_name)) { $e_name = pht('Required'); $errors[] = pht('Repository name is required.'); } else { $e_name = null; } if (!$errors) { $xactions = array(); $template = id(new PhabricatorRepositoryTransaction()); $type_name = PhabricatorRepositoryTransaction::TYPE_NAME; $type_desc = PhabricatorRepositoryTransaction::TYPE_DESCRIPTION; $type_edge = PhabricatorTransactions::TYPE_EDGE; $type_clone_name = PhabricatorRepositoryTransaction::TYPE_CLONE_NAME; $xactions[] = id(clone $template) ->setTransactionType($type_name) ->setNewValue($v_name); $xactions[] = id(clone $template) ->setTransactionType($type_desc) ->setNewValue($v_desc); $xactions[] = id(clone $template) ->setTransactionType($type_clone_name) ->setNewValue($v_clone_name); $xactions[] = id(clone $template) ->setTransactionType($type_edge) ->setMetadataValue( 'edge:type', PhabricatorProjectObjectHasProjectEdgeType::EDGECONST) ->setNewValue( array( '=' => array_fuse($v_projects), )); id(new PhabricatorRepositoryEditor()) ->setContinueOnNoEffect(true) ->setContentSourceFromRequest($request) ->setActor($user) ->applyTransactions($repository, $xactions); return id(new AphrontRedirectResponse())->setURI($edit_uri); } } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Edit Basics')); $title = pht('Edit %s', $repository->getName()); $project_handles = $this->loadViewerHandles($repository->getProjectPHIDs()); $form = id(new AphrontFormView()) ->setUser($user) ->appendChild( id(new AphrontFormTextControl()) ->setName('name') ->setLabel(pht('Name')) ->setValue($v_name) ->setError($e_name)); if ($repository->isHosted()) { $form ->appendChild( id(new AphrontFormTextControl()) ->setName('cloneName') ->setLabel(pht('Clone/Checkout As')) ->setValue($v_clone_name) ->setCaption( pht( 'Optional directory name to use when cloning or checking out '. 'this repository.'))); } $form ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($user) ->setName('description') ->setLabel(pht('Description')) ->setValue($v_desc)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorProjectDatasource()) ->setName('projectPHIDs') ->setLabel(pht('Projects')) ->setValue($project_handles)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Save')) ->addCancelButton($edit_uri)) ->appendChild(id(new PHUIFormDividerControl())) ->appendRemarkupInstructions($this->getReadmeInstructions()); $object_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->setForm($form) ->setFormErrors($errors); return $this->buildApplicationPage( array( $crumbs, $object_box, ), array( 'title' => $title, )); } private function getReadmeInstructions() { return pht(<<id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); if ($this->id) { $initiative = id(new FundInitiativeQuery()) ->setViewer($viewer) ->withIDs(array($this->id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$initiative) { return new Aphront404Response(); } $is_new = false; } else { $initiative = FundInitiative::initializeNewInitiative($viewer); $is_new = true; } if ($is_new) { $title = pht('Create Initiative'); $button_text = pht('Create Initiative'); $cancel_uri = $this->getApplicationURI(); } else { $title = pht( 'Edit %s %s', $initiative->getMonogram(), $initiative->getName()); $button_text = pht('Save Changes'); $cancel_uri = '/'.$initiative->getMonogram(); } $e_name = true; $v_name = $initiative->getName(); $e_merchant = null; $v_merchant = $initiative->getMerchantPHID(); $v_desc = $initiative->getDescription(); $v_risk = $initiative->getRisks(); if ($is_new) { $v_projects = array(); } else { $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( $initiative->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $v_projects = array_reverse($v_projects); } $validation_exception = null; if ($request->isFormPost()) { $v_name = $request->getStr('name'); $v_desc = $request->getStr('description'); $v_risk = $request->getStr('risks'); $v_view = $request->getStr('viewPolicy'); $v_edit = $request->getStr('editPolicy'); $v_merchant = $request->getStr('merchantPHID'); $v_projects = $request->getArr('projects'); $type_name = FundInitiativeTransaction::TYPE_NAME; $type_desc = FundInitiativeTransaction::TYPE_DESCRIPTION; $type_risk = FundInitiativeTransaction::TYPE_RISKS; $type_merchant = FundInitiativeTransaction::TYPE_MERCHANT; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; $xactions = array(); $xactions[] = id(new FundInitiativeTransaction()) ->setTransactionType($type_name) ->setNewValue($v_name); $xactions[] = id(new FundInitiativeTransaction()) ->setTransactionType($type_desc) ->setNewValue($v_desc); $xactions[] = id(new FundInitiativeTransaction()) ->setTransactionType($type_risk) ->setNewValue($v_risk); $xactions[] = id(new FundInitiativeTransaction()) ->setTransactionType($type_merchant) ->setNewValue($v_merchant); $xactions[] = id(new FundInitiativeTransaction()) ->setTransactionType($type_view) ->setNewValue($v_view); $xactions[] = id(new FundInitiativeTransaction()) ->setTransactionType($type_edit) ->setNewValue($v_edit); $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new FundInitiativeTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $proj_edge_type) ->setNewValue(array('=' => array_fuse($v_projects))); $editor = id(new FundInitiativeEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($initiative, $xactions); return id(new AphrontRedirectResponse()) ->setURI('/'.$initiative->getMonogram()); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_name = $ex->getShortMessage($type_name); $e_merchant = $ex->getShortMessage($type_merchant); $initiative->setViewPolicy($v_view); $initiative->setEditPolicy($v_edit); } } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) ->setObject($initiative) ->execute(); if ($v_projects) { $project_handles = $this->loadViewerHandles($v_projects); } else { $project_handles = array(); } $merchants = id(new PhortuneMerchantQuery()) ->setViewer($viewer) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->execute(); $merchant_options = array(); foreach ($merchants as $merchant) { $merchant_options[$merchant->getPHID()] = pht( 'Merchant %d %s', $merchant->getID(), $merchant->getName()); } if ($v_merchant && empty($merchant_options[$v_merchant])) { $merchant_options = array( $v_merchant => pht('(Restricted Merchant)'), ) + $merchant_options; } if (!$merchant_options) { return $this->newDialog() ->setTitle(pht('No Valid Phortune Merchant Accounts')) ->appendParagraph( pht( 'You do not control any merchant accounts which can receive '. 'payments from this initiative. When you create an initiative, '. 'you need to specify a merchant account where funds will be paid '. 'to.')) ->appendParagraph( pht( 'Create a merchant account in the Phortune application before '. 'creating an initiative in Fund.')) ->addCancelButton($this->getApplicationURI()); } $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormTextControl()) ->setName('name') ->setLabel(pht('Name')) ->setValue($v_name) ->setError($e_name)) ->appendChild( id(new AphrontFormSelectControl()) ->setName('merchantPHID') ->setLabel(pht('Pay To Merchant')) ->setValue($v_merchant) ->setError($e_merchant) ->setOptions($merchant_options)) ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($viewer) ->setName('description') ->setLabel(pht('Description')) ->setValue($v_desc)) ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($viewer) ->setName('risks') ->setLabel(pht('Risks/Challenges')) ->setValue($v_risk)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') ->setValue($project_handles) ->setDatasource(new PhabricatorProjectDatasource())) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('viewPolicy') ->setPolicyObject($initiative) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicies($policies)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('editPolicy') ->setPolicyObject($initiative) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicies($policies)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue($button_text) ->addCancelButton($cancel_uri)); $crumbs = $this->buildApplicationCrumbs(); if ($is_new) { $crumbs->addTextCrumb(pht('Create Initiative')); } else { $crumbs->addTextCrumb( $initiative->getMonogram(), '/'.$initiative->getMonogram()); $crumbs->addTextCrumb(pht('Edit')); } $box = id(new PHUIObjectBoxView()) ->setValidationException($validation_exception) ->setHeaderText($title) ->appendChild($form); return $this->buildApplicationPage( array( $crumbs, $box, ), array( 'title' => $title, )); } } diff --git a/src/applications/harbormaster/controller/HarbormasterStepEditController.php b/src/applications/harbormaster/controller/HarbormasterStepEditController.php index 62a8ac0e68..12631db71a 100644 --- a/src/applications/harbormaster/controller/HarbormasterStepEditController.php +++ b/src/applications/harbormaster/controller/HarbormasterStepEditController.php @@ -1,243 +1,244 @@ id = idx($data, 'id'); $this->planID = idx($data, 'plan'); $this->className = idx($data, 'class'); } public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $this->requireApplicationCapability( HarbormasterManagePlansCapability::CAPABILITY); if ($this->id) { $step = id(new HarbormasterBuildStepQuery()) ->setViewer($viewer) ->withIDs(array($this->id)) ->executeOne(); if (!$step) { return new Aphront404Response(); } $plan = $step->getBuildPlan(); $is_new = false; } else { $plan = id(new HarbormasterBuildPlanQuery()) ->setViewer($viewer) ->withIDs(array($this->planID)) ->executeOne(); if (!$plan) { return new Aphront404Response(); } $impl = HarbormasterBuildStepImplementation::getImplementation( $this->className); if (!$impl) { return new Aphront404Response(); } $step = HarbormasterBuildStep::initializeNewStep($viewer) ->setBuildPlanPHID($plan->getPHID()) ->setClassName($this->className); $is_new = true; } $plan_uri = $this->getApplicationURI('plan/'.$plan->getID().'/'); $implementation = $step->getStepImplementation(); $field_list = PhabricatorCustomField::getObjectFields( $step, PhabricatorCustomField::ROLE_EDIT); $field_list ->setViewer($viewer) ->readFieldsFromStorage($step); $e_name = true; $v_name = $step->getName(); $e_description = true; $v_description = $step->getDescription(); $e_depends_on = true; $raw_depends_on = $step->getDetail('dependsOn', array()); $v_depends_on = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs($raw_depends_on) ->execute(); $errors = array(); $validation_exception = null; if ($request->isFormPost()) { $e_name = null; $v_name = $request->getStr('name'); $e_description = null; $v_description = $request->getStr('description'); $e_depends_on = null; $v_depends_on = $request->getArr('dependsOn'); $xactions = $field_list->buildFieldTransactionsFromRequest( new HarbormasterBuildStepTransaction(), $request); $editor = id(new HarbormasterBuildStepEditor()) ->setActor($viewer) ->setContinueOnNoEffect(true) ->setContentSourceFromRequest($request); $name_xaction = id(new HarbormasterBuildStepTransaction()) ->setTransactionType(HarbormasterBuildStepTransaction::TYPE_NAME) ->setNewValue($v_name); array_unshift($xactions, $name_xaction); $depends_on_xaction = id(new HarbormasterBuildStepTransaction()) ->setTransactionType( HarbormasterBuildStepTransaction::TYPE_DEPENDS_ON) ->setNewValue($v_depends_on); array_unshift($xactions, $depends_on_xaction); $description_xaction = id(new HarbormasterBuildStepTransaction()) ->setTransactionType( HarbormasterBuildStepTransaction::TYPE_DESCRIPTION) ->setNewValue($v_description); array_unshift($xactions, $description_xaction); if ($is_new) { // When creating a new step, make sure we have a create transaction // so we'll apply the transactions even if the step has no // configurable options. $create_xaction = id(new HarbormasterBuildStepTransaction()) ->setTransactionType(HarbormasterBuildStepTransaction::TYPE_CREATE); array_unshift($xactions, $create_xaction); } try { $editor->applyTransactions($step, $xactions); return id(new AphrontRedirectResponse())->setURI($plan_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; } } $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormTextControl()) ->setName('name') ->setLabel(pht('Name')) ->setError($e_name) ->setValue($v_name)); $form ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource(id(new HarbormasterBuildDependencyDatasource()) ->setParameters(array( 'planPHID' => $plan->getPHID(), 'stepPHID' => $is_new ? null : $step->getPHID(), ))) ->setName('dependsOn') ->setLabel(pht('Depends On')) ->setError($e_depends_on) ->setValue($v_depends_on)); $field_list->appendFieldsToForm($form); $form ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($viewer) ->setName('description') ->setLabel(pht('Description')) ->setError($e_description) ->setValue($v_description)); if ($is_new) { $submit = pht('Create Build Step'); $header = pht('New Step: %s', $implementation->getName()); $crumb = pht('Add Step'); } else { $submit = pht('Save Build Step'); $header = pht('Edit Step: %s', $implementation->getName()); $crumb = pht('Edit Step'); } $form->appendChild( id(new AphrontFormSubmitControl()) ->setValue($submit) ->addCancelButton($plan_uri)); $box = id(new PHUIObjectBoxView()) ->setHeaderText($header) ->setValidationException($validation_exception) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $id = $plan->getID(); $crumbs->addTextCrumb(pht('Plan %d', $id), $plan_uri); $crumbs->addTextCrumb($crumb); $variables = $this->renderBuildVariablesTable(); if ($is_new) { $xaction_view = null; } else { $xactions = id(new HarbormasterBuildStepTransactionQuery()) ->setViewer($viewer) ->withObjectPHIDs(array($step->getPHID())) ->execute(); $xaction_view = id(new PhabricatorApplicationTransactionView()) ->setUser($viewer) ->setObjectPHID($step->getPHID()) ->setTransactions($xactions) ->setShouldTerminate(true); } return $this->buildApplicationPage( array( $crumbs, $box, $variables, $xaction_view, ), array( 'title' => $implementation->getName(), )); } private function renderBuildVariablesTable() { $viewer = $this->getRequest()->getUser(); $variables = HarbormasterBuild::getAvailableBuildVariables(); ksort($variables); $rows = array(); $rows[] = pht( 'The following variables can be used in most fields. To reference '. 'a variable, use `${name}` in a field.'); $rows[] = pht('| Variable | Description |'); $rows[] = '|---|---|'; foreach ($variables as $name => $description) { $rows[] = '| `'.$name.'` | '.$description.' |'; } $rows = implode("\n", $rows); $form = id(new AphrontFormView()) ->setUser($viewer) ->appendRemarkupInstructions($rows); return id(new PHUIObjectBoxView()) ->setHeaderText(pht('Build Variables')) ->appendChild($form); } } diff --git a/src/applications/legalpad/controller/LegalpadDocumentEditController.php b/src/applications/legalpad/controller/LegalpadDocumentEditController.php index 20002c4c77..d8b7d7c31b 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentEditController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentEditController.php @@ -1,228 +1,230 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if (!$this->id) { $is_create = true; $this->requireApplicationCapability( LegalpadCreateDocumentsCapability::CAPABILITY); $document = LegalpadDocument::initializeNewDocument($user); $body = id(new LegalpadDocumentBody()) ->setCreatorPHID($user->getPHID()); $document->attachDocumentBody($body); $document->setDocumentBodyPHID(PhabricatorPHIDConstants::PHID_VOID); } else { $is_create = false; $document = id(new LegalpadDocumentQuery()) ->setViewer($user) ->needDocumentBodies(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->withIDs(array($this->id)) ->executeOne(); if (!$document) { return new Aphront404Response(); } } $e_title = true; $e_text = true; $title = $document->getDocumentBody()->getTitle(); $text = $document->getDocumentBody()->getText(); $v_signature_type = $document->getSignatureType(); $v_preamble = $document->getPreamble(); $errors = array(); $can_view = null; $can_edit = null; if ($request->isFormPost()) { $xactions = array(); $title = $request->getStr('title'); if (!strlen($title)) { $e_title = pht('Required'); $errors[] = pht('The document title may not be blank.'); } else { $xactions[] = id(new LegalpadTransaction()) ->setTransactionType(LegalpadTransactionType::TYPE_TITLE) ->setNewValue($title); } $text = $request->getStr('text'); if (!strlen($text)) { $e_text = pht('Required'); $errors[] = pht('The document may not be blank.'); } else { $xactions[] = id(new LegalpadTransaction()) ->setTransactionType(LegalpadTransactionType::TYPE_TEXT) ->setNewValue($text); } $can_view = $request->getStr('can_view'); $xactions[] = id(new LegalpadTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setNewValue($can_view); $can_edit = $request->getStr('can_edit'); $xactions[] = id(new LegalpadTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) ->setNewValue($can_edit); if ($is_create) { $v_signature_type = $request->getStr('signatureType'); $xactions[] = id(new LegalpadTransaction()) ->setTransactionType(LegalpadTransactionType::TYPE_SIGNATURE_TYPE) ->setNewValue($v_signature_type); } $v_preamble = $request->getStr('preamble'); $xactions[] = id(new LegalpadTransaction()) ->setTransactionType(LegalpadTransactionType::TYPE_PREAMBLE) ->setNewValue($v_preamble); if (!$errors) { $editor = id(new LegalpadDocumentEditor()) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setActor($user); $xactions = $editor->applyTransactions($document, $xactions); return id(new AphrontRedirectResponse()) ->setURI($this->getApplicationURI('view/'.$document->getID())); } } if ($errors) { // set these to what was specified in the form on post $document->setViewPolicy($can_view); $document->setEditPolicy($can_edit); } $form = id(new AphrontFormView()) ->setUser($user) ->appendChild( id(new AphrontFormTextControl()) ->setID('document-title') ->setLabel(pht('Title')) ->setError($e_title) ->setValue($title) ->setName('title')); if ($is_create) { $form->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Who Should Sign?')) ->setName(pht('signatureType')) ->setValue($v_signature_type) ->setOptions(LegalpadDocument::getSignatureTypeMap())); } else { $form->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Who Should Sign?')) ->setValue($document->getSignatureTypeName())); } $form ->appendChild( id(new PhabricatorRemarkupControl()) - ->setID('preamble') - ->setLabel(pht('Preamble')) - ->setValue($v_preamble) - ->setName('preamble') - ->setCaption( - pht('Optional help text for users signing this document.'))) + ->setUser($user) + ->setID('preamble') + ->setLabel(pht('Preamble')) + ->setValue($v_preamble) + ->setName('preamble') + ->setCaption( + pht('Optional help text for users signing this document.'))) ->appendChild( id(new PhabricatorRemarkupControl()) - ->setID('document-text') - ->setLabel(pht('Document Body')) - ->setError($e_text) - ->setValue($text) - ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) - ->setName('text')); + ->setUser($user) + ->setID('document-text') + ->setLabel(pht('Document Body')) + ->setError($e_text) + ->setValue($text) + ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) + ->setName('text')); $policies = id(new PhabricatorPolicyQuery()) ->setViewer($user) ->setObject($document) ->execute(); $form ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicyObject($document) ->setPolicies($policies) ->setName('can_view')) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicyObject($document) ->setPolicies($policies) ->setName('can_edit')); $crumbs = $this->buildApplicationCrumbs($this->buildSideNav()); $submit = new AphrontFormSubmitControl(); if ($is_create) { $submit->setValue(pht('Create Document')); $submit->addCancelButton($this->getApplicationURI()); $title = pht('Create Document'); $short = pht('Create'); } else { $submit->setValue(pht('Edit Document')); $submit->addCancelButton( $this->getApplicationURI('view/'.$document->getID())); $title = pht('Edit Document'); $short = pht('Edit'); $crumbs->addTextCrumb( $document->getMonogram(), $this->getApplicationURI('view/'.$document->getID())); } $form ->appendChild($submit); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->setFormErrors($errors) ->setForm($form); $crumbs->addTextCrumb($short); $preview = id(new PHUIRemarkupPreviewPanel()) ->setHeader(pht('Document Preview')) ->setPreviewURI($this->getApplicationURI('document/preview/')) ->setControlID('document-text') ->setSkin('document'); return $this->buildApplicationPage( array( $crumbs, $form_box, $preview, ), array( 'title' => $title, )); } } diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index 1caba00d46..3472870a35 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -1,625 +1,626 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTaskQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->executeOne(); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTaskQuery()) ->setViewer($user) ->withIDs(array($workflow)) ->executeOne(); } $field_list = PhabricatorCustomField::getObjectFields( $task, PhabricatorCustomField::ROLE_VIEW); $field_list ->setViewer($user) ->readFieldsFromStorage($task); $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST; $e_dep_on = PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK; $e_dep_by = PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK; $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST; $e_mock = PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK; $phid = $task->getPHID(); $query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(array($phid)) ->withEdgeTypes( array( $e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock, )); $edges = idx($query->execute(), $phid); $phids = array_fill_keys($query->getDestinationPHIDs(), true); foreach ($task->getCCPHIDs() as $phid) { $phids[$phid] = true; } foreach ($task->getProjectPHIDs() as $phid) { $phids[$phid] = true; } if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $this->loadHandles($phids); $handles = $this->getLoadedHandles(); $context_bar = null; if ($parent_task) { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_tag( 'a', array( 'href' => '/maniphest/task/create/?parent='.$parent_task->getID(), 'class' => 'green button', ), pht('Create Another Subtask'))); $context_bar->appendChild(hsprintf( 'Created a subtask of %s', $this->getHandle($parent_task->getPHID())->renderLink())); } else if ($workflow == 'create') { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_tag('label', array(), 'Create Another')); $context_bar->addButton(phutil_tag( 'a', array( 'href' => '/maniphest/task/create/?template='.$task->getID(), 'class' => 'green button', ), pht('Similar Task'))); $context_bar->addButton(phutil_tag( 'a', array( 'href' => '/maniphest/task/create/', 'class' => 'green button', ), pht('Empty Task'))); $context_bar->appendChild(pht('New task created.')); } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); $timeline = $this->buildTransactionTimeline( $task, new ManiphestTransactionQuery(), $engine); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); $transaction_types = array( PhabricatorTransactions::TYPE_COMMENT => pht('Comment'), ManiphestTransaction::TYPE_STATUS => pht('Change Status'), ManiphestTransaction::TYPE_OWNER => pht('Reassign / Claim'), ManiphestTransaction::TYPE_CCS => pht('Add CCs'), ManiphestTransaction::TYPE_PRIORITY => pht('Change Priority'), ManiphestTransaction::TYPE_PROJECTS => pht('Associate Projects'), ); // Remove actions the user doesn't have permission to take. $requires = array( ManiphestTransaction::TYPE_OWNER => ManiphestEditAssignCapability::CAPABILITY, ManiphestTransaction::TYPE_PRIORITY => ManiphestEditPriorityCapability::CAPABILITY, ManiphestTransaction::TYPE_PROJECTS => ManiphestEditProjectsCapability::CAPABILITY, ManiphestTransaction::TYPE_STATUS => ManiphestEditStatusCapability::CAPABILITY, ); foreach ($transaction_types as $type => $name) { if (isset($requires[$type])) { if (!$this->hasApplicationCapability($requires[$type])) { unset($transaction_types[$type]); } } } // Don't show an option to change to the current status, or to change to // the duplicate status explicitly. unset($resolution_types[$task->getStatus()]); unset($resolution_types[ManiphestTaskStatus::getDuplicateStatus()]); // Don't show owner/priority changes for closed tasks, as they don't make // much sense. if ($task->isClosed()) { unset($transaction_types[ManiphestTransaction::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransaction::TYPE_OWNER]); } $default_claim = array( $user->getPHID() => $user->getUsername().' ('.$user->getRealName().')', ); $draft = id(new PhabricatorDraft())->loadOneWhere( 'authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $comment_form = new AphrontFormView(); $comment_form ->setUser($user) ->setWorkflow(true) ->setAction('/maniphest/transaction/save/') ->setEncType('multipart/form-data') ->addHiddenInput('taskID', $task->getID()) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Action')) ->setName('action') ->setOptions($transaction_types) ->setID('transaction-action')) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Status')) ->setName('resolution') ->setControlID('resolution') ->setControlStyle('display: none') ->setOptions($resolution_types)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Assign To')) ->setName('assign_to') ->setControlID('assign_to') ->setControlStyle('display: none') ->setID('assign-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('CCs')) ->setName('ccs') ->setControlID('ccs') ->setControlStyle('display: none') ->setID('cc-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Priority')) ->setName('priority') ->setOptions($priority_map) ->setControlID('priority') ->setControlStyle('display: none') ->setValue($task->getPriority())) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') ->setControlID('projects') ->setControlStyle('display: none') ->setID('projects-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormFileControl()) ->setLabel(pht('File')) ->setName('file') ->setControlID('file') ->setControlStyle('display: none')) ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($user) ->setLabel(pht('Comments')) ->setName('comments') ->setValue($draft_text) ->setID('transaction-comments') ->setUser($user)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Submit'))); $control_map = array( ManiphestTransaction::TYPE_STATUS => 'resolution', ManiphestTransaction::TYPE_OWNER => 'assign_to', ManiphestTransaction::TYPE_CCS => 'ccs', ManiphestTransaction::TYPE_PRIORITY => 'priority', ManiphestTransaction::TYPE_PROJECTS => 'projects', ); $projects_source = new PhabricatorProjectDatasource(); $users_source = new PhabricatorPeopleDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $tokenizer_map = array( ManiphestTransaction::TYPE_PROJECTS => array( 'id' => 'projects-tokenizer', 'src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText(), ), ManiphestTransaction::TYPE_OWNER => array( 'id' => 'assign-tokenizer', 'src' => $users_source->getDatasourceURI(), 'value' => $default_claim, 'limit' => 1, 'placeholder' => $users_source->getPlaceholderText(), ), ManiphestTransaction::TYPE_CCS => array( 'id' => 'cc-tokenizer', 'src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText(), ), ); // TODO: Initializing these behaviors for logged out users fatals things. if ($user->isLoggedIn()) { Javelin::initBehavior('maniphest-transaction-controls', array( 'select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => $tokenizer_map, )); Javelin::initBehavior('maniphest-transaction-preview', array( 'uri' => '/maniphest/transaction/preview/'.$task->getID().'/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, 'tokenizers' => $tokenizer_map, )); } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $comment_header = $is_serious ? pht('Add Comment') : pht('Weigh In'); $preview_panel = phutil_tag_div( 'aphront-panel-preview', phutil_tag( 'div', array('id' => 'transaction-preview'), phutil_tag_div( 'aphront-panel-preview-loading-text', pht('Loading preview...')))); $object_name = 'T'.$task->getID(); $actions = $this->buildActionView($task); $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb($object_name, '/'.$object_name) ->setActionList($actions); $header = $this->buildHeaderView($task); $properties = $this->buildPropertyView( $task, $field_list, $edges, $actions); $description = $this->buildDescriptionView($task, $engine); if (!$user->isLoggedIn()) { // TODO: Eventually, everything should run through this. For now, we're // only using it to get a consistent "Login to Comment" button. $comment_box = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($user) ->setRequestURI($request->getRequestURI()); $preview_panel = null; } else { $comment_box = id(new PHUIObjectBoxView()) ->setFlush(true) ->setHeaderText($comment_header) ->appendChild($comment_form); $timeline->setQuoteTargetID('transaction-comments'); $timeline->setQuoteRef($object_name); } $object_box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($properties); if ($description) { $object_box->addPropertyList($description); } return $this->buildApplicationPage( array( $crumbs, $context_bar, $object_box, $timeline, $comment_box, $preview_panel, ), array( 'title' => 'T'.$task->getID().' '.$task->getTitle(), 'pageObjects' => array($task->getPHID()), )); } private function buildHeaderView(ManiphestTask $task) { $view = id(new PHUIHeaderView()) ->setHeader($task->getTitle()) ->setUser($this->getRequest()->getUser()) ->setPolicyObject($task); $status = $task->getStatus(); $status_name = ManiphestTaskStatus::renderFullDescription($status); $view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_name); return $view; } private function buildActionView(ManiphestTask $task) { $viewer = $this->getRequest()->getUser(); $viewer_phid = $viewer->getPHID(); $viewer_is_cc = in_array($viewer_phid, $task->getCCPHIDs()); $id = $task->getID(); $phid = $task->getPHID(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $task, PhabricatorPolicyCapability::CAN_EDIT); $view = id(new PhabricatorActionListView()) ->setUser($viewer) ->setObject($task) ->setObjectURI($this->getRequest()->getRequestURI()); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Task')) ->setIcon('fa-pencil') ->setHref($this->getApplicationURI("/task/edit/{$id}/")) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); if ($task->getOwnerPHID() === $viewer_phid) { $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Automatically Subscribed')) ->setDisabled(true) ->setIcon('fa-check-circle')); } else { $action = $viewer_is_cc ? 'rem' : 'add'; $name = $viewer_is_cc ? pht('Unsubscribe') : pht('Subscribe'); $icon = $viewer_is_cc ? 'fa-minus-circle' : 'fa-plus-circle'; $view->addAction( id(new PhabricatorActionView()) ->setName($name) ->setHref("/maniphest/subscribe/{$action}/{$id}/") ->setRenderAsForm(true) ->setUser($viewer) ->setIcon($icon)); } $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Merge Duplicates In')) ->setHref("/search/attach/{$phid}/TASK/merge/") ->setWorkflow(true) ->setIcon('fa-compress') ->setDisabled(!$can_edit) ->setWorkflow(true)); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Create Subtask')) ->setHref($this->getApplicationURI("/task/create/?parent={$id}")) ->setIcon('fa-level-down')); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Blocking Tasks')) ->setHref("/search/attach/{$phid}/TASK/blocks/") ->setWorkflow(true) ->setIcon('fa-link') ->setDisabled(!$can_edit) ->setWorkflow(true)); return $view; } private function buildPropertyView( ManiphestTask $task, PhabricatorCustomFieldList $field_list, array $edges, PhabricatorActionListView $actions) { $viewer = $this->getRequest()->getUser(); $view = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($task) ->setActionList($actions); $view->addProperty( pht('Assigned To'), $task->getOwnerPHID() ? $this->getHandle($task->getOwnerPHID())->renderLink() : phutil_tag('em', array(), pht('None'))); $view->addProperty( pht('Priority'), ManiphestTaskPriority::getTaskPriorityName($task->getPriority())); $handles = $this->getLoadedHandles(); $cc_handles = array_select_keys($handles, $task->getCCPHIDs()); $subscriber_html = id(new SubscriptionListStringBuilder()) ->setObjectPHID($task->getPHID()) ->setHandles($cc_handles) ->buildPropertyString(); $view->addProperty(pht('Subscribers'), $subscriber_html); $view->addProperty( pht('Author'), $this->getHandle($task->getAuthorPHID())->renderLink()); $source = $task->getOriginalEmailSource(); if ($source) { $subject = '[T'.$task->getID().'] '.$task->getTitle(); $view->addProperty( pht('From Email'), phutil_tag( 'a', array( 'href' => 'mailto:'.$source.'?subject='.$subject, ), $source)); } $edge_types = array( PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK => pht('Blocks'), PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK => pht('Blocked By'), ManiphestTaskHasRevisionEdgeType::EDGECONST => pht('Differential Revisions'), PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK => pht('Pholio Mocks'), ); $revisions_commits = array(); $handles = $this->getLoadedHandles(); $commit_phids = array_keys( $edges[ManiphestTaskHasCommitEdgeType::EDGECONST]); if ($commit_phids) { $commit_drev = PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV; $drev_edges = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs($commit_phids) ->withEdgeTypes(array($commit_drev)) ->execute(); foreach ($commit_phids as $phid) { $revisions_commits[$phid] = $handles[$phid]->renderLink(); $revision_phid = key($drev_edges[$phid][$commit_drev]); $revision_handle = idx($handles, $revision_phid); if ($revision_handle) { $task_drev = ManiphestTaskHasRevisionEdgeType::EDGECONST; unset($edges[$task_drev][$revision_phid]); $revisions_commits[$phid] = hsprintf( '%s / %s', $revision_handle->renderLink($revision_handle->getName()), $revisions_commits[$phid]); } } } foreach ($edge_types as $edge_type => $edge_name) { if ($edges[$edge_type]) { $view->addProperty( $edge_name, $this->renderHandlesForPHIDs(array_keys($edges[$edge_type]))); } } if ($revisions_commits) { $view->addProperty( pht('Commits'), phutil_implode_html(phutil_tag('br'), $revisions_commits)); } $attached = $task->getAttached(); if (!is_array($attached)) { $attached = array(); } $file_infos = idx($attached, PhabricatorFileFilePHIDType::TYPECONST); if ($file_infos) { $file_phids = array_keys($file_infos); // TODO: These should probably be handles or something; clean this up // as we sort out file attachments. $files = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs($file_phids) ->execute(); $file_view = new PhabricatorFileLinkListView(); $file_view->setFiles($files); $view->addProperty( pht('Files'), $file_view->render()); } $view->invokeWillRenderEvent(); $field_list->appendFieldsToPropertyList( $task, $viewer, $view); return $view; } private function buildDescriptionView( ManiphestTask $task, PhabricatorMarkupEngine $engine) { $section = null; if (strlen($task->getDescription())) { $section = new PHUIPropertyListView(); $section->addSectionHeader( pht('Description'), PHUIPropertyListView::ICON_SUMMARY); $section->addTextContent( phutil_tag( 'div', array( 'class' => 'phabricator-remarkup', ), $engine->getOutput($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION))); } return $section; } } diff --git a/src/applications/people/customfield/PhabricatorUserBlurbField.php b/src/applications/people/customfield/PhabricatorUserBlurbField.php index 8bd903e57c..3221a33202 100644 --- a/src/applications/people/customfield/PhabricatorUserBlurbField.php +++ b/src/applications/people/customfield/PhabricatorUserBlurbField.php @@ -1,79 +1,80 @@ value = $object->loadUserProfile()->getBlurb(); } public function getOldValueForApplicationTransactions() { return $this->getObject()->loadUserProfile()->getBlurb(); } public function getNewValueForApplicationTransactions() { return $this->value; } public function applyApplicationTransactionInternalEffects( PhabricatorApplicationTransaction $xaction) { $this->getObject()->loadUserProfile()->setBlurb($xaction->getNewValue()); } public function readValueFromRequest(AphrontRequest $request) { $this->value = $request->getStr($this->getFieldKey()); } public function renderEditControl(array $handles) { return id(new PhabricatorRemarkupControl()) + ->setUser($this->getViewer()) ->setName($this->getFieldKey()) ->setValue($this->value) ->setLabel($this->getFieldName()); } public function renderPropertyViewLabel() { return null; } public function renderPropertyViewValue(array $handles) { $blurb = $this->getObject()->loadUserProfile()->getBlurb(); if (!strlen($blurb)) { return null; } return PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff())->setContent($blurb), 'default', $this->getViewer()); } public function getStyleForPropertyView() { return 'block'; } } diff --git a/src/applications/phame/controller/blog/PhameBlogEditController.php b/src/applications/phame/controller/blog/PhameBlogEditController.php index e8ec34d19c..1363cf8343 100644 --- a/src/applications/phame/controller/blog/PhameBlogEditController.php +++ b/src/applications/phame/controller/blog/PhameBlogEditController.php @@ -1,193 +1,194 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $blog = id(new PhameBlogQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$blog) { return new Aphront404Response(); } $submit_button = pht('Save Changes'); $page_title = pht('Edit Blog'); $cancel_uri = $this->getApplicationURI('blog/view/'.$blog->getID().'/'); } else { $blog = id(new PhameBlog()) ->setCreatorPHID($user->getPHID()); $blog->setViewPolicy(PhabricatorPolicies::POLICY_USER); $blog->setEditPolicy(PhabricatorPolicies::POLICY_USER); $blog->setJoinPolicy(PhabricatorPolicies::POLICY_USER); $submit_button = pht('Create Blog'); $page_title = pht('Create Blog'); $cancel_uri = $this->getApplicationURI(); } $e_name = true; $e_custom_domain = null; $errors = array(); if ($request->isFormPost()) { $name = $request->getStr('name'); $description = $request->getStr('description'); $custom_domain = $request->getStr('custom_domain'); $skin = $request->getStr('skin'); if (empty($name)) { $errors[] = pht('You must give the blog a name.'); $e_name = pht('Required'); } else { $e_name = null; } $blog->setName($name); $blog->setDescription($description); $blog->setDomain(nonempty($custom_domain, null)); $blog->setSkin($skin); $blog->setViewPolicy($request->getStr('can_view')); $blog->setEditPolicy($request->getStr('can_edit')); $blog->setJoinPolicy($request->getStr('can_join')); if (!empty($custom_domain)) { list($error_label, $error_text) = $blog->validateCustomDomain($custom_domain); if ($error_label) { $errors[] = $error_text; $e_custom_domain = $error_label; } if ($blog->getViewPolicy() != PhabricatorPolicies::POLICY_PUBLIC) { $errors[] = pht( 'For custom domains to work, the blog must have a view policy of '. 'public.'); // Prefer earlier labels for the multiple error scenario. if (!$e_custom_domain) { $e_custom_domain = pht('Invalid Policy'); } } } // Don't let users remove their ability to edit blogs. PhabricatorPolicyFilter::mustRetainCapability( $user, $blog, PhabricatorPolicyCapability::CAN_EDIT); if (!$errors) { try { $blog->save(); return id(new AphrontRedirectResponse()) ->setURI($this->getApplicationURI('blog/view/'.$blog->getID().'/')); } catch (AphrontDuplicateKeyQueryException $ex) { $errors[] = pht('Domain must be unique.'); $e_custom_domain = pht('Not Unique'); } } } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($user) ->setObject($blog) ->execute(); $skins = PhameSkinSpecification::loadAllSkinSpecifications(); $skins = mpull($skins, 'getName'); $form = id(new AphrontFormView()) ->setUser($user) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Name')) ->setName('name') ->setValue($blog->getName()) ->setID('blog-name') ->setError($e_name)) ->appendChild( id(new PhabricatorRemarkupControl()) - ->setLabel(pht('Description')) - ->setName('description') - ->setValue($blog->getDescription()) - ->setID('blog-description') - ->setUser($user) - ->setDisableMacros(true)) + ->setUser($user) + ->setLabel(pht('Description')) + ->setName('description') + ->setValue($blog->getDescription()) + ->setID('blog-description') + ->setUser($user) + ->setDisableMacros(true)) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicyObject($blog) ->setPolicies($policies) ->setName('can_view')) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicyObject($blog) ->setPolicies($policies) ->setName('can_edit')) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_JOIN) ->setPolicyObject($blog) ->setPolicies($policies) ->setName('can_join')) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Custom Domain')) ->setName('custom_domain') ->setValue($blog->getDomain()) ->setCaption( pht('Must include at least one dot (.), e.g. blog.example.com')) ->setError($e_custom_domain)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Skin')) ->setName('skin') ->setValue($blog->getSkin()) ->setOptions($skins)) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($submit_button)); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($page_title) ->setFormErrors($errors) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($page_title, $this->getApplicationURI('blog/new')); $nav = $this->renderSideNavFilterView(); $nav->selectFilter($this->id ? null : 'blog/new'); $nav->appendChild( array( $crumbs, $form_box, )); return $this->buildApplicationPage( $nav, array( 'title' => $page_title, )); } } diff --git a/src/applications/pholio/controller/PholioInlineController.php b/src/applications/pholio/controller/PholioInlineController.php index b17679c758..782383cdb8 100644 --- a/src/applications/pholio/controller/PholioInlineController.php +++ b/src/applications/pholio/controller/PholioInlineController.php @@ -1,172 +1,173 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); if ($this->id) { $inline = id(new PholioTransactionComment())->load($this->id); if (!$inline) { return new Aphront404Response(); } if ($inline->getTransactionPHID()) { $mode = 'view'; } else { if ($inline->getAuthorPHID() == $viewer->getPHID()) { $mode = 'edit'; } else { return new Aphront404Response(); } } } else { $mock = id(new PholioMockQuery()) ->setViewer($viewer) ->withIDs(array($request->getInt('mockID'))) ->executeOne(); if (!$mock) { return new Aphront404Response(); } $inline = id(new PholioTransactionComment()) ->setImageID($request->getInt('imageID')) ->setX($request->getInt('startX')) ->setY($request->getInt('startY')) ->setCommentVersion(1) ->setAuthorPHID($viewer->getPHID()) ->setEditPolicy($viewer->getPHID()) ->setViewPolicy(PhabricatorPolicies::POLICY_PUBLIC) ->setContentSourceFromRequest($request) ->setWidth($request->getInt('endX') - $request->getInt('startX')) ->setHeight($request->getInt('endY') - $request->getInt('startY')); $mode = 'new'; } $v_content = $inline->getContent(); // TODO: Not correct, but we don't always have a mock right now. $mock_uri = '/'; if ($mode == 'view') { require_celerity_resource('pholio-inline-comments-css'); $image = id(new PholioImageQuery()) ->setViewer($viewer) ->withIDs(array($inline->getImageID())) ->executeOne(); $handles = $this->loadViewerHandles(array($inline->getAuthorPHID())); $author_handle = $handles[$inline->getAuthorPHID()]; $file = $image->getFile(); if (!$file->isViewableImage()) { throw new Exception('File is not viewable.'); } $image_uri = $file->getBestURI(); $thumb = id(new PHUIImageMaskView()) ->addClass('mrl') ->setImage($image_uri) ->setDisplayHeight(200) ->setDisplayWidth(498) ->withMask(true) ->centerViewOnPoint( $inline->getX(), $inline->getY(), $inline->getHeight(), $inline->getWidth()); $comment_head = phutil_tag( 'div', array( 'class' => 'pholio-inline-comment-head', ), $author_handle->renderLink()); $comment_body = phutil_tag( 'div', array( 'class' => 'pholio-inline-comment-body', ), PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff()) ->setContent($inline->getContent()), 'default', $viewer)); return $this->newDialog() ->setTitle(pht('Inline Comment')) ->appendChild($thumb) ->appendChild($comment_head) ->appendChild($comment_body) ->addCancelButton($mock_uri, pht('Close')); } if ($request->isFormPost()) { $v_content = $request->getStr('content'); if (strlen($v_content)) { $inline->setContent($v_content); $inline->save(); $dictionary = $inline->toDictionary(); } else if ($inline->getID()) { $inline->delete(); $dictionary = array(); } return id(new AphrontAjaxResponse())->setContent($dictionary); } switch ($mode) { case 'edit': $title = pht('Edit Inline Comment'); $submit_text = pht('Save Draft'); break; case 'new': $title = pht('New Inline Comment'); $submit_text = pht('Save Draft'); break; } $form = id(new AphrontFormView()) ->setUser($viewer); if ($mode == 'new') { $params = array( 'mockID' => $request->getInt('mockID'), 'imageID' => $request->getInt('imageID'), 'startX' => $request->getInt('startX'), 'startY' => $request->getInt('startY'), 'endX' => $request->getInt('endX'), 'endY' => $request->getInt('endY'), ); foreach ($params as $key => $value) { $form->addHiddenInput($key, $value); } } $form ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($viewer) ->setName('content') ->setLabel(pht('Comment')) ->setValue($v_content)); return $this->newDialog() ->setTitle($title) ->setWidth(AphrontDialogView::WIDTH_FORM) ->appendChild($form->buildLayoutView()) ->addCancelButton($mock_uri) ->addSubmitButton($submit_text); } } diff --git a/src/applications/pholio/view/PholioUploadedImageView.php b/src/applications/pholio/view/PholioUploadedImageView.php index 766264ee9b..fb8a82431e 100644 --- a/src/applications/pholio/view/PholioUploadedImageView.php +++ b/src/applications/pholio/view/PholioUploadedImageView.php @@ -1,116 +1,117 @@ replacesPHID = $replaces_phid; return $this; } public function setImage(PholioImage $image) { $this->image = $image; return $this; } public function render() { require_celerity_resource('pholio-edit-css'); $image = $this->image; $file = $image->getFile(); $phid = $file->getPHID(); $replaces_phid = $this->replacesPHID; $remove = $this->renderRemoveElement(); $title = id(new AphrontFormTextControl()) ->setName('title_'.$phid) ->setValue($image->getName()) ->setSigil('image-title') ->setLabel(pht('Title')); $description = id(new PhabricatorRemarkupControl()) + ->setUser($this->getUser()) ->setName('description_'.$phid) ->setValue($image->getDescription()) ->setSigil('image-description') ->setLabel(pht('Description')); $thumb_frame = phutil_tag( 'div', array( 'class' => 'pholio-thumb-frame', 'style' => 'background-image: url('.$file->getThumb280x210URI().');', )); $handle = javelin_tag( 'div', array( 'class' => 'pholio-drag-handle', 'sigil' => 'pholio-drag-handle', )); $content = hsprintf( '
%s
%s
%s
%s %s
', $remove, $file->getName(), $thumb_frame, $title, $description); $input = phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'file_phids[]', 'value' => $phid, )); $replaces_input = phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'replaces['.$replaces_phid.']', 'value' => $phid, )); return javelin_tag( 'div', array( 'class' => 'pholio-uploaded-image', 'sigil' => 'pholio-drop-image', 'meta' => array( 'filePHID' => $file->getPHID(), 'replacesPHID' => $replaces_phid, ), ), array( $handle, $content, $input, $replaces_input, )); } private function renderRemoveElement() { return javelin_tag( 'a', array( 'class' => 'button grey', 'sigil' => 'pholio-drop-remove', ), 'X'); } } diff --git a/src/applications/phortune/controller/PhortuneMerchantEditController.php b/src/applications/phortune/controller/PhortuneMerchantEditController.php index fa7b5391d1..2b66209761 100644 --- a/src/applications/phortune/controller/PhortuneMerchantEditController.php +++ b/src/applications/phortune/controller/PhortuneMerchantEditController.php @@ -1,180 +1,181 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); if ($this->id) { $merchant = id(new PhortuneMerchantQuery()) ->setViewer($viewer) ->withIDs(array($this->id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$merchant) { return new Aphront404Response(); } $is_new = false; } else { $this->requireApplicationCapability( PhortuneMerchantCapability::CAPABILITY); $merchant = PhortuneMerchant::initializeNewMerchant($viewer); $merchant->attachMemberPHIDs(array($viewer->getPHID())); $is_new = true; } if ($is_new) { $title = pht('Create Merchant'); $button_text = pht('Create Merchant'); $cancel_uri = $this->getApplicationURI('merchant/'); } else { $title = pht( 'Edit Merchant %d %s', $merchant->getID(), $merchant->getName()); $button_text = pht('Save Changes'); $cancel_uri = $this->getApplicationURI( '/merchant/'.$merchant->getID().'/'); } $e_name = true; $v_name = $merchant->getName(); $v_desc = $merchant->getDescription(); $v_members = $merchant->getMemberPHIDs(); $e_members = null; $validation_exception = null; if ($request->isFormPost()) { $v_name = $request->getStr('name'); $v_desc = $request->getStr('desc'); $v_view = $request->getStr('viewPolicy'); $v_edit = $request->getStr('editPolicy'); $v_members = $request->getArr('memberPHIDs'); $type_name = PhortuneMerchantTransaction::TYPE_NAME; $type_desc = PhortuneMerchantTransaction::TYPE_DESCRIPTION; $type_edge = PhabricatorTransactions::TYPE_EDGE; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $edge_members = PhortuneMerchantHasMemberEdgeType::EDGECONST; $xactions = array(); $xactions[] = id(new PhortuneMerchantTransaction()) ->setTransactionType($type_name) ->setNewValue($v_name); $xactions[] = id(new PhortuneMerchantTransaction()) ->setTransactionType($type_desc) ->setNewValue($v_desc); $xactions[] = id(new PhortuneMerchantTransaction()) ->setTransactionType($type_view) ->setNewValue($v_view); $xactions[] = id(new PhortuneMerchantTransaction()) ->setTransactionType($type_edge) ->setMetadataValue('edge:type', $edge_members) ->setNewValue( array( '=' => array_fuse($v_members), )); $editor = id(new PhortuneMerchantEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($merchant, $xactions); $id = $merchant->getID(); $merchant_uri = $this->getApplicationURI("merchant/{$id}/"); return id(new AphrontRedirectResponse())->setURI($merchant_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_name = $ex->getShortMessage($type_name); $e_mbmers = $ex->getShortMessage($type_edge); $merchant->setViewPolicy($v_view); } } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) ->setObject($merchant) ->execute(); $member_handles = $this->loadViewerHandles($v_members); $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormTextControl()) ->setName('name') ->setLabel(pht('Name')) ->setValue($v_name) ->setError($e_name)) ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($viewer) ->setName('desc') ->setLabel(pht('Description')) ->setValue($v_desc)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorPeopleDatasource()) ->setLabel(pht('Members')) ->setName('memberPHIDs') ->setValue($member_handles) ->setError($e_members)) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('viewPolicy') ->setPolicyObject($merchant) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicies($policies)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue($button_text) ->addCancelButton($cancel_uri)); $crumbs = $this->buildApplicationCrumbs(); if ($is_new) { $crumbs->addTextCrumb(pht('Create Merchant')); } else { $crumbs->addTextCrumb( pht('Merchant %d', $merchant->getID()), $this->getApplicationURI('/merchant/'.$merchant->getID().'/')); $crumbs->addTextCrumb(pht('Edit')); } $box = id(new PHUIObjectBoxView()) ->setValidationException($validation_exception) ->setHeaderText($title) ->appendChild($form); return $this->buildApplicationPage( array( $crumbs, $box, ), array( 'title' => $title, )); } } diff --git a/src/applications/ponder/controller/PonderAnswerEditController.php b/src/applications/ponder/controller/PonderAnswerEditController.php index 30f97e1177..80273bb053 100644 --- a/src/applications/ponder/controller/PonderAnswerEditController.php +++ b/src/applications/ponder/controller/PonderAnswerEditController.php @@ -1,109 +1,110 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $answer = id(new PonderAnswerQuery()) ->setViewer($viewer) ->withIDs(array($this->id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$answer) { return new Aphront404Response(); } $v_content = $answer->getContent(); $e_content = true; $question = $answer->getQuestion(); $qid = $question->getID(); $answer_uri = $answer->getURI(); $errors = array(); if ($request->isFormPost()) { $v_content = $request->getStr('content'); if (!strlen($v_content)) { $errors[] = pht('You must provide some substance in your answer.'); $e_content = pht('Required'); } if (!$errors) { $xactions = array(); $xactions[] = id(new PonderAnswerTransaction()) ->setTransactionType(PonderAnswerTransaction::TYPE_CONTENT) ->setNewValue($v_content); $editor = id(new PonderAnswerEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); $editor->applyTransactions($answer, $xactions); return id(new AphrontRedirectResponse()) ->setURI($answer_uri); } } $answer_content_id = celerity_generate_unique_node_id(); $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Question')) ->setValue($question->getTitle())) ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($viewer) ->setLabel(pht('Answer')) ->setName('content') ->setID($answer_content_id) ->setValue($v_content) ->setError($e_content)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Update Answer')) ->addCancelButton($answer_uri)); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb("Q{$qid}", $answer_uri); $crumbs->addTextCrumb(pht('Edit Answer')); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Edit Answer')) ->setFormErrors($errors) ->setForm($form); $preview = id(new PHUIRemarkupPreviewPanel()) ->setHeader(pht('Answer Preview')) ->setControlID($answer_content_id) ->setPreviewURI($this->getApplicationURI('preview/')); return $this->buildApplicationPage( array( $crumbs, $form_box, $preview, ), array( 'title' => pht('Edit Answer'), )); } } diff --git a/src/applications/ponder/controller/PonderQuestionEditController.php b/src/applications/ponder/controller/PonderQuestionEditController.php index 557c2c8910..117eefa461 100644 --- a/src/applications/ponder/controller/PonderQuestionEditController.php +++ b/src/applications/ponder/controller/PonderQuestionEditController.php @@ -1,156 +1,157 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $question = id(new PonderQuestionQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$question) { return new Aphront404Response(); } $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( $question->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $v_projects = array_reverse($v_projects); } else { $question = id(new PonderQuestion()) ->setStatus(PonderQuestionStatus::STATUS_OPEN) ->setAuthorPHID($user->getPHID()) ->setVoteCount(0) ->setAnswerCount(0) ->setHeat(0.0); $v_projects = array(); } $v_title = $question->getTitle(); $v_content = $question->getContent(); $errors = array(); $e_title = true; if ($request->isFormPost()) { $v_title = $request->getStr('title'); $v_content = $request->getStr('content'); $v_projects = $request->getArr('projects'); $len = phutil_utf8_strlen($v_title); if ($len < 1) { $errors[] = pht('Title must not be empty.'); $e_title = pht('Required'); } else if ($len > 255) { $errors[] = pht('Title is too long.'); $e_title = pht('Too Long'); } if (!$errors) { $template = id(new PonderQuestionTransaction()); $xactions = array(); $xactions[] = id(clone $template) ->setTransactionType(PonderQuestionTransaction::TYPE_TITLE) ->setNewValue($v_title); $xactions[] = id(clone $template) ->setTransactionType(PonderQuestionTransaction::TYPE_CONTENT) ->setNewValue($v_content); $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new PonderQuestionTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $proj_edge_type) ->setNewValue(array('=' => array_fuse($v_projects))); $editor = id(new PonderQuestionEditor()) ->setActor($user) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); $editor->applyTransactions($question, $xactions); return id(new AphrontRedirectResponse()) ->setURI('/Q'.$question->getID()); } } $form = id(new AphrontFormView()) ->setUser($user) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Question')) ->setName('title') ->setValue($v_title) ->setError($e_title)) ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($user) ->setName('content') ->setID('content') ->setValue($v_content) ->setLabel(pht('Description')) ->setUser($user)); if ($v_projects) { $project_handles = $this->loadViewerHandles($v_projects); } else { $project_handles = array(); } $form->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') ->setValue($project_handles) ->setDatasource(new PhabricatorProjectDatasource())); $form ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($this->getApplicationURI()) ->setValue(pht('Ask Away!'))); $preview = id(new PHUIRemarkupPreviewPanel()) ->setHeader(pht('Question Preview')) ->setControlID('content') ->setPreviewURI($this->getApplicationURI('preview/')); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Ask New Question')) ->setFormErrors($errors) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $id = $question->getID(); if ($id) { $crumbs->addTextCrumb("Q{$id}", "/Q{$id}"); $crumbs->addTextCrumb(pht('Edit')); } else { $crumbs->addTextCrumb(pht('Ask Question')); } return $this->buildApplicationPage( array( $crumbs, $form_box, $preview, ), array( 'title' => pht('Ask New Question'), )); } } diff --git a/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php b/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php index 57e18d760f..d84b255086 100644 --- a/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php +++ b/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php @@ -1,282 +1,283 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $poll = id(new PhabricatorSlowvoteQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$poll) { return new Aphront404Response(); } $is_new = false; } else { $poll = PhabricatorSlowvotePoll::initializeNewPoll($user); $is_new = true; } if ($is_new) { $v_projects = array(); } else { $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( $poll->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $v_projects = array_reverse($v_projects); } $e_question = true; $e_response = true; $errors = array(); $v_question = $poll->getQuestion(); $v_description = $poll->getDescription(); $v_responses = $poll->getResponseVisibility(); $v_shuffle = $poll->getShuffle(); $responses = $request->getArr('response'); if ($request->isFormPost()) { $v_question = $request->getStr('question'); $v_description = $request->getStr('description'); $v_responses = (int)$request->getInt('responses'); $v_shuffle = (int)$request->getBool('shuffle'); $v_view_policy = $request->getStr('viewPolicy'); $v_projects = $request->getArr('projects'); if ($is_new) { $poll->setMethod($request->getInt('method')); } if (!strlen($v_question)) { $e_question = pht('Required'); $errors[] = pht('You must ask a poll question.'); } else { $e_question = null; } if ($is_new) { $responses = array_filter($responses); if (empty($responses)) { $errors[] = pht('You must offer at least one response.'); $e_response = pht('Required'); } else { $e_response = null; } } $xactions = array(); $template = id(new PhabricatorSlowvoteTransaction()); $xactions[] = id(clone $template) ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_QUESTION) ->setNewValue($v_question); $xactions[] = id(clone $template) ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION) ->setNewValue($v_description); $xactions[] = id(clone $template) ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_RESPONSES) ->setNewValue($v_responses); $xactions[] = id(clone $template) ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_SHUFFLE) ->setNewValue($v_shuffle); $xactions[] = id(clone $template) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setNewValue($v_view_policy); if (empty($errors)) { $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new PhabricatorSlowvoteTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $proj_edge_type) ->setNewValue(array('=' => array_fuse($v_projects))); $editor = id(new PhabricatorSlowvoteEditor()) ->setActor($user) ->setContinueOnNoEffect(true) ->setContentSourceFromRequest($request); $xactions = $editor->applyTransactions($poll, $xactions); if ($is_new) { $poll->save(); foreach ($responses as $response) { $option = new PhabricatorSlowvoteOption(); $option->setName($response); $option->setPollID($poll->getID()); $option->save(); } } return id(new AphrontRedirectResponse()) ->setURI('/V'.$poll->getID()); } else { $poll->setViewPolicy($v_view_policy); } } $instructions = phutil_tag( 'p', array( 'class' => 'aphront-form-instructions', ), pht('Resolve issues and build consensus through '. 'protracted deliberation.')); if ($v_projects) { $project_handles = $this->loadViewerHandles($v_projects); } else { $project_handles = array(); } $form = id(new AphrontFormView()) ->setUser($user) ->appendChild($instructions) ->appendChild( id(new AphrontFormTextAreaControl()) ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT) ->setLabel(pht('Question')) ->setName('question') ->setValue($v_question) ->setError($e_question)) ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($user) ->setLabel(pht('Description')) ->setName('description') ->setValue($v_description)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') ->setValue($project_handles) ->setDatasource(new PhabricatorProjectDatasource())); if ($is_new) { for ($ii = 0; $ii < 10; $ii++) { $n = ($ii + 1); $response = id(new AphrontFormTextControl()) ->setLabel(pht('Response %d', $n)) ->setName('response[]') ->setValue(idx($responses, $ii, '')); if ($ii == 0) { $response->setError($e_response); } $form->appendChild($response); } } $poll_type_options = array( PhabricatorSlowvotePoll::METHOD_PLURALITY => pht('Plurality (Single Choice)'), PhabricatorSlowvotePoll::METHOD_APPROVAL => pht('Approval (Multiple Choice)'), ); $response_type_options = array( PhabricatorSlowvotePoll::RESPONSES_VISIBLE => pht('Allow anyone to see the responses'), PhabricatorSlowvotePoll::RESPONSES_VOTERS => pht('Require a vote to see the responses'), PhabricatorSlowvotePoll::RESPONSES_OWNER => pht('Only I can see the responses'), ); if ($is_new) { $form->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Vote Type')) ->setName('method') ->setValue($poll->getMethod()) ->setOptions($poll_type_options)); } else { $form->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Vote Type')) ->setValue(idx($poll_type_options, $poll->getMethod()))); } if ($is_new) { $title = pht('Create Slowvote'); $button = pht('Create'); $cancel_uri = $this->getApplicationURI(); } else { $title = pht('Edit %s', 'V'.$poll->getID()); $button = pht('Save Changes'); $cancel_uri = '/V'.$poll->getID(); } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($user) ->setObject($poll) ->execute(); $form ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Responses')) ->setName('responses') ->setValue($v_responses) ->setOptions($response_type_options)) ->appendChild( id(new AphrontFormCheckboxControl()) ->setLabel(pht('Shuffle')) ->addCheckbox( 'shuffle', 1, pht('Show choices in random order.'), $v_shuffle)) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setName('viewPolicy') ->setPolicyObject($poll) ->setPolicies($policies) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue($button) ->addCancelButton($cancel_uri)); $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView()); $crumbs->addTextCrumb($title); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) ->setFormErrors($errors) ->setForm($form); return $this->buildApplicationPage( array( $crumbs, $form_box, ), array( 'title' => $title, )); } } diff --git a/src/applications/transactions/controller/PhabricatorApplicationTransactionCommentEditController.php b/src/applications/transactions/controller/PhabricatorApplicationTransactionCommentEditController.php index 0b4d0b615e..1cb38b1768 100644 --- a/src/applications/transactions/controller/PhabricatorApplicationTransactionCommentEditController.php +++ b/src/applications/transactions/controller/PhabricatorApplicationTransactionCommentEditController.php @@ -1,86 +1,87 @@ phid = $data['phid']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $xaction = id(new PhabricatorObjectQuery()) ->withPHIDs(array($this->phid)) ->setViewer($user) ->executeOne(); if (!$xaction) { return new Aphront404Response(); } if (!$xaction->getComment()) { // You can't currently edit a transaction which doesn't have a comment. // Some day you may be able to edit the visibility. return new Aphront404Response(); } if ($xaction->getComment()->getIsRemoved()) { // You can't edit history of a transaction with a removed comment. return new Aphront400Response(); } $obj_phid = $xaction->getObjectPHID(); $obj_handle = id(new PhabricatorHandleQuery()) ->setViewer($user) ->withPHIDs(array($obj_phid)) ->executeOne(); if ($request->isDialogFormPost()) { $text = $request->getStr('text'); $comment = $xaction->getApplicationTransactionCommentObject(); $comment->setContent($text); if (!strlen($text)) { $comment->setIsDeleted(true); } $editor = id(new PhabricatorApplicationTransactionCommentEditor()) ->setActor($user) ->setContentSource(PhabricatorContentSource::newFromRequest($request)) ->applyEdit($xaction, $comment); if ($request->isAjax()) { return id(new AphrontAjaxResponse())->setContent(array()); } else { return id(new AphrontReloadResponse())->setURI($obj_handle->getURI()); } } $dialog = id(new AphrontDialogView()) ->setUser($user) ->setSubmitURI( $this->getApplicationURI('/transactions/edit/'.$xaction->getPHID().'/')) ->setTitle(pht('Edit Comment')); $dialog ->addHiddenInput('anchor', $request->getStr('anchor')) ->appendChild( id(new PHUIFormLayoutView()) ->setFullWidth(true) ->appendChild( id(new PhabricatorRemarkupControl()) + ->setUser($user) ->setName('text') ->setValue($xaction->getComment()->getContent()))); $dialog ->addSubmitButton(pht('Save Changes')) ->addCancelButton($obj_handle->getURI()); return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php index d67c51bb29..3c56bf75c0 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php @@ -1,76 +1,77 @@ setUser($this->getViewer()) ->setLabel($this->getFieldName()) ->setName($this->getFieldKey()) ->setCaption($this->getCaption()) ->setValue($this->getFieldValue()); } public function getStyleForPropertyView() { return 'block'; } public function getApplicationTransactionRemarkupBlocks( PhabricatorApplicationTransaction $xaction) { return array( $xaction->getNewValue(), ); } public function renderPropertyViewValue(array $handles) { $value = $this->getFieldValue(); if (!strlen($value)) { return null; } // TODO: Once this stabilizes, it would be nice to let fields batch this. // For now, an extra query here and there on object detail pages isn't the // end of the world. $viewer = $this->getViewer(); return PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff()) ->setContent($value) ->setPReserveLinebreaks(true), 'default', $viewer); } public function getApplicationTransactionTitle( PhabricatorApplicationTransaction $xaction) { $author_phid = $xaction->getAuthorPHID(); // TODO: Expose fancy transactions. return pht( '%s edited %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName()); } public function shouldAppearInHerald() { return true; } public function getHeraldFieldConditions() { return array( HeraldAdapter::CONDITION_CONTAINS, HeraldAdapter::CONDITION_NOT_CONTAINS, HeraldAdapter::CONDITION_IS, HeraldAdapter::CONDITION_IS_NOT, HeraldAdapter::CONDITION_REGEXP, ); } } diff --git a/src/view/form/control/PhabricatorRemarkupControl.php b/src/view/form/control/PhabricatorRemarkupControl.php index 3d37c7d671..e1041c409e 100644 --- a/src/view/form/control/PhabricatorRemarkupControl.php +++ b/src/view/form/control/PhabricatorRemarkupControl.php @@ -1,213 +1,226 @@ disableMacro = $disable; return $this; } public function setDisableFullScreen($disable) { $this->disableFullScreen = $disable; return $this; } protected function renderInput() { $id = $this->getID(); if (!$id) { $id = celerity_generate_unique_node_id(); $this->setID($id); } + $viewer = $this->getUser(); + if (!$viewer) { + throw new Exception( + pht('Call setUser() before rendering a PhabricatorRemarkupControl!')); + } + // We need to have this if previews render images, since Ajax can not // currently ship JS or CSS. require_celerity_resource('lightbox-attachment-css'); Javelin::initBehavior( 'aphront-drag-and-drop-textarea', array( 'target' => $id, 'activatedClass' => 'aphront-textarea-drag-and-drop', 'uri' => '/file/dropupload/', )); Javelin::initBehavior( 'phabricator-remarkup-assist', array( 'pht' => array( 'bold text' => pht('bold text'), 'italic text' => pht('italic text'), 'monospaced text' => pht('monospaced text'), 'List Item' => pht('List Item'), 'data' => pht('data'), 'name' => pht('name'), 'URL' => pht('URL'), ), )); Javelin::initBehavior('phabricator-tooltips', array()); $actions = array( 'fa-bold' => array( 'tip' => pht('Bold'), ), 'fa-italic' => array( 'tip' => pht('Italics'), ), 'fa-text-width' => array( 'tip' => pht('Monospaced'), ), 'fa-link' => array( 'tip' => pht('Link'), ), array( 'spacer' => true, ), 'fa-list-ul' => array( 'tip' => pht('Bulleted List'), ), 'fa-list-ol' => array( 'tip' => pht('Numbered List'), ), 'fa-code' => array( 'tip' => pht('Code Block'), ), 'fa-table' => array( 'tip' => pht('Table'), ), 'fa-cloud-upload' => array( 'tip' => pht('Upload File'), ), ); - if (!$this->disableMacro and function_exists('imagettftext')) { + $can_use_macros = + (!$this->disableMacro) && + (function_exists('imagettftext')); + + if ($can_use_macros) { + $can_use_macros = PhabricatorApplication::isClassInstalledForViewer( + 'PhabricatorMacroApplication', + $viewer); + } + + if ($can_use_macros) { $actions[] = array( 'spacer' => true, ); $actions['fa-meh-o'] = array( 'tip' => pht('Meme'), ); } $actions['fa-life-bouy'] = array( 'tip' => pht('Help'), 'align' => 'right', 'href' => PhabricatorEnv::getDoclink('Remarkup Reference'), ); if (!$this->disableFullScreen) { $actions[] = array( 'spacer' => true, 'align' => 'right', ); $actions['fa-arrows-alt'] = array( 'tip' => pht('Fullscreen Mode'), 'align' => 'right', ); } $buttons = array(); foreach ($actions as $action => $spec) { $classes = array(); if (idx($spec, 'align') == 'right') { $classes[] = 'remarkup-assist-right'; } if (idx($spec, 'spacer')) { $classes[] = 'remarkup-assist-separator'; $buttons[] = phutil_tag( 'span', array( 'class' => implode(' ', $classes), ), ''); continue; } else { $classes[] = 'remarkup-assist-button'; } $href = idx($spec, 'href', '#'); if ($href == '#') { $meta = array('action' => $action); $mustcapture = true; $target = null; } else { $meta = array(); $mustcapture = null; $target = '_blank'; } $content = null; $tip = idx($spec, 'tip'); if ($tip) { $meta['tip'] = $tip; $content = javelin_tag( 'span', array( 'aural' => true, ), $tip); } $buttons[] = javelin_tag( 'a', array( 'class' => implode(' ', $classes), 'href' => $href, 'sigil' => 'remarkup-assist has-tooltip', 'meta' => $meta, 'mustcapture' => $mustcapture, 'target' => $target, 'tabindex' => -1, ), phutil_tag( 'div', array( 'class' => 'remarkup-assist phui-icon-view phui-font-fa bluegrey '.$action, ), $content)); } $buttons = phutil_tag( 'div', array( 'class' => 'remarkup-assist-bar', ), $buttons); $monospaced_textareas = null; $monospaced_textareas_class = null; - $user = $this->getUser(); - - if ($user) { - $monospaced_textareas = $user - ->loadPreferences() - ->getPreference( - PhabricatorUserPreferences::PREFERENCE_MONOSPACED_TEXTAREAS); - if ($monospaced_textareas == 'enabled') { - $monospaced_textareas_class = 'PhabricatorMonospaced'; - } + + $monospaced_textareas = $viewer + ->loadPreferences() + ->getPreference( + PhabricatorUserPreferences::PREFERENCE_MONOSPACED_TEXTAREAS); + if ($monospaced_textareas == 'enabled') { + $monospaced_textareas_class = 'PhabricatorMonospaced'; } $this->setCustomClass( 'remarkup-assist-textarea '.$monospaced_textareas_class); return javelin_tag( 'div', array( 'sigil' => 'remarkup-assist-control', ), array( $buttons, parent::renderInput(), )); } }