1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-18 18:51:12 +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:
epriestley 2012-12-11 14:02:12 -08:00
parent 26dd2a0eef
commit 025411990b
5 changed files with 144 additions and 24 deletions

View file

@ -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')

View file

@ -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;
}
}

View file

@ -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',

View file

@ -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));
}

View file

@ -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();
});
});