mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-31 00:48:21 +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 {
|
extends PhabricatorApplicationTransactionController {
|
||||||
|
|
||||||
private $phid;
|
private $phid;
|
||||||
private $anchor;
|
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
public function willProcessRequest(array $data) {
|
||||||
$this->phid = $data['phid'];
|
$this->phid = $data['phid'];
|
||||||
$this->anchor = idx($data, 'anchor');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processRequest() {
|
public function processRequest() {
|
||||||
|
@ -59,7 +57,26 @@ final class PhabricatorApplicationTransactionCommentEditController
|
||||||
)))
|
)))
|
||||||
->applyEdit($xaction, $comment);
|
->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())
|
$dialog = id(new AphrontDialogView())
|
||||||
|
@ -67,6 +84,7 @@ final class PhabricatorApplicationTransactionCommentEditController
|
||||||
->setTitle(pht('Edit Comment'));
|
->setTitle(pht('Edit Comment'));
|
||||||
|
|
||||||
$dialog
|
$dialog
|
||||||
|
->addHiddenInput('anchor', $request->getStr('anchor'))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new PhabricatorRemarkupControl())
|
id(new PhabricatorRemarkupControl())
|
||||||
->setName('text')
|
->setName('text')
|
||||||
|
|
|
@ -8,7 +8,7 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
||||||
private $viewer;
|
private $viewer;
|
||||||
private $transactions;
|
private $transactions;
|
||||||
private $engine;
|
private $engine;
|
||||||
private $anchorOffset = 0;
|
private $anchorOffset = 1;
|
||||||
private $showEditActions = true;
|
private $showEditActions = true;
|
||||||
|
|
||||||
public function setShowEditActions($show_edit_actions) {
|
public function setShowEditActions($show_edit_actions) {
|
||||||
|
@ -41,33 +41,19 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render() {
|
public function buildEvents() {
|
||||||
$field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT;
|
$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;
|
$viewer = $this->viewer;
|
||||||
|
|
||||||
$anchor = $this->anchorOffset;
|
$anchor = $this->anchorOffset;
|
||||||
|
$events = array();
|
||||||
foreach ($this->transactions as $xaction) {
|
foreach ($this->transactions as $xaction) {
|
||||||
if ($xaction->shouldHide()) {
|
if ($xaction->shouldHide()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$anchor++;
|
|
||||||
$event = id(new PhabricatorTimelineEventView())
|
$event = id(new PhabricatorTimelineEventView())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->setTransactionPHID($xaction->getPHID())
|
->setTransactionPHID($xaction->getPHID())
|
||||||
|
@ -79,6 +65,9 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
||||||
->setContentSource($xaction->getContentSource())
|
->setContentSource($xaction->getContentSource())
|
||||||
->setAnchor($anchor);
|
->setAnchor($anchor);
|
||||||
|
|
||||||
|
$anchor++;
|
||||||
|
|
||||||
|
|
||||||
$has_deleted_comment = $xaction->getComment() &&
|
$has_deleted_comment = $xaction->getComment() &&
|
||||||
$xaction->getComment()->getIsDeleted();
|
$xaction->getComment()->getIsDeleted();
|
||||||
|
|
||||||
|
@ -102,16 +91,59 @@ class PhabricatorApplicationTransactionView extends AphrontView {
|
||||||
|
|
||||||
if ($xaction->hasComment()) {
|
if ($xaction->hasComment()) {
|
||||||
$event->appendChild(
|
$event->appendChild(
|
||||||
$this->engine->getOutput($xaction->getComment(), $field));
|
$engine->getOutput($xaction->getComment(), $field));
|
||||||
} else if ($has_deleted_comment) {
|
} else if ($has_deleted_comment) {
|
||||||
$event->appendChild(
|
$event->appendChild(
|
||||||
'<em>'.pht('This comment has been deleted.').'</em>');
|
'<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);
|
$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();
|
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',
|
'a',
|
||||||
array(
|
array(
|
||||||
'href' => '/transactions/edit/'.$xaction_phid.'/',
|
'href' => '/transactions/edit/'.$xaction_phid.'/',
|
||||||
'sigil' => 'workflow',
|
'sigil' => 'workflow transaction-edit',
|
||||||
),
|
),
|
||||||
pht('Edit'));
|
pht('Edit'));
|
||||||
}
|
}
|
||||||
|
@ -258,11 +258,23 @@ final class PhabricatorTimelineEventView extends AphrontView {
|
||||||
$outer_classes[] = 'phabricator-timeline-'.$this->color;
|
$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',
|
'div',
|
||||||
array(
|
array(
|
||||||
'class' => implode(' ', $outer_classes),
|
'class' => implode(' ', $outer_classes),
|
||||||
'id' => $this->anchor ? 'anchor-'.$this->anchor : null,
|
'id' => $this->anchor ? 'anchor-'.$this->anchor : null,
|
||||||
|
'sigil' => $sigil,
|
||||||
|
'meta' => $meta,
|
||||||
),
|
),
|
||||||
phutil_render_tag(
|
phutil_render_tag(
|
||||||
'div',
|
'div',
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
final class PhabricatorTimelineView extends AphrontView {
|
final class PhabricatorTimelineView extends AphrontView {
|
||||||
|
|
||||||
private $events = array();
|
private $events = array();
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
public function setID($id) {
|
||||||
|
$this->id = $id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function addEvent(PhabricatorTimelineEventView $event) {
|
public function addEvent(PhabricatorTimelineEventView $event) {
|
||||||
$this->events[] = $event;
|
$this->events[] = $event;
|
||||||
|
@ -31,6 +37,7 @@ final class PhabricatorTimelineView extends AphrontView {
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
'class' => 'phabricator-timeline-view',
|
'class' => 'phabricator-timeline-view',
|
||||||
|
'id' => $this->id,
|
||||||
),
|
),
|
||||||
implode('', $events));
|
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…
Add table
Reference in a new issue