mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-18 10:41:08 +01:00
Apply ApplicationTransaction edits and deletes via Ajax if available
Summary: When possible, replace the edited or deleted transaction inline using Ajax. Test Plan: Repeatedly edited and deleted transactions. Clicked their anchors to verify anchors were correctly preserved. Reviewers: vrana, btrahan, chad Reviewed By: vrana CC: aran Maniphest Tasks: T1082 Differential Revision: https://secure.phabricator.com/D4150
This commit is contained in:
parent
26dd2a0eef
commit
025411990b
5 changed files with 144 additions and 24 deletions
|
@ -4,11 +4,9 @@ final class PhabricatorApplicationTransactionCommentEditController
|
|||
extends PhabricatorApplicationTransactionController {
|
||||
|
||||
private $phid;
|
||||
private $anchor;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->phid = $data['phid'];
|
||||
$this->anchor = idx($data, 'anchor');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
@ -59,7 +57,26 @@ final class PhabricatorApplicationTransactionCommentEditController
|
|||
)))
|
||||
->applyEdit($xaction, $comment);
|
||||
|
||||
return id(new AphrontReloadResponse())->setURI($obj_handle->getURI());
|
||||
if ($request->isAjax()) {
|
||||
$view = id(new PhabricatorApplicationTransactionView())
|
||||
->setViewer($user)
|
||||
->setTransactions(array($xaction));
|
||||
|
||||
$anchor = $request->getStr('anchor');
|
||||
if ($anchor) {
|
||||
$view->setAnchorOffset($anchor);
|
||||
}
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent(
|
||||
array(
|
||||
'xactions' => mpull(
|
||||
$view->buildEvents(),
|
||||
'render',
|
||||
'getTransactionPHID'),
|
||||
));
|
||||
} else {
|
||||
return id(new AphrontReloadResponse())->setURI($obj_handle->getURI());
|
||||
}
|
||||
}
|
||||
|
||||
$dialog = id(new AphrontDialogView())
|
||||
|
@ -67,6 +84,7 @@ final class PhabricatorApplicationTransactionCommentEditController
|
|||
->setTitle(pht('Edit Comment'));
|
||||
|
||||
$dialog
|
||||
->addHiddenInput('anchor', $request->getStr('anchor'))
|
||||
->appendChild(
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setName('text')
|
||||
|
|
|
@ -8,7 +8,7 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
|||
private $viewer;
|
||||
private $transactions;
|
||||
private $engine;
|
||||
private $anchorOffset = 0;
|
||||
private $anchorOffset = 1;
|
||||
private $showEditActions = true;
|
||||
|
||||
public function setShowEditActions($show_edit_actions) {
|
||||
|
@ -41,33 +41,19 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
public function buildEvents() {
|
||||
$field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT;
|
||||
$engine = $this->getOrBuildEngine();
|
||||
|
||||
if (!$this->engine) {
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($this->viewer);
|
||||
foreach ($this->transactions as $xaction) {
|
||||
if (!$xaction->hasComment()) {
|
||||
continue;
|
||||
}
|
||||
$engine->addObject($xaction->getComment(), $field);
|
||||
}
|
||||
$engine->process();
|
||||
|
||||
$this->engine = $engine;
|
||||
}
|
||||
|
||||
$view = new PhabricatorTimelineView();
|
||||
$viewer = $this->viewer;
|
||||
|
||||
$anchor = $this->anchorOffset;
|
||||
$events = array();
|
||||
foreach ($this->transactions as $xaction) {
|
||||
if ($xaction->shouldHide()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$anchor++;
|
||||
$event = id(new PhabricatorTimelineEventView())
|
||||
->setViewer($viewer)
|
||||
->setTransactionPHID($xaction->getPHID())
|
||||
|
@ -79,6 +65,9 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
|||
->setContentSource($xaction->getContentSource())
|
||||
->setAnchor($anchor);
|
||||
|
||||
$anchor++;
|
||||
|
||||
|
||||
$has_deleted_comment = $xaction->getComment() &&
|
||||
$xaction->getComment()->getIsDeleted();
|
||||
|
||||
|
@ -102,16 +91,59 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
|||
|
||||
if ($xaction->hasComment()) {
|
||||
$event->appendChild(
|
||||
$this->engine->getOutput($xaction->getComment(), $field));
|
||||
$engine->getOutput($xaction->getComment(), $field));
|
||||
} else if ($has_deleted_comment) {
|
||||
$event->appendChild(
|
||||
'<em>'.pht('This comment has been deleted.').'</em>');
|
||||
}
|
||||
|
||||
$events[] = $event;
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$view = new PhabricatorTimelineView();
|
||||
foreach ($this->buildEvents() as $event) {
|
||||
$view->addEvent($event);
|
||||
}
|
||||
|
||||
if ($this->getShowEditActions()) {
|
||||
$list_id = celerity_generate_unique_node_id();
|
||||
|
||||
$view->setID($list_id);
|
||||
|
||||
Javelin::initBehavior(
|
||||
'phabricator-transaction-list',
|
||||
array(
|
||||
'listID' => $list_id,
|
||||
));
|
||||
}
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
|
||||
private function getOrBuildEngine() {
|
||||
if ($this->engine) {
|
||||
return $this->engine;
|
||||
}
|
||||
|
||||
$field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT;
|
||||
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($this->viewer);
|
||||
foreach ($this->transactions as $xaction) {
|
||||
if (!$xaction->hasComment()) {
|
||||
continue;
|
||||
}
|
||||
$engine->addObject($xaction->getComment(), $field);
|
||||
}
|
||||
$engine->process();
|
||||
|
||||
return $engine;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ final class PhabricatorTimelineEventView extends AphrontView {
|
|||
'a',
|
||||
array(
|
||||
'href' => '/transactions/edit/'.$xaction_phid.'/',
|
||||
'sigil' => 'workflow',
|
||||
'sigil' => 'workflow transaction-edit',
|
||||
),
|
||||
pht('Edit'));
|
||||
}
|
||||
|
@ -258,11 +258,23 @@ final class PhabricatorTimelineEventView extends AphrontView {
|
|||
$outer_classes[] = 'phabricator-timeline-'.$this->color;
|
||||
}
|
||||
|
||||
return phutil_render_tag(
|
||||
$sigil = null;
|
||||
$meta = null;
|
||||
if ($this->getTransactionPHID()) {
|
||||
$sigil = 'transaction';
|
||||
$meta = array(
|
||||
'phid' => $this->getTransactionPHID(),
|
||||
'anchor' => $this->anchor,
|
||||
);
|
||||
}
|
||||
|
||||
return javelin_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => implode(' ', $outer_classes),
|
||||
'id' => $this->anchor ? 'anchor-'.$this->anchor : null,
|
||||
'sigil' => $sigil,
|
||||
'meta' => $meta,
|
||||
),
|
||||
phutil_render_tag(
|
||||
'div',
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
final class PhabricatorTimelineView extends AphrontView {
|
||||
|
||||
private $events = array();
|
||||
private $id;
|
||||
|
||||
public function setID($id) {
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addEvent(PhabricatorTimelineEventView $event) {
|
||||
$this->events[] = $event;
|
||||
|
@ -31,6 +37,7 @@ final class PhabricatorTimelineView extends AphrontView {
|
|||
'div',
|
||||
array(
|
||||
'class' => 'phabricator-timeline-view',
|
||||
'id' => $this->id,
|
||||
),
|
||||
implode('', $events));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @provides javelin-behavior-phabricator-transaction-list
|
||||
* @requires javelin-behavior
|
||||
* javelin-stratcom
|
||||
* javelin-workflow
|
||||
* javelin-dom
|
||||
*/
|
||||
|
||||
JX.behavior('phabricator-transaction-list', function(config) {
|
||||
|
||||
var list = JX.$(config.listID);
|
||||
var xaction_nodes = null;
|
||||
|
||||
function get_xaction_nodes() {
|
||||
if (xaction_nodes === null) {
|
||||
xaction_nodes = {};
|
||||
var xactions = JX.DOM.scry(list, 'div', 'transaction');
|
||||
for (var ii = 0; ii < xactions.length; ii++) {
|
||||
xaction_nodes[JX.Stratcom.getData(xactions[ii]).phid] = xactions[ii];
|
||||
}
|
||||
}
|
||||
return xaction_nodes;
|
||||
}
|
||||
|
||||
function ontransactions(response) {
|
||||
var nodes = get_xaction_nodes();
|
||||
for (var phid in response.xactions) {
|
||||
var new_node = JX.$H(response.xactions[phid]).getFragment().firstChild;
|
||||
if (nodes[phid]) {
|
||||
JX.DOM.replace(nodes[phid], new_node);
|
||||
} else {
|
||||
list.appendChild(new_node);
|
||||
}
|
||||
nodes[phid] = new_node;
|
||||
}
|
||||
}
|
||||
|
||||
JX.DOM.listen(list, 'click', 'transaction-edit', function(e) {
|
||||
if (!e.isNormalClick()) {
|
||||
return;
|
||||
}
|
||||
|
||||
JX.Workflow.newFromLink(e.getTarget())
|
||||
.setData({anchor: e.getNodeData('transaction').anchor})
|
||||
.setHandler(ontransactions)
|
||||
.start();
|
||||
|
||||
e.kill();
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in a new issue