Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/webroot/rsrc/js/application/transactions/behavior-comment-actions.js
12242 views
1
/**
2
* @provides javelin-behavior-comment-actions
3
* @requires javelin-behavior
4
* javelin-stratcom
5
* javelin-workflow
6
* javelin-dom
7
* phuix-form-control-view
8
* phuix-icon-view
9
* javelin-behavior-phabricator-gesture
10
*/
11
12
JX.behavior('comment-actions', function(config) {
13
var action_map = config.actions;
14
15
var action_node = JX.$(config.actionID);
16
var form_node = JX.$(config.formID);
17
var input_node = JX.$(config.inputID);
18
var place_node = JX.$(config.placeID);
19
20
var rows = {};
21
22
JX.DOM.listen(action_node, 'change', null, function() {
23
var option = find_option(action_node.value);
24
25
action_node.value = '+';
26
27
if (option) {
28
add_row(option);
29
}
30
});
31
32
function find_option(key) {
33
var options = action_node.options;
34
var option;
35
36
for (var ii = 0; ii < options.length; ii++) {
37
option = options[ii];
38
if (option.value == key) {
39
return option;
40
}
41
}
42
43
return null;
44
}
45
46
function redraw() {
47
// If any of the stacked actions specify that they change the label for
48
// the "Submit" button, update the button text. Otherwise, return it to
49
// the default text.
50
var button_text = config.defaultButtonText;
51
for (var k in rows) {
52
var action = action_map[k];
53
if (action.buttonText) {
54
button_text = action.buttonText;
55
}
56
}
57
58
var button_node = JX.DOM.find(form_node, 'button', 'submit-transactions');
59
JX.DOM.setContent(button_node, button_text);
60
}
61
62
function remove_action(key) {
63
var row = rows[key];
64
if (row) {
65
JX.DOM.remove(row.node);
66
row.option.disabled = false;
67
delete rows[key];
68
}
69
70
redraw();
71
}
72
73
function serialize_actions() {
74
var data = [];
75
76
for (var k in rows) {
77
data.push({
78
type: k,
79
value: rows[k].control.getValue(),
80
initialValue: action_map[k].initialValue || null
81
});
82
}
83
84
return JX.JSON.stringify(data);
85
}
86
87
function get_data() {
88
var data = JX.DOM.convertFormToDictionary(form_node);
89
90
data.__preview__ = 1;
91
data[input_node.name] = serialize_actions();
92
93
data.viewData = JX.JSON.stringify(config.viewData);
94
95
return data;
96
}
97
98
function restore_draft_actions(drafts) {
99
var draft;
100
var option;
101
var control;
102
103
for (var ii = 0; ii < drafts.length; ii++) {
104
draft = drafts[ii];
105
106
option = find_option(draft);
107
if (!option) {
108
continue;
109
}
110
111
control = add_row(option);
112
}
113
114
redraw();
115
}
116
117
function onresponse(response) {
118
if (JX.Device.getDevice() != 'desktop') {
119
return;
120
}
121
122
var panel = JX.$(config.panelID);
123
if (!response.xactions.length) {
124
JX.DOM.hide(panel);
125
} else {
126
var preview_root = JX.$(config.timelineID);
127
JX.DOM.setContent(
128
preview_root,
129
[
130
JX.$H(response.header),
131
JX.$H(response.xactions.join('')),
132
JX.$H(response.previewContent)
133
]);
134
JX.DOM.show(panel);
135
136
// NOTE: Resonses are currently processed before associated behaviors are
137
// registered. We need to defer invoking this event so that any behaviors
138
// accompanying the response are registered.
139
var invoke_preview = function() {
140
JX.Stratcom.invoke(
141
'EditEngine.didCommentPreview',
142
null,
143
{
144
rootNode: preview_root
145
});
146
};
147
setTimeout(invoke_preview, 0);
148
}
149
}
150
151
function force_preview() {
152
if (!config.showPreview) {
153
return;
154
}
155
156
new JX.Request(config.actionURI, onresponse)
157
.setData(get_data())
158
.send();
159
}
160
161
function add_row(option) {
162
var action = action_map[option.value];
163
if (!action) {
164
return;
165
}
166
167
// Remove any conflicting actions. For example, "Accept Revision" conflicts
168
// with "Reject Revision".
169
var conflict_key = action.conflictKey || null;
170
if (conflict_key !== null) {
171
for (var k in action_map) {
172
if (k === action.key) {
173
continue;
174
}
175
if (action_map[k].conflictKey !== conflict_key) {
176
continue;
177
}
178
179
if (!(k in rows)) {
180
continue;
181
}
182
183
remove_action(k);
184
}
185
}
186
187
option.disabled = true;
188
189
var aural = JX.$N('span', {className: 'aural-only'}, action.auralLabel);
190
191
var icon = new JX.PHUIXIconView()
192
.setIcon('fa-times-circle');
193
194
var remove = JX.$N('a', {href: '#'}, [aural, icon.getNode()]);
195
196
var control = new JX.PHUIXFormControl()
197
.setLabel(action.label)
198
.setError(remove)
199
.setControl(action.type, action.spec)
200
.setClass('phui-comment-action');
201
var node = control.getNode();
202
203
JX.Stratcom.addSigil(node, 'touchable');
204
205
JX.DOM.listen(node, 'gesture.swipe.end', null, function(e) {
206
var data = e.getData();
207
208
if (data.direction != 'left') {
209
// Didn't swipe left.
210
return;
211
}
212
213
if (data.length <= (JX.Vector.getDim(node).x / 2)) {
214
// Didn't swipe far enough.
215
return;
216
}
217
218
remove_action(action.key);
219
});
220
221
rows[action.key] = {
222
control: control,
223
node: node,
224
option: option
225
};
226
227
JX.DOM.listen(remove, 'click', null, function(e) {
228
e.kill();
229
remove_action(action.key);
230
});
231
232
place_node.parentNode.insertBefore(node, place_node);
233
234
redraw();
235
236
force_preview();
237
238
return control;
239
}
240
241
JX.DOM.listen(form_node, ['submit', 'didSyntheticSubmit'], null, function() {
242
input_node.value = serialize_actions();
243
});
244
245
if (config.showPreview) {
246
var request = new JX.PhabricatorShapedRequest(
247
config.actionURI,
248
onresponse,
249
get_data);
250
251
var trigger = JX.bind(request, request.trigger);
252
253
JX.DOM.listen(form_node, 'keydown', null, trigger);
254
255
JX.DOM.listen(form_node, 'shouldRefresh', null, force_preview);
256
request.start();
257
258
var old_device = JX.Device.getDevice();
259
260
var ondevicechange = function() {
261
var new_device = JX.Device.getDevice();
262
263
var panel = JX.$(config.panelID);
264
if (new_device == 'desktop') {
265
request.setRateLimit(500);
266
267
// Force an immediate refresh if we switched from another device type
268
// to desktop.
269
if (old_device != new_device) {
270
force_preview();
271
}
272
} else {
273
// On mobile, don't show live previews and only save drafts every
274
// 10 seconds.
275
request.setRateLimit(10000);
276
JX.DOM.hide(panel);
277
}
278
279
old_device = new_device;
280
};
281
282
ondevicechange();
283
284
JX.Stratcom.listen('phabricator-device-change', null, ondevicechange);
285
}
286
287
restore_draft_actions(config.drafts || []);
288
289
});
290
291