Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F18284124
D14390.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
54 KB
Referenced Files
None
Subscribers
None
D14390.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1570,6 +1570,7 @@
'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php',
'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php',
'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php',
+ 'PhabricatorApplicationEditEngine' => 'applications/transactions/editengine/PhabricatorApplicationEditEngine.php',
'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php',
'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php',
'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php',
@@ -2063,6 +2064,7 @@
'PhabricatorDataCacheSpec' => 'applications/cache/spec/PhabricatorDataCacheSpec.php',
'PhabricatorDataNotAttachedException' => 'infrastructure/storage/lisk/PhabricatorDataNotAttachedException.php',
'PhabricatorDatabaseSetupCheck' => 'applications/config/check/PhabricatorDatabaseSetupCheck.php',
+ 'PhabricatorDatasourceEditField' => 'applications/transactions/editfield/PhabricatorDatasourceEditField.php',
'PhabricatorDateTimeSettingsPanel' => 'applications/settings/panel/PhabricatorDateTimeSettingsPanel.php',
'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php',
'PhabricatorDefaultRequestExceptionHandler' => 'aphront/handler/PhabricatorDefaultRequestExceptionHandler.php',
@@ -2097,6 +2099,7 @@
'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php',
'PhabricatorEdgeType' => 'infrastructure/edges/type/PhabricatorEdgeType.php',
'PhabricatorEdgeTypeTestCase' => 'infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php',
+ 'PhabricatorEditField' => 'applications/transactions/editfield/PhabricatorEditField.php',
'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php',
'PhabricatorElasticSearchEngine' => 'applications/search/engine/PhabricatorElasticSearchEngine.php',
'PhabricatorElasticSearchSetupCheck' => 'applications/config/check/PhabricatorElasticSearchSetupCheck.php',
@@ -2554,6 +2557,7 @@
'PhabricatorPasteController' => 'applications/paste/controller/PhabricatorPasteController.php',
'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php',
'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php',
+ 'PhabricatorPasteEditEngine' => 'applications/paste/editor/PhabricatorPasteEditEngine.php',
'PhabricatorPasteEditor' => 'applications/paste/editor/PhabricatorPasteEditor.php',
'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php',
'PhabricatorPastePastePHIDType' => 'applications/paste/phid/PhabricatorPastePastePHIDType.php',
@@ -2654,6 +2658,7 @@
'PhabricatorPolicyDAO' => 'applications/policy/storage/PhabricatorPolicyDAO.php',
'PhabricatorPolicyDataTestCase' => 'applications/policy/__tests__/PhabricatorPolicyDataTestCase.php',
'PhabricatorPolicyEditController' => 'applications/policy/controller/PhabricatorPolicyEditController.php',
+ 'PhabricatorPolicyEditField' => 'applications/transactions/editfield/PhabricatorPolicyEditField.php',
'PhabricatorPolicyException' => 'applications/policy/exception/PhabricatorPolicyException.php',
'PhabricatorPolicyExplainController' => 'applications/policy/controller/PhabricatorPolicyExplainController.php',
'PhabricatorPolicyFilter' => 'applications/policy/filter/PhabricatorPolicyFilter.php',
@@ -2917,6 +2922,7 @@
'PhabricatorSearchWorker' => 'applications/search/worker/PhabricatorSearchWorker.php',
'PhabricatorSecurityConfigOptions' => 'applications/config/option/PhabricatorSecurityConfigOptions.php',
'PhabricatorSecuritySetupCheck' => 'applications/config/check/PhabricatorSecuritySetupCheck.php',
+ 'PhabricatorSelectEditField' => 'applications/transactions/editfield/PhabricatorSelectEditField.php',
'PhabricatorSendGridConfigOptions' => 'applications/config/option/PhabricatorSendGridConfigOptions.php',
'PhabricatorSessionsSettingsPanel' => 'applications/settings/panel/PhabricatorSessionsSettingsPanel.php',
'PhabricatorSettingsAddEmailAction' => 'applications/settings/action/PhabricatorSettingsAddEmailAction.php',
@@ -2957,6 +2963,7 @@
'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php',
'PhabricatorSortTableUIExample' => 'applications/uiexample/examples/PhabricatorSortTableUIExample.php',
'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php',
+ 'PhabricatorSpaceEditField' => 'applications/transactions/editfield/PhabricatorSpaceEditField.php',
'PhabricatorSpacesApplication' => 'applications/spaces/application/PhabricatorSpacesApplication.php',
'PhabricatorSpacesArchiveController' => 'applications/spaces/controller/PhabricatorSpacesArchiveController.php',
'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php',
@@ -3063,6 +3070,8 @@
'PhabricatorTestNoCycleEdgeType' => 'applications/transactions/edges/PhabricatorTestNoCycleEdgeType.php',
'PhabricatorTestStorageEngine' => 'applications/files/engine/PhabricatorTestStorageEngine.php',
'PhabricatorTestWorker' => 'infrastructure/daemon/workers/__tests__/PhabricatorTestWorker.php',
+ 'PhabricatorTextAreaEditField' => 'applications/transactions/editfield/PhabricatorTextAreaEditField.php',
+ 'PhabricatorTextEditField' => 'applications/transactions/editfield/PhabricatorTextEditField.php',
'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php',
'PhabricatorTimeGuard' => 'infrastructure/time/PhabricatorTimeGuard.php',
'PhabricatorTimeTestCase' => 'infrastructure/time/__tests__/PhabricatorTimeTestCase.php',
@@ -3084,6 +3093,7 @@
'PhabricatorTokenReceiverQuery' => 'applications/tokens/query/PhabricatorTokenReceiverQuery.php',
'PhabricatorTokenTokenPHIDType' => 'applications/tokens/phid/PhabricatorTokenTokenPHIDType.php',
'PhabricatorTokenUIEventListener' => 'applications/tokens/event/PhabricatorTokenUIEventListener.php',
+ 'PhabricatorTokenizerEditField' => 'applications/transactions/editfield/PhabricatorTokenizerEditField.php',
'PhabricatorTokensApplication' => 'applications/tokens/application/PhabricatorTokensApplication.php',
'PhabricatorTokensSettingsPanel' => 'applications/settings/panel/PhabricatorTokensSettingsPanel.php',
'PhabricatorTooltipUIExample' => 'applications/uiexample/examples/PhabricatorTooltipUIExample.php',
@@ -5489,6 +5499,7 @@
'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController',
'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController',
+ 'PhabricatorApplicationEditEngine' => 'Phobject',
'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController',
'PhabricatorApplicationLaunchView' => 'AphrontTagView',
'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController',
@@ -6080,6 +6091,7 @@
'PhabricatorDataCacheSpec' => 'PhabricatorCacheSpec',
'PhabricatorDataNotAttachedException' => 'Exception',
'PhabricatorDatabaseSetupCheck' => 'PhabricatorSetupCheck',
+ 'PhabricatorDatasourceEditField' => 'PhabricatorTokenizerEditField',
'PhabricatorDateTimeSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorDebugController' => 'PhabricatorController',
'PhabricatorDefaultRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
@@ -6113,6 +6125,7 @@
'PhabricatorEdgeTestCase' => 'PhabricatorTestCase',
'PhabricatorEdgeType' => 'Phobject',
'PhabricatorEdgeTypeTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorEditField' => 'Phobject',
'PhabricatorEditor' => 'Phobject',
'PhabricatorElasticSearchEngine' => 'PhabricatorSearchEngine',
'PhabricatorElasticSearchSetupCheck' => 'PhabricatorSetupCheck',
@@ -6647,6 +6660,7 @@
'PhabricatorPasteController' => 'PhabricatorController',
'PhabricatorPasteDAO' => 'PhabricatorLiskDAO',
'PhabricatorPasteEditController' => 'PhabricatorPasteController',
+ 'PhabricatorPasteEditEngine' => 'PhabricatorApplicationEditEngine',
'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorPasteListController' => 'PhabricatorPasteController',
'PhabricatorPastePastePHIDType' => 'PhabricatorPHIDType',
@@ -6762,6 +6776,7 @@
'PhabricatorPolicyDAO' => 'PhabricatorLiskDAO',
'PhabricatorPolicyDataTestCase' => 'PhabricatorTestCase',
'PhabricatorPolicyEditController' => 'PhabricatorPolicyController',
+ 'PhabricatorPolicyEditField' => 'PhabricatorEditField',
'PhabricatorPolicyException' => 'Exception',
'PhabricatorPolicyExplainController' => 'PhabricatorPolicyController',
'PhabricatorPolicyFilter' => 'Phobject',
@@ -7090,6 +7105,7 @@
'PhabricatorSearchWorker' => 'PhabricatorWorker',
'PhabricatorSecurityConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorSecuritySetupCheck' => 'PhabricatorSetupCheck',
+ 'PhabricatorSelectEditField' => 'PhabricatorEditField',
'PhabricatorSendGridConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorSessionsSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsAddEmailAction' => 'PhabricatorSystemAction',
@@ -7140,6 +7156,7 @@
'PhabricatorSlugTestCase' => 'PhabricatorTestCase',
'PhabricatorSortTableUIExample' => 'PhabricatorUIExample',
'PhabricatorSourceCodeView' => 'AphrontView',
+ 'PhabricatorSpaceEditField' => 'PhabricatorEditField',
'PhabricatorSpacesApplication' => 'PhabricatorApplication',
'PhabricatorSpacesArchiveController' => 'PhabricatorSpacesController',
'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability',
@@ -7252,6 +7269,8 @@
'PhabricatorTestNoCycleEdgeType' => 'PhabricatorEdgeType',
'PhabricatorTestStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorTestWorker' => 'PhabricatorWorker',
+ 'PhabricatorTextAreaEditField' => 'PhabricatorEditField',
+ 'PhabricatorTextEditField' => 'PhabricatorEditField',
'PhabricatorTime' => 'Phobject',
'PhabricatorTimeGuard' => 'Phobject',
'PhabricatorTimeTestCase' => 'PhabricatorTestCase',
@@ -7278,6 +7297,7 @@
'PhabricatorTokenReceiverQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorTokenTokenPHIDType' => 'PhabricatorPHIDType',
'PhabricatorTokenUIEventListener' => 'PhabricatorEventListener',
+ 'PhabricatorTokenizerEditField' => 'PhabricatorEditField',
'PhabricatorTokensApplication' => 'PhabricatorApplication',
'PhabricatorTokensSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorTooltipUIExample' => 'PhabricatorUIExample',
diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php
--- a/src/applications/base/controller/PhabricatorController.php
+++ b/src/applications/base/controller/PhabricatorController.php
@@ -521,6 +521,14 @@
}
+ public function buildApplicationCrumbsForEditEngine() {
+ // TODO: This is kind of gross, I'm bascially just making this public so
+ // I can use it in EditEngine. We could do this without making it public
+ // by using controller delegation, or make it properly public.
+ return $this->buildApplicationCrumbs();
+ }
+
+
/* -( Deprecated )--------------------------------------------------------- */
diff --git a/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php b/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
--- a/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
+++ b/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php
@@ -44,16 +44,11 @@
$paste = PhabricatorPaste::initializeNewPaste($viewer);
- $file = PhabricatorPasteEditor::initializeFileForPaste(
- $viewer,
- $title,
- $content);
-
$xactions = array();
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
- ->setNewValue($file->getPHID());
+ ->setNewValue($content);
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
diff --git a/src/applications/paste/controller/PhabricatorPasteEditController.php b/src/applications/paste/controller/PhabricatorPasteEditController.php
--- a/src/applications/paste/controller/PhabricatorPasteEditController.php
+++ b/src/applications/paste/controller/PhabricatorPasteEditController.php
@@ -3,248 +3,9 @@
final class PhabricatorPasteEditController extends PhabricatorPasteController {
public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $parent = null;
- $parent_id = null;
- if (!$id) {
- $is_create = true;
-
- $paste = PhabricatorPaste::initializeNewPaste($viewer);
-
- $parent_id = $request->getStr('parent');
- if ($parent_id) {
- // NOTE: If the Paste is forked from a paste which the user no longer
- // has permission to see, we still let them edit it.
- $parent = id(new PhabricatorPasteQuery())
- ->setViewer($viewer)
- ->withIDs(array($parent_id))
- ->needContent(true)
- ->needRawContent(true)
- ->execute();
- $parent = head($parent);
-
- if ($parent) {
- $paste->setParentPHID($parent->getPHID());
- $paste->setViewPolicy($parent->getViewPolicy());
- }
- }
-
- $paste->setAuthorPHID($viewer->getPHID());
- $paste->attachRawContent('');
- } else {
- $is_create = false;
-
- $paste = id(new PhabricatorPasteQuery())
- ->setViewer($viewer)
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->withIDs(array($id))
- ->needRawContent(true)
- ->executeOne();
- if (!$paste) {
- return new Aphront404Response();
- }
- }
-
- $v_space = $paste->getSpacePHID();
- if ($is_create && $parent) {
- $v_title = pht('Fork of %s', $parent->getFullName());
- $v_language = $parent->getLanguage();
- $v_text = $parent->getRawContent();
- $v_space = $parent->getSpacePHID();
- } else {
- $v_title = $paste->getTitle();
- $v_language = $paste->getLanguage();
- $v_text = $paste->getRawContent();
- }
- $v_view_policy = $paste->getViewPolicy();
- $v_edit_policy = $paste->getEditPolicy();
- $v_status = $paste->getStatus();
-
- if ($is_create) {
- $v_projects = array();
- } else {
- $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
- $paste->getPHID(),
- PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
- $v_projects = array_reverse($v_projects);
- }
-
- $validation_exception = null;
- if ($request->isFormPost()) {
- $xactions = array();
-
- $v_text = $request->getStr('text');
- $v_title = $request->getStr('title');
- $v_language = $request->getStr('language');
- $v_view_policy = $request->getStr('can_view');
- $v_edit_policy = $request->getStr('can_edit');
- $v_projects = $request->getArr('projects');
- $v_space = $request->getStr('spacePHID');
- $v_status = $request->getStr('status');
-
- // NOTE: The author is the only editor and can always view the paste,
- // so it's impossible for them to choose an invalid policy.
-
- if ($is_create || ($v_text !== $paste->getRawContent())) {
- $file = PhabricatorPasteEditor::initializeFileForPaste(
- $viewer,
- $v_title,
- $v_text);
-
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
- ->setNewValue($file->getPHID());
- }
-
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
- ->setNewValue($v_title);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
- ->setNewValue($v_language);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
- ->setNewValue($v_view_policy);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
- ->setNewValue($v_edit_policy);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
- ->setNewValue($v_space);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_STATUS)
- ->setNewValue($v_status);
-
- $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
- ->setMetadataValue('edge:type', $proj_edge_type)
- ->setNewValue(array('=' => array_fuse($v_projects)));
-
- $editor = id(new PhabricatorPasteEditor())
- ->setActor($viewer)
- ->setContentSourceFromRequest($request)
- ->setContinueOnNoEffect(true);
-
- try {
- $xactions = $editor->applyTransactions($paste, $xactions);
- return id(new AphrontRedirectResponse())->setURI($paste->getURI());
- } catch (PhabricatorApplicationTransactionValidationException $ex) {
- $validation_exception = $ex;
- }
- }
-
- $form = new AphrontFormView();
-
- $langs = array(
- '' => pht('(Detect From Filename in Title)'),
- ) + PhabricatorEnv::getEnvConfig('pygments.dropdown-choices');
-
- $form
- ->setUser($viewer)
- ->addHiddenInput('parent', $parent_id)
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Title'))
- ->setValue($v_title)
- ->setName('title'))
- ->appendChild(
- id(new AphrontFormSelectControl())
- ->setLabel(pht('Language'))
- ->setName('language')
- ->setValue($v_language)
- ->setOptions($langs));
-
- $policies = id(new PhabricatorPolicyQuery())
- ->setViewer($viewer)
- ->setObject($paste)
- ->execute();
-
- $form->appendChild(
- id(new AphrontFormPolicyControl())
- ->setUser($viewer)
- ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
- ->setPolicyObject($paste)
- ->setPolicies($policies)
- ->setValue($v_view_policy)
- ->setSpacePHID($v_space)
- ->setName('can_view'));
-
- $form->appendChild(
- id(new AphrontFormPolicyControl())
- ->setUser($viewer)
- ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
- ->setPolicyObject($paste)
- ->setPolicies($policies)
- ->setValue($v_edit_policy)
- ->setName('can_edit'));
-
- $form->appendChild(
- id(new AphrontFormSelectControl())
- ->setLabel(pht('Status'))
- ->setName('status')
- ->setValue($v_status)
- ->setOptions($paste->getStatusNameMap()));
-
- $form->appendControl(
- id(new AphrontFormTokenizerControl())
- ->setLabel(pht('Projects'))
- ->setName('projects')
- ->setValue($v_projects)
- ->setDatasource(new PhabricatorProjectDatasource()));
-
- $form
- ->appendChild(
- id(new AphrontFormTextAreaControl())
- ->setLabel(pht('Text'))
- ->setValue($v_text)
- ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
- ->setCustomClass('PhabricatorMonospaced')
- ->setName('text'));
-
- $submit = new AphrontFormSubmitControl();
-
- if (!$is_create) {
- $submit->addCancelButton($paste->getURI());
- $submit->setValue(pht('Save Paste'));
- $title = pht('Edit %s', $paste->getFullName());
- $short = pht('Edit');
- } else {
- $submit->setValue(pht('Create Paste'));
- $title = pht('Create New Paste');
- $short = pht('Create');
- }
-
- $form->appendChild($submit);
-
- $form_box = id(new PHUIObjectBoxView())
- ->setHeaderText($title)
- ->setForm($form);
-
- if ($validation_exception) {
- $form_box->setValidationException($validation_exception);
- }
-
- $crumbs = $this->buildApplicationCrumbs();
- if (!$is_create) {
- $crumbs->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
- }
- $crumbs->addTextCrumb($short);
-
- return $this->buildApplicationPage(
- array(
- $crumbs,
- $form_box,
- ),
- array(
- 'title' => $title,
- ));
+ return id(new PhabricatorPasteEditEngine())
+ ->setController($this)
+ ->buildResponse();
}
}
diff --git a/src/applications/paste/controller/PhabricatorPasteViewController.php b/src/applications/paste/controller/PhabricatorPasteViewController.php
--- a/src/applications/paste/controller/PhabricatorPasteViewController.php
+++ b/src/applications/paste/controller/PhabricatorPasteViewController.php
@@ -137,9 +137,7 @@
$paste,
PhabricatorPolicyCapability::CAN_EDIT);
- $can_fork = $viewer->isLoggedIn();
$id = $paste->getID();
- $fork_uri = $this->getApplicationURI('/create/?parent='.$id);
return id(new PhabricatorActionListView())
->setUser($viewer)
@@ -154,13 +152,6 @@
->setHref($this->getApplicationURI("edit/{$id}/")))
->addAction(
id(new PhabricatorActionView())
- ->setName(pht('Fork This Paste'))
- ->setIcon('fa-code-fork')
- ->setDisabled(!$can_fork)
- ->setWorkflow(!$can_fork)
- ->setHref($fork_uri))
- ->addAction(
- id(new PhabricatorActionView())
->setName(pht('View Raw File'))
->setIcon('fa-file-text-o')
->setHref($this->getApplicationURI("raw/{$id}/")));
diff --git a/src/applications/paste/editor/PhabricatorPasteEditEngine.php b/src/applications/paste/editor/PhabricatorPasteEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/paste/editor/PhabricatorPasteEditEngine.php
@@ -0,0 +1,69 @@
+<?php
+
+final class PhabricatorPasteEditEngine
+ extends PhabricatorApplicationEditEngine {
+
+ protected function newEditableObject() {
+ return PhabricatorPaste::initializeNewPaste($this->getViewer());
+ }
+
+ protected function newObjectQuery() {
+ return id(new PhabricatorPasteQuery())
+ ->needRawContent(true);
+ }
+
+ protected function getObjectCreateTitleText($object) {
+ return pht('Create New Paste');
+ }
+
+ protected function getObjectEditTitleText($object) {
+ return pht('Edit %s %s', $object->getMonogram(), $object->getTitle());
+ }
+
+ protected function getObjectEditShortText($object) {
+ return $object->getMonogram();
+ }
+
+ protected function getObjectCreateShortText($object) {
+ return pht('Create Paste');
+ }
+
+ protected function getObjectViewURI($object) {
+ return '/P'.$object->getID();
+ }
+
+ protected function buildCustomEditFields($object) {
+ $langs = array(
+ '' => pht('(Detect From Filename in Title)'),
+ ) + PhabricatorEnv::getEnvConfig('pygments.dropdown-choices');
+
+ return array(
+ id(new PhabricatorTextEditField())
+ ->setKey('title')
+ ->setLabel(pht('Title'))
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
+ ->setValue($object->getTitle()),
+ id(new PhabricatorSelectEditField())
+ ->setKey('language')
+ ->setLabel(pht('Language'))
+ ->setAliases(array('lang'))
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
+ ->setValue($object->getLanguage())
+ ->setOptions($langs),
+ id(new PhabricatorSelectEditField())
+ ->setKey('status')
+ ->setLabel(pht('Status'))
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_STATUS)
+ ->setValue($object->getStatus())
+ ->setOptions(PhabricatorPaste::getStatusNameMap()),
+ id(new PhabricatorTextAreaEditField())
+ ->setKey('text')
+ ->setLabel(pht('Text'))
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
+ ->setMonospaced(true)
+ ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
+ ->setValue($object->getRawContent()),
+ );
+ }
+
+}
diff --git a/src/applications/paste/editor/PhabricatorPasteEditor.php b/src/applications/paste/editor/PhabricatorPasteEditor.php
--- a/src/applications/paste/editor/PhabricatorPasteEditor.php
+++ b/src/applications/paste/editor/PhabricatorPasteEditor.php
@@ -3,6 +3,8 @@
final class PhabricatorPasteEditor
extends PhabricatorApplicationTransactionEditor {
+ private $fileName;
+
public function getEditorApplicationClass() {
return 'PhabricatorPasteApplication';
}
@@ -41,6 +43,35 @@
return $types;
}
+ protected function shouldApplyInitialEffects(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+ return true;
+ }
+
+ protected function applyInitialEffects(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+
+ // Find the most user-friendly filename we can by examining the title of
+ // the paste and the pending transactions. We'll use this if we create a
+ // new file to store raw content later.
+
+ $name = $object->getTitle();
+ if (!strlen($name)) {
+ $name = 'paste.raw';
+ }
+
+ $type_title = PhabricatorPasteTransaction::TYPE_TITLE;
+ foreach ($xactions as $xaction) {
+ if ($xaction->getTransactionType() == $type_title) {
+ $name = $xaction->getNewValue();
+ }
+ }
+
+ $this->fileName = $name;
+ }
+
protected function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
@@ -62,11 +93,26 @@
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
- case PhabricatorPasteTransaction::TYPE_CONTENT:
case PhabricatorPasteTransaction::TYPE_TITLE:
case PhabricatorPasteTransaction::TYPE_LANGUAGE:
case PhabricatorPasteTransaction::TYPE_STATUS:
return $xaction->getNewValue();
+ case PhabricatorPasteTransaction::TYPE_CONTENT:
+ // If this transaction does not really change the paste content, return
+ // the current file PHID so this transaction no-ops.
+ $new_content = $xaction->getNewValue();
+ $old_content = $object->getRawContent();
+ $file_phid = $object->getFilePHID();
+ if (($new_content === $old_content) && $file_phid) {
+ return $file_phid;
+ }
+
+ $file = self::initializeFileForPaste(
+ $this->getActor(),
+ $this->fileName,
+ $xaction->getNewValue());
+
+ return $file->getPHID();
}
}
diff --git a/src/applications/paste/mail/PasteCreateMailReceiver.php b/src/applications/paste/mail/PasteCreateMailReceiver.php
--- a/src/applications/paste/mail/PasteCreateMailReceiver.php
+++ b/src/applications/paste/mail/PasteCreateMailReceiver.php
@@ -21,16 +21,11 @@
$title = pht('Email Paste');
}
- $file = PhabricatorPasteEditor::initializeFileForPaste(
- $sender,
- $title,
- $mail->getCleanTextBody());
-
$xactions = array();
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
- ->setNewValue($file->getPHID());
+ ->setNewValue($mail->getCleanTextBody());
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
diff --git a/src/applications/paste/storage/PhabricatorPaste.php b/src/applications/paste/storage/PhabricatorPaste.php
--- a/src/applications/paste/storage/PhabricatorPaste.php
+++ b/src/applications/paste/storage/PhabricatorPaste.php
@@ -45,7 +45,8 @@
->setAuthorPHID($actor->getPHID())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
- ->setSpacePHID($actor->getDefaultSpacePHID());
+ ->setSpacePHID($actor->getDefaultSpacePHID())
+ ->attachRawContent(null);
}
public static function getStatusNameMap() {
diff --git a/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php b/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php
@@ -0,0 +1,303 @@
+<?php
+
+abstract class PhabricatorApplicationEditEngine extends Phobject {
+
+ private $viewer;
+ private $controller;
+
+ final public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ final public function getViewer() {
+ return $this->viewer;
+ }
+
+ final public function setController(PhabricatorController $controller) {
+ $this->controller = $controller;
+ $this->setViewer($controller->getViewer());
+ return $this;
+ }
+
+ final public function getController() {
+ return $this->controller;
+ }
+
+ final protected function buildEditFields($object) {
+ $viewer = $this->getViewer();
+ $editor = $object->getApplicationTransactionEditor();
+
+ $types = $editor->getTransactionTypesForObject($object);
+ $types = array_fuse($types);
+
+ $fields = $this->buildCustomEditFields($object);
+
+ if ($object instanceof PhabricatorPolicyInterface) {
+ $policies = id(new PhabricatorPolicyQuery())
+ ->setViewer($viewer)
+ ->setObject($object)
+ ->execute();
+
+ $map = array(
+ PhabricatorTransactions::TYPE_VIEW_POLICY => array(
+ 'key' => 'policy.view',
+ 'aliases' => array('view'),
+ 'capability' => PhabricatorPolicyCapability::CAN_VIEW,
+ ),
+ PhabricatorTransactions::TYPE_EDIT_POLICY => array(
+ 'key' => 'policy.edit',
+ 'aliases' => array('edit'),
+ 'capability' => PhabricatorPolicyCapability::CAN_EDIT,
+ ),
+ PhabricatorTransactions::TYPE_JOIN_POLICY => array(
+ 'key' => 'policy.join',
+ 'aliases' => array('join'),
+ 'capability' => PhabricatorPolicyCapability::CAN_JOIN,
+ ),
+ );
+
+ foreach ($map as $type => $spec) {
+ if (empty($types[$type])) {
+ continue;
+ }
+
+ $capability = $spec['capability'];
+ $key = $spec['key'];
+ $aliases = $spec['aliases'];
+
+ $policy_field = id(new PhabricatorPolicyEditField())
+ ->setKey($key)
+ ->setAliases($aliases)
+ ->setCapability($capability)
+ ->setPolicies($policies)
+ ->setTransactionType($type)
+ ->setValue($object->getPolicy($capability));
+ $fields[] = $policy_field;
+
+ if ($object instanceof PhabricatorSpacesInterface) {
+ if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
+ $type_space = PhabricatorTransactions::TYPE_SPACE;
+ if (isset($types[$type_space])) {
+ $space_field = id(new PhabricatorSpaceEditField())
+ ->setKey('spacePHID')
+ ->setAliases(array('space', 'policy.space'))
+ ->setTransactionType($type_space)
+ ->setValue($object->getSpacePHID());
+ $fields[] = $space_field;
+
+ $policy_field->setSpaceField($space_field);
+ }
+ }
+ }
+ }
+ }
+
+ $edge_type = PhabricatorTransactions::TYPE_EDGE;
+ $object_phid = $object->getPHID();
+
+ $project_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
+
+ if ($object instanceof PhabricatorProjectInterface) {
+ if (isset($types[$edge_type])) {
+ if ($object_phid) {
+ $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $object_phid,
+ $project_edge_type);
+ $project_phids = array_reverse($project_phids);
+ } else {
+ $project_phids = array();
+ }
+
+ $edge_field = id(new PhabricatorDatasourceEditField())
+ ->setKey('projectPHIDs')
+ ->setLabel(pht('Projects'))
+ ->setDatasource(new PhabricatorProjectDatasource())
+ ->setAliases(array('project', 'projects'))
+ ->setTransactionType($edge_type)
+ ->setMetadataValue('edge:type', $project_edge_type)
+ ->setValue($project_phids);
+ $fields[] = $edge_field;
+ }
+ }
+
+ $subscribers_type = PhabricatorTransactions::TYPE_SUBSCRIBERS;
+
+ if ($object instanceof PhabricatorSubscribableInterface) {
+ if (isset($types[$subscribers_type])) {
+ if ($object_phid) {
+ $sub_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
+ $object_phid);
+ } else {
+ // TODO: Allow applications to provide default subscribers; Maniphest
+ // does this at a minimum.
+ $sub_phids = array();
+ }
+
+ $subscribers_field = id(new PhabricatorDatasourceEditField())
+ ->setKey('subscriberPHIDs')
+ ->setLabel(pht('Subscribers'))
+ ->setDatasource(new PhabricatorMetaMTAMailableDatasource())
+ ->setAliases(array('subscriber', 'subscribers'))
+ ->setTransactionType($subscribers_type)
+ ->setValue($sub_phids);
+ $fields[] = $subscribers_field;
+ }
+ }
+
+ return $fields;
+ }
+
+ abstract protected function newEditableObject();
+ abstract protected function newObjectQuery();
+ abstract protected function buildCustomEditFields($object);
+
+ abstract protected function getObjectCreateTitleText($object);
+ abstract protected function getObjectEditTitleText($object);
+ abstract protected function getObjectCreateShortText($object);
+ abstract protected function getObjectEditShortText($object);
+ abstract protected function getObjectViewURI($object);
+
+ protected function getObjectCreateCancelURI($object) {
+ return $this->getController()->getApplicationURI();
+ }
+
+ protected function getObjectEditCancelURI($object) {
+ return $this->getObjectViewURI($object);
+ }
+
+ protected function getObjectCreateButtonText($object) {
+ return $this->getObjectCreateTitleText($object);
+ }
+
+ protected function getObjectEditButtonText($object) {
+ return pht('Save Changes');
+ }
+
+ final public function buildResponse() {
+ $controller = $this->getController();
+ $viewer = $this->getViewer();
+ $request = $controller->getRequest();
+
+ $id = $request->getURIData('id');
+ if ($id) {
+ $object = $this->newObjectQuery()
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$object) {
+ return new Aphront404Response();
+ }
+
+ $is_create = false;
+ } else {
+ $object = $this->newEditableObject();
+
+ $is_create = true;
+ }
+
+ $fields = $this->buildEditFields($object);
+
+ foreach ($fields as $field) {
+ $field
+ ->setViewer($viewer)
+ ->setObject($object);
+ }
+
+ $validation_exception = null;
+ if ($request->isFormPost()) {
+ foreach ($fields as $field) {
+ $field->readValueFromSubmit($request);
+ }
+
+ $template = $object->getApplicationTransactionTemplate();
+
+ $xactions = array();
+ foreach ($fields as $field) {
+ $xactions[] = $field->generateTransaction(clone $template);
+ }
+
+ $editor = $object->getApplicationTransactionEditor()
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(false);
+
+ try {
+
+ $editor->applyTransactions($object, $xactions);
+
+ return id(new AphrontRedirectResponse())
+ ->setURI($this->getObjectViewURI($object));
+ } catch (PhabricatorApplicationTransactionValidationException $ex) {
+ $validation_exception = $ex;
+ }
+ } else {
+ if ($is_create) {
+ foreach ($fields as $field) {
+ $field->readValueFromRequest($request);
+ }
+ } else {
+ foreach ($fields as $field) {
+ $field->readValueFromObject($object);
+ }
+ }
+ }
+
+ $box = id(new PHUIObjectBoxView())
+ ->setUser($viewer);
+
+ $crumbs = $controller->buildApplicationCrumbsForEditEngine();
+
+ if ($is_create) {
+ $header_text = $this->getObjectCreateTitleText($object);
+
+ $crumbs->addTextCrumb(
+ $this->getObjectCreateShortText($object));
+
+ $cancel_uri = $this->getObjectCreateCancelURI($object);
+ $submit_button = $this->getObjectCreateButtonText($object);
+ } else {
+ $header_text = $this->getObjectEditTitleText($object);
+
+ $crumbs->addTextCrumb(
+ $this->getObjectEditShortText($object),
+ $this->getObjectViewURI($object));
+
+ $cancel_uri = $this->getObjectEditCancelURI($object);
+ $submit_button = $this->getObjectEditButtonText($object);
+ }
+
+ $box->setHeaderText($header_text);
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer);
+
+ foreach ($fields as $field) {
+ $field->appendToForm($form);
+ }
+
+ $form->appendControl(
+ id(new AphrontFormSubmitControl())
+ ->addCancelButton($cancel_uri)
+ ->setValue($submit_button));
+
+ $box->appendChild($form);
+
+ if ($validation_exception) {
+ $box->setValidationException($validation_exception);
+ }
+
+ return $controller->newPage()
+ ->setTitle($header_text)
+ ->setCrumbs($crumbs)
+ ->appendChild($box);
+ }
+
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php b/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorDatasourceEditField.php
@@ -0,0 +1,21 @@
+<?php
+
+final class PhabricatorDatasourceEditField
+ extends PhabricatorTokenizerEditField {
+
+ private $datasource;
+
+ public function setDatasource(PhabricatorTypeaheadDatasource $datasource) {
+ $this->datasource = $datasource;
+ return $this;
+ }
+
+ public function getDatasource() {
+ return $this->datasource;
+ }
+
+ protected function newDatasource() {
+ return id(clone $this->getDatasource());
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorEditField.php
@@ -0,0 +1,212 @@
+<?php
+
+abstract class PhabricatorEditField extends Phobject {
+
+ private $key;
+ private $viewer;
+ private $label;
+ private $aliases = array();
+ private $value;
+ private $hasValue = false;
+ private $object;
+ private $transactionType;
+ private $metadata = array();
+
+ public function setKey($key) {
+ $this->key = $key;
+ return $this;
+ }
+
+ public function getKey() {
+ return $this->key;
+ }
+
+ public function setLabel($label) {
+ $this->label = $label;
+ return $this;
+ }
+
+ public function getLabel() {
+ return $this->label;
+ }
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ public function setAliases(array $aliases) {
+ $this->aliases = $aliases;
+ return $this;
+ }
+
+ public function getAliases() {
+ return $this->aliases;
+ }
+
+ public function setObject($object) {
+ $this->object = $object;
+ return $this;
+ }
+
+ public function getObject() {
+ return $this->object;
+ }
+
+ abstract protected function newControl();
+
+ protected function renderControl() {
+ $control = $this->newControl();
+ if ($control === null) {
+ return null;
+ }
+
+ $control
+ ->setValue($this->getValueForControl())
+ ->setName($this->getKey());
+
+ if (!$control->getLabel()) {
+ $control->setLabel($this->getLabel());
+ }
+
+ return $control;
+ }
+
+ public function appendToForm(AphrontFormView $form) {
+ $control = $this->renderControl();
+ if ($control !== null) {
+ $form->appendControl($control);
+ }
+ return $this;
+ }
+
+ protected function getValueForControl() {
+ return $this->getValue();
+ }
+
+ protected function getValue() {
+ return $this->value;
+ }
+
+ public function setValue($value) {
+ $this->hasValue = true;
+ $this->value = $value;
+ return $this;
+ }
+
+ public function generateTransaction(
+ PhabricatorApplicationTransaction $xaction) {
+
+ $xaction
+ ->setTransactionType($this->getTransactionType())
+ ->setNewValue($this->getValueForTransaction());
+
+ foreach ($this->metadata as $key => $value) {
+ $xaction->setMetadataValue($key, $value);
+ }
+
+ return $xaction;
+ }
+
+ public function setMetadataValue($key, $value) {
+ $this->metadata[$key] = $value;
+ return $this;
+ }
+
+ protected function getValueForTransaction() {
+ return $this->getValue();
+ }
+
+ public function getTransactionType() {
+ if (!$this->transactionType) {
+ throw new PhutilInvalidStateException('setTransactionType');
+ }
+ return $this->transactionType;
+ }
+
+ public function setTransactionType($type) {
+ $this->transactionType = $type;
+ return $this;
+ }
+
+ public function readValueFromRequest(AphrontRequest $request) {
+ $check = array_merge(array($this->getKey()), $this->getAliases());
+ foreach ($check as $key) {
+ if (!$this->getValueExistsInRequest($request, $key)) {
+ continue;
+ }
+
+ $this->value = $this->getValueFromRequest($request, $key);
+ return;
+ }
+
+ $this->readValueFromObject($this->getObject());
+
+ return $this;
+ }
+
+ public function readValueFromObject($object) {
+ $this->value = $this->getValueFromObject($object);
+ return $this;
+ }
+
+ protected function getValueFromObject($object) {
+ if ($this->hasValue) {
+ return $this->value;
+ } else {
+ return $this->getDefaultValue();
+ }
+ }
+
+ protected function getValueExistsInRequest(AphrontRequest $request, $key) {
+ return $this->getValueExistsInSubmit($request, $key);
+ }
+
+ protected function getValueFromRequest(AphrontRequest $request, $key) {
+ return $this->getValueFromSubmit($request, $key);
+ }
+
+ public function readValueFromSubmit(AphrontRequest $request) {
+ $key = $this->getKey();
+ if ($this->getValueExistsInSubmit($request, $key)) {
+ $value = $this->getValueFromSubmit($request, $key);
+ } else {
+ $value = $this->getDefaultValue();
+ }
+ $this->value = $value;
+ return $this;
+ }
+
+ protected function getValueExistsInSubmit(AphrontRequest $request, $key) {
+ return $request->getExists($key);
+ }
+
+ protected function getValueFromSubmit(AphrontRequest $request, $key) {
+ return $request->getStr($key);
+ }
+
+ protected function getDefaultValue() {
+ return null;
+ }
+
+ protected function getListFromRequest(
+ AphrontRequest $request,
+ $key) {
+
+ $list = $request->getArr($key, null);
+ if ($list === null) {
+ $list = $request->getStrList($key);
+ }
+
+ if (!$list) {
+ return array();
+ }
+
+ return $list;
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorPolicyEditField.php b/src/applications/transactions/editfield/PhabricatorPolicyEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorPolicyEditField.php
@@ -0,0 +1,54 @@
+<?php
+
+final class PhabricatorPolicyEditField
+ extends PhabricatorEditField {
+
+ private $policies;
+ private $capability;
+ private $spaceField;
+
+ public function setPolicies(array $policies) {
+ $this->policies = $policies;
+ return $this;
+ }
+
+ public function getPolicies() {
+ if ($this->policies === null) {
+ throw new PhutilInvalidStateException('setPolicies');
+ }
+ return $this->policies;
+ }
+
+ public function setCapability($capability) {
+ $this->capability = $capability;
+ return $this;
+ }
+
+ public function getCapability() {
+ return $this->capability;
+ }
+
+ public function setSpaceField(PhabricatorSpaceEditField $space_field) {
+ $this->spaceField = $space_field;
+ return $this;
+ }
+
+ public function getSpaceField() {
+ return $this->spaceField;
+ }
+
+ protected function newControl() {
+ $control = id(new AphrontFormPolicyControl())
+ ->setCapability($this->getCapability())
+ ->setPolicyObject($this->getObject())
+ ->setPolicies($this->getPolicies());
+
+ $space_field = $this->getSpaceField();
+ if ($space_field) {
+ $control->setSpacePHID($space_field->getValueForControl());
+ }
+
+ return $control;
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorSelectEditField.php b/src/applications/transactions/editfield/PhabricatorSelectEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorSelectEditField.php
@@ -0,0 +1,25 @@
+<?php
+
+final class PhabricatorSelectEditField
+ extends PhabricatorEditField {
+
+ private $options;
+
+ public function setOptions(array $options) {
+ $this->options = $options;
+ return $this;
+ }
+
+ public function getOptions() {
+ if ($this->options === null) {
+ throw new PhutilInvalidStateException('setOptions');
+ }
+ return $this->options;
+ }
+
+ protected function newControl() {
+ return id(new AphrontFormSelectControl())
+ ->setOptions($this->getOptions());
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorSpaceEditField.php b/src/applications/transactions/editfield/PhabricatorSpaceEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorSpaceEditField.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorSpaceEditField
+ extends PhabricatorEditField {
+
+ protected function newControl() {
+ // NOTE: This field doesn't do anything on its own, it just serves as a
+ // companion to the associated View Policy field.
+ return null;
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorTextAreaEditField.php b/src/applications/transactions/editfield/PhabricatorTextAreaEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorTextAreaEditField.php
@@ -0,0 +1,42 @@
+<?php
+
+final class PhabricatorTextAreaEditField
+ extends PhabricatorEditField {
+
+ private $monospaced;
+ private $height;
+
+ public function setMonospaced($monospaced) {
+ $this->monospaced = $monospaced;
+ return $this;
+ }
+
+ public function getMonospaced() {
+ return $this->monospaced;
+ }
+
+ public function setHeight($height) {
+ $this->height = $height;
+ return $this;
+ }
+
+ public function getHeight() {
+ return $this->height;
+ }
+
+ protected function newControl() {
+ $control = new AphrontFormTextAreaControl();
+
+ if ($this->getMonospaced()) {
+ $control->setCustomClass('PhabricatorMonospaced');
+ }
+
+ $height = $this->getHeight();
+ if ($height) {
+ $control->setHeight($height);
+ }
+
+ return $control;
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorTextEditField.php b/src/applications/transactions/editfield/PhabricatorTextEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorTextEditField.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorTextEditField
+ extends PhabricatorEditField {
+
+ protected function newControl() {
+ return new AphrontFormTextControl();
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorTokenizerEditField.php b/src/applications/transactions/editfield/PhabricatorTokenizerEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorTokenizerEditField.php
@@ -0,0 +1,90 @@
+<?php
+
+abstract class PhabricatorTokenizerEditField
+ extends PhabricatorEditField {
+
+ private $originalValue;
+
+ abstract protected function newDatasource();
+
+ protected function newControl() {
+ $control = id(new AphrontFormTokenizerControl())
+ ->setDatasource($this->newDatasource());
+
+ if ($this->originalValue !== null) {
+ $control->setOriginalValue($this->originalValue);
+ }
+
+ return $control;
+ }
+
+ public function setOriginalValue(array $value) {
+ $this->originalValue = $value;
+ return $this;
+ }
+
+ public function setValue($value) {
+ $this->originalValue = $value;
+ return parent::setValue($value);
+ }
+
+ protected function getValueFromSubmit(AphrontRequest $request, $key) {
+ // TODO: Maybe move this unusual read somewhere else so subclassing this
+ // correctly is easier?
+ $this->originalValue = $request->getArr($key.'.original');
+
+ return $this->getListFromRequest($request, $key);
+ }
+
+ protected function getDefaultValue() {
+ return array();
+ }
+
+ protected function getValueForTransaction() {
+ $new = parent::getValueForTransaction();
+
+ $edge_types = array(
+ PhabricatorTransactions::TYPE_EDGE => true,
+ PhabricatorTransactions::TYPE_SUBSCRIBERS => true,
+ );
+
+ if (isset($edge_types[$this->getTransactionType()])) {
+ if ($this->originalValue !== null) {
+ // If we're building an edge transaction and the request has data
+ // about the original value the user saw when they loaded the form,
+ // interpret the edit as a mixture of "+" and "-" operations instead
+ // of a single "=" operation. This limits our exposure to race
+ // conditions by making most concurrent edits merge correctly.
+
+ $new = parent::getValueForTransaction();
+ $old = $this->originalValue;
+
+ $add = array_diff($new, $old);
+ $rem = array_diff($old, $new);
+
+ $value = array();
+
+ if ($add) {
+ $value['+'] = array_fuse($add);
+ }
+ if ($rem) {
+ $value['-'] = array_fuse($rem);
+ }
+
+ return $value;
+ } else {
+
+ if (!is_array($new)) {
+ throw new Exception(print_r($new, true));
+ }
+
+ return array(
+ '=' => array_fuse($new),
+ );
+ }
+ }
+
+ return $new;
+ }
+
+}
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -242,6 +242,19 @@
return $this->applicationEmail;
}
+ public function getTransactionTypesForObject($object) {
+ $old = $this->object;
+ try {
+ $this->object = $object;
+ $result = $this->getTransactionTypes();
+ $this->object = $old;
+ } catch (Exception $ex) {
+ $this->object = $old;
+ throw $ex;
+ }
+ return $result;
+ }
+
public function getTransactionTypes() {
$types = array();
@@ -1650,7 +1663,7 @@
throw new Exception(
pht(
"Invalid '%s' value for PHID transaction. Value should contain only ".
- "keys '%s' (add PHIDs), '%' (remove PHIDs) and '%s' (set PHIDS).",
+ "keys '%s' (add PHIDs), '%s' (remove PHIDs) and '%s' (set PHIDS).",
'new',
'+',
'-',
diff --git a/src/view/control/AphrontTokenizerTemplateView.php b/src/view/control/AphrontTokenizerTemplateView.php
--- a/src/view/control/AphrontTokenizerTemplateView.php
+++ b/src/view/control/AphrontTokenizerTemplateView.php
@@ -6,6 +6,7 @@
private $name;
private $id;
private $browseURI;
+ private $originalValue;
public function setBrowseURI($browse_uri) {
$this->browseURI = $browse_uri;
@@ -36,6 +37,15 @@
return $this->name;
}
+ public function setOriginalValue(array $original_value) {
+ $this->originalValue = $original_value;
+ return $this;
+ }
+
+ public function getOriginalValue() {
+ return $this->originalValue;
+ }
+
public function render() {
require_celerity_resource('aphront-tokenizer-control-css');
@@ -85,6 +95,20 @@
$classes[] = 'has-browse';
}
+ $original = array();
+ $original_value = $this->getOriginalValue();
+ if ($original_value) {
+ foreach ($this->getOriginalValue() as $value) {
+ $original[] = phutil_tag(
+ 'input',
+ array(
+ 'type' => 'hidden',
+ 'name' => $name.'.original[]',
+ 'value' => $value,
+ ));
+ }
+ }
+
$frame = javelin_tag(
'div',
array(
@@ -94,6 +118,7 @@
array(
$container,
$browse,
+ $original,
));
return $frame;
diff --git a/src/view/form/control/AphrontFormTokenizerControl.php b/src/view/form/control/AphrontFormTokenizerControl.php
--- a/src/view/form/control/AphrontFormTokenizerControl.php
+++ b/src/view/form/control/AphrontFormTokenizerControl.php
@@ -7,6 +7,7 @@
private $limit;
private $placeholder;
private $handles;
+ private $originalValue;
public function setDatasource(PhabricatorTypeaheadDatasource $datasource) {
$this->datasource = $datasource;
@@ -32,6 +33,15 @@
return $this;
}
+ public function setOriginalValue(array $original_value) {
+ $this->originalValue = $original_value;
+ return $this;
+ }
+
+ public function getOriginalValue() {
+ return $this->originalValue;
+ }
+
public function willRender() {
// Load the handles now so we'll get a bulk load later on when we actually
// render them.
@@ -69,10 +79,15 @@
$token->setInputName($this->getName());
}
- $template = new AphrontTokenizerTemplateView();
- $template->setName($name);
- $template->setID($id);
- $template->setValue($tokens);
+ $template = id(new AphrontTokenizerTemplateView())
+ ->setName($name)
+ ->setID($id)
+ ->setValue($tokens);
+
+ $original_value = $this->getOriginalValue();
+ if ($original_value !== null) {
+ $template->setOriginalValue($original_value);
+ }
$username = null;
if ($this->user) {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Aug 24, 3:04 AM (13 h, 4 m)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/r4/xf/qol2uezpej7gmza6
Default Alt Text
D14390.diff (54 KB)
Attached To
Mode
D14390: Implement a basic version of ApplicationEditor in Paste
Attached
Detach File
Event Timeline
Log In to Comment