mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-15 03:12:41 +01:00
44c32839a6
Summary: See PHI975. Ref T13216. Ref T2543. Previously, see D19204 and PHI433. When you're acting on a draft revision, we change the button text to "Submit Quietly" as a hint that your actions don't generate notifications yet. However, this isn't accurate when one of your actions is "Request Review", which causes the revision to publish. Allow actions to override the submit button text, and make the "Request Review" action change the button text to "Publish Revision". The alternative change I considered was to remove the word "Quietly" in all cases. I'm not //thrilled// about how complex this change is to adjust one word, but the various pieces are all fairly clean individually. I'm not sure we'll ever be able to use it for anything else, but I do suspect that the word "Quietly" was the change in D19204 with the largest effect by far (see T10000). Test Plan: - Created a draft revision. Saw "Submit Quietly" text. - Added a "Request Review" action, saw it change to "Publish Revision". - Reloaded page, saw stack saved and "Publish Revision". - Removed action, saw "Submit Quietly". - Repeated on a non-draft revision, button stayed put as "Submit". - Submitted the various actions, saw them have the desired effects. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13216, T2543 Differential Revision: https://secure.phabricator.com/D19810
287 lines
6.5 KiB
JavaScript
287 lines
6.5 KiB
JavaScript
/**
|
|
* @provides javelin-behavior-comment-actions
|
|
* @requires javelin-behavior
|
|
* javelin-stratcom
|
|
* javelin-workflow
|
|
* javelin-dom
|
|
* phuix-form-control-view
|
|
* phuix-icon-view
|
|
* javelin-behavior-phabricator-gesture
|
|
*/
|
|
|
|
JX.behavior('comment-actions', function(config) {
|
|
var action_map = config.actions;
|
|
|
|
var action_node = JX.$(config.actionID);
|
|
var form_node = JX.$(config.formID);
|
|
var input_node = JX.$(config.inputID);
|
|
var place_node = JX.$(config.placeID);
|
|
|
|
var rows = {};
|
|
|
|
JX.DOM.listen(action_node, 'change', null, function() {
|
|
var option = find_option(action_node.value);
|
|
|
|
action_node.value = '+';
|
|
|
|
if (option) {
|
|
add_row(option);
|
|
}
|
|
});
|
|
|
|
function find_option(key) {
|
|
var options = action_node.options;
|
|
var option;
|
|
|
|
for (var ii = 0; ii < options.length; ii++) {
|
|
option = options[ii];
|
|
if (option.value == key) {
|
|
return option;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function redraw() {
|
|
// If any of the stacked actions specify that they change the label for
|
|
// the "Submit" button, update the button text. Otherwise, return it to
|
|
// the default text.
|
|
var button_text = config.defaultButtonText;
|
|
for (var k in rows) {
|
|
var action = action_map[k];
|
|
if (action.buttonText) {
|
|
button_text = action.buttonText;
|
|
}
|
|
}
|
|
|
|
var button_node = JX.DOM.find(form_node, 'button', 'submit-transactions');
|
|
JX.DOM.setContent(button_node, button_text);
|
|
}
|
|
|
|
function remove_action(key) {
|
|
var row = rows[key];
|
|
if (row) {
|
|
JX.DOM.remove(row.node);
|
|
row.option.disabled = false;
|
|
delete rows[key];
|
|
}
|
|
|
|
redraw();
|
|
}
|
|
|
|
function serialize_actions() {
|
|
var data = [];
|
|
|
|
for (var k in rows) {
|
|
data.push({
|
|
type: k,
|
|
value: rows[k].control.getValue(),
|
|
initialValue: action_map[k].initialValue || null
|
|
});
|
|
}
|
|
|
|
return JX.JSON.stringify(data);
|
|
}
|
|
|
|
function get_data() {
|
|
var data = JX.DOM.convertFormToDictionary(form_node);
|
|
|
|
data.__preview__ = 1;
|
|
data[input_node.name] = serialize_actions();
|
|
|
|
return data;
|
|
}
|
|
|
|
function restore_draft_actions(drafts) {
|
|
var draft;
|
|
var option;
|
|
var control;
|
|
|
|
for (var ii = 0; ii < drafts.length; ii++) {
|
|
draft = drafts[ii];
|
|
|
|
option = find_option(draft);
|
|
if (!option) {
|
|
continue;
|
|
}
|
|
|
|
control = add_row(option);
|
|
}
|
|
|
|
redraw();
|
|
}
|
|
|
|
function onresponse(response) {
|
|
if (JX.Device.getDevice() != 'desktop') {
|
|
return;
|
|
}
|
|
|
|
var panel = JX.$(config.panelID);
|
|
if (!response.xactions.length) {
|
|
JX.DOM.hide(panel);
|
|
} else {
|
|
var preview_root = JX.$(config.timelineID);
|
|
JX.DOM.setContent(
|
|
preview_root,
|
|
[
|
|
JX.$H(response.header),
|
|
JX.$H(response.xactions.join('')),
|
|
JX.$H(response.previewContent)
|
|
]);
|
|
JX.DOM.show(panel);
|
|
|
|
// NOTE: Resonses are currently processed before associated behaviors are
|
|
// registered. We need to defer invoking this event so that any behaviors
|
|
// accompanying the response are registered.
|
|
var invoke_preview = function() {
|
|
JX.Stratcom.invoke(
|
|
'EditEngine.didCommentPreview',
|
|
null,
|
|
{
|
|
rootNode: preview_root
|
|
});
|
|
};
|
|
setTimeout(invoke_preview, 0);
|
|
}
|
|
}
|
|
|
|
function force_preview() {
|
|
if (!config.showPreview) {
|
|
return;
|
|
}
|
|
|
|
new JX.Request(config.actionURI, onresponse)
|
|
.setData(get_data())
|
|
.send();
|
|
}
|
|
|
|
function add_row(option) {
|
|
var action = action_map[option.value];
|
|
if (!action) {
|
|
return;
|
|
}
|
|
|
|
// Remove any conflicting actions. For example, "Accept Revision" conflicts
|
|
// with "Reject Revision".
|
|
var conflict_key = action.conflictKey || null;
|
|
if (conflict_key !== null) {
|
|
for (var k in action_map) {
|
|
if (k === action.key) {
|
|
continue;
|
|
}
|
|
if (action_map[k].conflictKey !== conflict_key) {
|
|
continue;
|
|
}
|
|
|
|
if (!(k in rows)) {
|
|
continue;
|
|
}
|
|
|
|
remove_action(k);
|
|
}
|
|
}
|
|
|
|
option.disabled = true;
|
|
|
|
var aural = JX.$N('span', {className: 'aural-only'}, action.auralLabel);
|
|
|
|
var icon = new JX.PHUIXIconView()
|
|
.setIcon('fa-times-circle');
|
|
|
|
var remove = JX.$N('a', {href: '#'}, [aural, icon.getNode()]);
|
|
|
|
var control = new JX.PHUIXFormControl()
|
|
.setLabel(action.label)
|
|
.setError(remove)
|
|
.setControl(action.type, action.spec)
|
|
.setClass('phui-comment-action');
|
|
var node = control.getNode();
|
|
|
|
JX.Stratcom.addSigil(node, 'touchable');
|
|
|
|
JX.DOM.listen(node, 'gesture.swipe.end', null, function(e) {
|
|
var data = e.getData();
|
|
|
|
if (data.direction != 'left') {
|
|
// Didn't swipe left.
|
|
return;
|
|
}
|
|
|
|
if (data.length <= (JX.Vector.getDim(node).x / 2)) {
|
|
// Didn't swipe far enough.
|
|
return;
|
|
}
|
|
|
|
remove_action(action.key);
|
|
});
|
|
|
|
rows[action.key] = {
|
|
control: control,
|
|
node: node,
|
|
option: option
|
|
};
|
|
|
|
JX.DOM.listen(remove, 'click', null, function(e) {
|
|
e.kill();
|
|
remove_action(action.key);
|
|
});
|
|
|
|
place_node.parentNode.insertBefore(node, place_node);
|
|
|
|
redraw();
|
|
|
|
force_preview();
|
|
|
|
return control;
|
|
}
|
|
|
|
JX.DOM.listen(form_node, ['submit', 'didSyntheticSubmit'], null, function() {
|
|
input_node.value = serialize_actions();
|
|
});
|
|
|
|
if (config.showPreview) {
|
|
var request = new JX.PhabricatorShapedRequest(
|
|
config.actionURI,
|
|
onresponse,
|
|
get_data);
|
|
|
|
var trigger = JX.bind(request, request.trigger);
|
|
|
|
JX.DOM.listen(form_node, 'keydown', null, trigger);
|
|
|
|
JX.DOM.listen(form_node, 'shouldRefresh', null, force_preview);
|
|
request.start();
|
|
|
|
var old_device = JX.Device.getDevice();
|
|
|
|
var ondevicechange = function() {
|
|
var new_device = JX.Device.getDevice();
|
|
|
|
var panel = JX.$(config.panelID);
|
|
if (new_device == 'desktop') {
|
|
request.setRateLimit(500);
|
|
|
|
// Force an immediate refresh if we switched from another device type
|
|
// to desktop.
|
|
if (old_device != new_device) {
|
|
force_preview();
|
|
}
|
|
} else {
|
|
// On mobile, don't show live previews and only save drafts every
|
|
// 10 seconds.
|
|
request.setRateLimit(10000);
|
|
JX.DOM.hide(panel);
|
|
}
|
|
|
|
old_device = new_device;
|
|
};
|
|
|
|
ondevicechange();
|
|
|
|
JX.Stratcom.listen('phabricator-device-change', null, ondevicechange);
|
|
}
|
|
|
|
restore_draft_actions(config.drafts || []);
|
|
|
|
});
|