1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 14:52:41 +01:00

Move inline comment actions into a dropdown menu

Summary: Ref T11401. Ref T13513. This paves the way for more comment actions, particularly an edit-after-submit action.

Test Plan: Took all actions from menus, via mouse and via keyboard (where applicable).

Maniphest Tasks: T13513, T11401

Differential Revision: https://secure.phabricator.com/D21244
This commit is contained in:
epriestley 2020-05-13 04:59:04 -07:00
parent 1da54837ea
commit 419b7ceebb
4 changed files with 205 additions and 119 deletions

View file

@ -13,7 +13,7 @@ return array(
'core.pkg.js' => '1e667bcb', 'core.pkg.js' => '1e667bcb',
'dark-console.pkg.js' => '187792c2', 'dark-console.pkg.js' => '187792c2',
'differential.pkg.css' => 'd71d4531', 'differential.pkg.css' => 'd71d4531',
'differential.pkg.js' => '39781f05', 'differential.pkg.js' => '21616a78',
'diffusion.pkg.css' => '42c75c37', 'diffusion.pkg.css' => '42c75c37',
'diffusion.pkg.js' => 'a98c0bf7', 'diffusion.pkg.js' => 'a98c0bf7',
'maniphest.pkg.css' => '35995d6d', 'maniphest.pkg.css' => '35995d6d',
@ -380,8 +380,8 @@ return array(
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8',
'rsrc/js/application/diff/DiffChangeset.js' => '20715b98', 'rsrc/js/application/diff/DiffChangeset.js' => '20715b98',
'rsrc/js/application/diff/DiffChangesetList.js' => '564cbd20', 'rsrc/js/application/diff/DiffChangesetList.js' => '40d6c41c',
'rsrc/js/application/diff/DiffInline.js' => 'a0ef0b54', 'rsrc/js/application/diff/DiffInline.js' => '15de2478',
'rsrc/js/application/diff/DiffPathView.js' => '8207abf9', 'rsrc/js/application/diff/DiffPathView.js' => '8207abf9',
'rsrc/js/application/diff/DiffTreeView.js' => '5d83623b', 'rsrc/js/application/diff/DiffTreeView.js' => '5d83623b',
'rsrc/js/application/differential/behavior-diff-radios.js' => '925fe8cd', 'rsrc/js/application/differential/behavior-diff-radios.js' => '925fe8cd',
@ -775,8 +775,8 @@ return array(
'phabricator-darkmessage' => '26cd4b73', 'phabricator-darkmessage' => '26cd4b73',
'phabricator-dashboard-css' => '5a205b9d', 'phabricator-dashboard-css' => '5a205b9d',
'phabricator-diff-changeset' => '20715b98', 'phabricator-diff-changeset' => '20715b98',
'phabricator-diff-changeset-list' => '564cbd20', 'phabricator-diff-changeset-list' => '40d6c41c',
'phabricator-diff-inline' => 'a0ef0b54', 'phabricator-diff-inline' => '15de2478',
'phabricator-diff-path-view' => '8207abf9', 'phabricator-diff-path-view' => '8207abf9',
'phabricator-diff-tree-view' => '5d83623b', 'phabricator-diff-tree-view' => '5d83623b',
'phabricator-drag-and-drop-file-upload' => '4370900d', 'phabricator-drag-and-drop-file-upload' => '4370900d',
@ -1034,6 +1034,9 @@ return array(
'javelin-stratcom', 'javelin-stratcom',
'javelin-util', 'javelin-util',
), ),
'15de2478' => array(
'javelin-dom',
),
'1a844c06' => array( '1a844c06' => array(
'javelin-install', 'javelin-install',
'javelin-util', 'javelin-util',
@ -1259,6 +1262,11 @@ return array(
'javelin-behavior', 'javelin-behavior',
'javelin-uri', 'javelin-uri',
), ),
'40d6c41c' => array(
'javelin-install',
'phuix-button-view',
'phabricator-diff-tree-view',
),
'42c44e8b' => array( '42c44e8b' => array(
'javelin-behavior', 'javelin-behavior',
'javelin-workflow', 'javelin-workflow',
@ -1418,11 +1426,6 @@ return array(
'javelin-stratcom', 'javelin-stratcom',
'javelin-dom', 'javelin-dom',
), ),
'564cbd20' => array(
'javelin-install',
'phuix-button-view',
'phabricator-diff-tree-view',
),
'5793d835' => array( '5793d835' => array(
'javelin-install', 'javelin-install',
'javelin-util', 'javelin-util',
@ -1833,9 +1836,6 @@ return array(
'javelin-util', 'javelin-util',
'phabricator-keyboard-shortcut', 'phabricator-keyboard-shortcut',
), ),
'a0ef0b54' => array(
'javelin-dom',
),
'a17b84f1' => array( 'a17b84f1' => array(
'javelin-behavior', 'javelin-behavior',
'javelin-dom', 'javelin-dom',

View file

@ -88,10 +88,12 @@ final class PHUIDiffInlineCommentDetailView
$is_synthetic = true; $is_synthetic = true;
} }
$is_preview = $this->preview;
$metadata = $this->getInlineCommentMetadata(); $metadata = $this->getInlineCommentMetadata();
$sigil = 'differential-inline-comment'; $sigil = 'differential-inline-comment';
if ($this->preview) { if ($is_preview) {
$sigil = $sigil.' differential-inline-comment-preview'; $sigil = $sigil.' differential-inline-comment-preview';
} }
@ -146,11 +148,6 @@ final class PHUIDiffInlineCommentDetailView
$classes[] = 'inline-comment-ghost'; $classes[] = 'inline-comment-ghost';
} }
// I think this is unused
if ($inline->getHasReplies()) {
$classes[] = 'inline-comment-has-reply';
}
if ($inline->getReplyToCommentPHID()) { if ($inline->getReplyToCommentPHID()) {
$classes[] = 'inline-comment-is-reply'; $classes[] = 'inline-comment-is-reply';
} }
@ -167,47 +164,22 @@ final class PHUIDiffInlineCommentDetailView
$anchor_name = $this->getAnchorName(); $anchor_name = $this->getAnchorName();
$action_buttons = array(); $action_buttons = array();
$menu_items = array();
$can_reply = if ($this->editable && !$is_preview) {
(!$this->editable) && $menu_items[] = array(
(!$this->preview) && 'label' => pht('Edit Comment'),
($this->allowReply) && 'icon' => 'fa-pencil',
'action' => 'edit',
'key' => 'e',
);
// NOTE: No product reason why you can't reply to synthetic comments, $menu_items[] = array(
// but the reply mechanism currently sends the inline comment ID to the 'label' => pht('Delete Comment'),
// server, not file/line information, and synthetic comments don't have 'icon' => 'fa-trash-o',
// an inline comment ID. 'action' => 'delete',
(!$is_synthetic); );
} else if ($is_preview) {
if ($can_reply) {
$action_buttons[] = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-reply')
->setTooltip(pht('Reply'))
->addSigil('differential-inline-reply')
->setMustCapture(true)
->setAuralLabel(pht('Reply'));
}
if ($this->editable && !$this->preview) {
$action_buttons[] = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-pencil')
->setTooltip(pht('Edit'))
->addSigil('differential-inline-edit')
->setMustCapture(true)
->setAuralLabel(pht('Edit'));
$action_buttons[] = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-trash-o')
->setTooltip(pht('Delete'))
->addSigil('differential-inline-delete')
->setMustCapture(true)
->setAuralLabel(pht('Delete'));
} else if ($this->preview) {
$links[] = javelin_tag( $links[] = javelin_tag(
'a', 'a',
array( array(
@ -228,14 +200,40 @@ final class PHUIDiffInlineCommentDetailView
->setAuralLabel(pht('Delete')); ->setAuralLabel(pht('Delete'));
} }
if (!$this->preview && $this->canHide()) { if (!$is_preview && $this->canHide()) {
$action_buttons[] = id(new PHUIButtonView()) $menu_items[] = array(
->setTag('a') 'label' => pht('Collapse'),
->setTooltip(pht('Collapse')) 'icon' => 'fa-times',
->setIcon('fa-times') 'action' => 'collapse',
->addSigil('hide-inline') 'key' => 'q',
->setMustCapture(true) );
->setAuralLabel(pht('Collapse')); }
$can_reply =
(!$this->editable) &&
(!$is_preview) &&
($this->allowReply) &&
// NOTE: No product reason why you can't reply to synthetic comments,
// but the reply mechanism currently sends the inline comment ID to the
// server, not file/line information, and synthetic comments don't have
// an inline comment ID.
(!$is_synthetic);
if ($can_reply) {
$menu_items[] = array(
'label' => pht('Reply to Comment'),
'icon' => 'fa-reply',
'action' => 'reply',
'key' => 'r',
);
$menu_items[] = array(
'label' => pht('Quote Comment'),
'icon' => 'fa-quote-left',
'action' => 'quote',
'key' => 'R',
);
} }
$done_button = null; $done_button = null;
@ -283,7 +281,7 @@ final class PHUIDiffInlineCommentDetailView
$classes[] = 'inline-state-is-draft'; $classes[] = 'inline-state-is-draft';
} }
if ($mark_done && !$this->preview) { if ($mark_done && !$is_preview) {
$done_input = javelin_tag( $done_input = javelin_tag(
'input', 'input',
array( array(
@ -327,7 +325,7 @@ final class PHUIDiffInlineCommentDetailView
$inline, $inline,
PhabricatorInlineComment::MARKUP_FIELD_BODY); PhabricatorInlineComment::MARKUP_FIELD_BODY);
if ($this->preview) { if ($is_preview) {
$anchor = null; $anchor = null;
} else { } else {
$anchor = phutil_tag( $anchor = phutil_tag(
@ -364,13 +362,24 @@ final class PHUIDiffInlineCommentDetailView
} }
$actions = null; $actions = null;
if ($action_buttons) { if ($action_buttons || $menu_items) {
$actions = new PHUIButtonBarView(); $actions = new PHUIButtonBarView();
$actions->setBorderless(true); $actions->setBorderless(true);
$actions->addClass('inline-button-divider'); $actions->addClass('inline-button-divider');
foreach ($action_buttons as $button) { foreach ($action_buttons as $button) {
$actions->addButton($button); $actions->addButton($button);
} }
if (!$is_preview) {
$menu_button = id(new PHUIButtonView())
->setTag('a')
->setColor(PHUIButtonView::GREY)
->setDropdown(true)
->setAuralLabel(pht('Inline Actions'))
->addSigil('inline-action-dropdown');
$actions->addButton($menu_button);
}
} }
$group_left = phutil_tag( $group_left = phutil_tag(
@ -401,6 +410,8 @@ final class PHUIDiffInlineCommentDetailView
->truncateString($inline->getContent()); ->truncateString($inline->getContent());
$metadata['snippet'] = pht('%s: %s', $author, $snippet); $metadata['snippet'] = pht('%s: %s', $author, $snippet);
$metadata['menuItems'] = $menu_items;
$markup = javelin_tag( $markup = javelin_tag(
'div', 'div',
array( array(

View file

@ -20,9 +20,6 @@ JX.install('DiffChangesetList', {
var onmenu = JX.bind(this, this._ifawake, this._onmenu); var onmenu = JX.bind(this, this._ifawake, this._onmenu);
JX.Stratcom.listen('click', 'differential-view-options', onmenu); JX.Stratcom.listen('click', 'differential-view-options', onmenu);
var oncollapse = JX.bind(this, this._ifawake, this._oncollapse, true);
JX.Stratcom.listen('click', 'hide-inline', oncollapse);
var onexpand = JX.bind(this, this._ifawake, this._oncollapse, false); var onexpand = JX.bind(this, this._ifawake, this._oncollapse, false);
JX.Stratcom.listen('click', 'reveal-inline', onexpand); JX.Stratcom.listen('click', 'reveal-inline', onexpand);
@ -336,16 +333,7 @@ JX.install('DiffChangesetList', {
var inline = cursor.target; var inline = cursor.target;
if (inline.canReply()) { if (inline.canReply()) {
this.setFocus(null); this.setFocus(null);
inline.reply(true);
var text;
if (is_quote) {
text = inline.getRawText();
text = '> ' + text.replace(/\n/g, '\n> ') + '\n\n';
} else {
text = '';
}
inline.reply(text);
return; return;
} }
} }
@ -2094,12 +2082,6 @@ JX.install('DiffChangesetList', {
'differential-inline-comment-undo', 'differential-inline-comment-undo',
onundo); onundo);
var onedit = JX.bind(this, this._onInlineEvent, 'edit');
JX.Stratcom.listen(
'click',
['differential-inline-comment', 'differential-inline-edit'],
onedit);
var ondone = JX.bind(this, this._onInlineEvent, 'done'); var ondone = JX.bind(this, this._onInlineEvent, 'done');
JX.Stratcom.listen( JX.Stratcom.listen(
'click', 'click',
@ -2112,11 +2094,11 @@ JX.install('DiffChangesetList', {
['differential-inline-comment', 'differential-inline-delete'], ['differential-inline-comment', 'differential-inline-delete'],
ondelete); ondelete);
var onreply = JX.bind(this, this._onInlineEvent, 'reply'); var onmenu = JX.bind(this, this._onInlineEvent, 'menu');
JX.Stratcom.listen( JX.Stratcom.listen(
'click', 'click',
['differential-inline-comment', 'differential-inline-reply'], ['differential-inline-comment', 'inline-action-dropdown'],
onreply); onmenu);
var ondraft = JX.bind(this, this._onInlineEvent, 'draft'); var ondraft = JX.bind(this, this._onInlineEvent, 'draft');
JX.Stratcom.listen( JX.Stratcom.listen(
@ -2156,7 +2138,7 @@ JX.install('DiffChangesetList', {
return; return;
} }
if (action !== 'draft') { if (action !== 'draft' && action !== 'menu') {
e.kill(); e.kill();
} }
@ -2201,21 +2183,19 @@ JX.install('DiffChangesetList', {
case 'undo': case 'undo':
inline.undo(); inline.undo();
break; break;
case 'edit':
inline.edit();
break;
case 'done': case 'done':
inline.toggleDone(); inline.toggleDone();
break; break;
case 'delete': case 'delete':
inline.delete(is_ref); inline.delete(is_ref);
break; break;
case 'reply':
inline.reply();
break;
case 'draft': case 'draft':
inline.triggerDraft(); inline.triggerDraft();
break; break;
case 'menu':
var node = e.getNode('inline-action-dropdown');
inline.activateMenu(node, e);
break;
} }
} }

View file

@ -21,6 +21,7 @@ JX.install('DiffInline', {
_replyToCommentPHID: null, _replyToCommentPHID: null,
_originalText: null, _originalText: null,
_snippet: null, _snippet: null,
_menuItems: null,
_documentEngineKey: null, _documentEngineKey: null,
_isDeleted: false, _isDeleted: false,
@ -45,6 +46,7 @@ JX.install('DiffInline', {
_draftRequest: null, _draftRequest: null,
_skipFocus: false, _skipFocus: false,
_menu: null,
bindToRow: function(row) { bindToRow: function(row) {
this._row = row; this._row = row;
@ -89,6 +91,7 @@ JX.install('DiffInline', {
this._changesetID = data.changesetID; this._changesetID = data.changesetID;
this._isNew = false; this._isNew = false;
this._snippet = data.snippet; this._snippet = data.snippet;
this._menuItems = data.menuItems;
this._documentEngineKey = data.documentEngineKey; this._documentEngineKey = data.documentEngineKey;
this._isEditing = data.isEditing; this._isEditing = data.isEditing;
@ -252,19 +255,11 @@ JX.install('DiffInline', {
}, },
canReply: function() { canReply: function() {
if (!this._hasAction('reply')) { return this._hasMenuAction('reply');
return false;
}
return true;
}, },
canEdit: function() { canEdit: function() {
if (!this._hasAction('edit')) { return this._hasMenuAction('edit');
return false;
}
return true;
}, },
canDone: function() { canDone: function() {
@ -276,22 +271,13 @@ JX.install('DiffInline', {
}, },
canCollapse: function() { canCollapse: function() {
if (!JX.DOM.scry(this._row, 'a', 'hide-inline').length) { return this._hasMenuAction('collapse');
return false;
}
return true;
}, },
getRawText: function() { getRawText: function() {
return this._originalText; return this._originalText;
}, },
_hasAction: function(action) {
var nodes = JX.DOM.scry(this._row, 'a', 'differential-inline-' + action);
return (nodes.length > 0);
},
_newRow: function() { _newRow: function() {
var attributes = { var attributes = {
sigil: 'inline-row' sigil: 'inline-row'
@ -312,6 +298,8 @@ JX.install('DiffInline', {
}, },
setCollapsed: function(collapsed) { setCollapsed: function(collapsed) {
this._closeMenu();
this._isCollapsed = collapsed; this._isCollapsed = collapsed;
var op; var op;
@ -393,12 +381,24 @@ JX.install('DiffInline', {
.send(); .send();
}, },
reply: function(text) { reply: function(with_quote) {
this._closeMenu();
var text;
if (with_quote) {
text = this.getRawText();
text = '> ' + text.replace(/\n/g, '\n> ') + '\n\n';
} else {
text = '';
}
var changeset = this.getChangeset(); var changeset = this.getChangeset();
return changeset.newInlineReply(this, text); return changeset.newInlineReply(this, text);
}, },
edit: function(text, skip_focus) { edit: function(text, skip_focus) {
this._closeMenu();
this._skipFocus = !!skip_focus; this._skipFocus = !!skip_focus;
// If you edit an inline ("A"), modify the text ("AB"), cancel, and then // If you edit an inline ("A"), modify the text ("AB"), cancel, and then
@ -881,6 +881,101 @@ JX.install('DiffInline', {
if (this._draftRequest) { if (this._draftRequest) {
this._draftRequest.trigger(); this._draftRequest.trigger();
} }
},
activateMenu: function(button, e) {
// If we already have a menu for this button, let the menu handle the
// event.
var data = JX.Stratcom.getData(button);
if (data.menu) {
return;
}
e.prevent();
var menu = new JX.PHUIXDropdownMenu(button)
.setWidth(240);
var list = new JX.PHUIXActionListView();
var items = this._newMenuItems(menu);
for (var ii = 0; ii < items.length; ii++) {
list.addItem(items[ii]);
}
menu.setContent(list.getNode());
data.menu = menu;
this._menu = menu;
menu.listen('open', JX.bind(this, function() {
var changeset_list = this.getChangeset().getChangesetList();
changeset_list.selectInline(this, true);
}));
menu.open();
},
_newMenuItems: function(menu) {
var items = [];
for (var ii = 0; ii < this._menuItems.length; ii++) {
var spec = this._menuItems[ii];
var onmenu = JX.bind(this, this._onMenuItem, menu, spec.action);
var item = new JX.PHUIXActionView()
.setIcon(spec.icon)
.setName(spec.label)
.setHandler(onmenu);
if (spec.key) {
item.setKeyCommand(spec.key);
}
items.push(item);
}
return items;
},
_onMenuItem: function(menu, action, e) {
e.prevent();
menu.close();
switch (action) {
case 'reply':
this.reply();
break;
case 'quote':
this.reply(true);
break;
case 'collapse':
this.setCollapsed(true);
break;
case 'delete':
this.delete();
break;
case 'edit':
this.edit();
break;
}
},
_hasMenuAction: function(action) {
for (var ii = 0; ii < this._menuItems.length; ii++) {
var spec = this._menuItems[ii];
if (spec.action === action) {
return true;
}
}
return false;
},
_closeMenu: function() {
if (this._menu) {
this._menu.close();
}
} }
} }