Path: blob/master/webroot/rsrc/js/application/transactions/behavior-comment-actions.js
12242 views
/**1* @provides javelin-behavior-comment-actions2* @requires javelin-behavior3* javelin-stratcom4* javelin-workflow5* javelin-dom6* phuix-form-control-view7* phuix-icon-view8* javelin-behavior-phabricator-gesture9*/1011JX.behavior('comment-actions', function(config) {12var action_map = config.actions;1314var action_node = JX.$(config.actionID);15var form_node = JX.$(config.formID);16var input_node = JX.$(config.inputID);17var place_node = JX.$(config.placeID);1819var rows = {};2021JX.DOM.listen(action_node, 'change', null, function() {22var option = find_option(action_node.value);2324action_node.value = '+';2526if (option) {27add_row(option);28}29});3031function find_option(key) {32var options = action_node.options;33var option;3435for (var ii = 0; ii < options.length; ii++) {36option = options[ii];37if (option.value == key) {38return option;39}40}4142return null;43}4445function redraw() {46// If any of the stacked actions specify that they change the label for47// the "Submit" button, update the button text. Otherwise, return it to48// the default text.49var button_text = config.defaultButtonText;50for (var k in rows) {51var action = action_map[k];52if (action.buttonText) {53button_text = action.buttonText;54}55}5657var button_node = JX.DOM.find(form_node, 'button', 'submit-transactions');58JX.DOM.setContent(button_node, button_text);59}6061function remove_action(key) {62var row = rows[key];63if (row) {64JX.DOM.remove(row.node);65row.option.disabled = false;66delete rows[key];67}6869redraw();70}7172function serialize_actions() {73var data = [];7475for (var k in rows) {76data.push({77type: k,78value: rows[k].control.getValue(),79initialValue: action_map[k].initialValue || null80});81}8283return JX.JSON.stringify(data);84}8586function get_data() {87var data = JX.DOM.convertFormToDictionary(form_node);8889data.__preview__ = 1;90data[input_node.name] = serialize_actions();9192data.viewData = JX.JSON.stringify(config.viewData);9394return data;95}9697function restore_draft_actions(drafts) {98var draft;99var option;100var control;101102for (var ii = 0; ii < drafts.length; ii++) {103draft = drafts[ii];104105option = find_option(draft);106if (!option) {107continue;108}109110control = add_row(option);111}112113redraw();114}115116function onresponse(response) {117if (JX.Device.getDevice() != 'desktop') {118return;119}120121var panel = JX.$(config.panelID);122if (!response.xactions.length) {123JX.DOM.hide(panel);124} else {125var preview_root = JX.$(config.timelineID);126JX.DOM.setContent(127preview_root,128[129JX.$H(response.header),130JX.$H(response.xactions.join('')),131JX.$H(response.previewContent)132]);133JX.DOM.show(panel);134135// NOTE: Resonses are currently processed before associated behaviors are136// registered. We need to defer invoking this event so that any behaviors137// accompanying the response are registered.138var invoke_preview = function() {139JX.Stratcom.invoke(140'EditEngine.didCommentPreview',141null,142{143rootNode: preview_root144});145};146setTimeout(invoke_preview, 0);147}148}149150function force_preview() {151if (!config.showPreview) {152return;153}154155new JX.Request(config.actionURI, onresponse)156.setData(get_data())157.send();158}159160function add_row(option) {161var action = action_map[option.value];162if (!action) {163return;164}165166// Remove any conflicting actions. For example, "Accept Revision" conflicts167// with "Reject Revision".168var conflict_key = action.conflictKey || null;169if (conflict_key !== null) {170for (var k in action_map) {171if (k === action.key) {172continue;173}174if (action_map[k].conflictKey !== conflict_key) {175continue;176}177178if (!(k in rows)) {179continue;180}181182remove_action(k);183}184}185186option.disabled = true;187188var aural = JX.$N('span', {className: 'aural-only'}, action.auralLabel);189190var icon = new JX.PHUIXIconView()191.setIcon('fa-times-circle');192193var remove = JX.$N('a', {href: '#'}, [aural, icon.getNode()]);194195var control = new JX.PHUIXFormControl()196.setLabel(action.label)197.setError(remove)198.setControl(action.type, action.spec)199.setClass('phui-comment-action');200var node = control.getNode();201202JX.Stratcom.addSigil(node, 'touchable');203204JX.DOM.listen(node, 'gesture.swipe.end', null, function(e) {205var data = e.getData();206207if (data.direction != 'left') {208// Didn't swipe left.209return;210}211212if (data.length <= (JX.Vector.getDim(node).x / 2)) {213// Didn't swipe far enough.214return;215}216217remove_action(action.key);218});219220rows[action.key] = {221control: control,222node: node,223option: option224};225226JX.DOM.listen(remove, 'click', null, function(e) {227e.kill();228remove_action(action.key);229});230231place_node.parentNode.insertBefore(node, place_node);232233redraw();234235force_preview();236237return control;238}239240JX.DOM.listen(form_node, ['submit', 'didSyntheticSubmit'], null, function() {241input_node.value = serialize_actions();242});243244if (config.showPreview) {245var request = new JX.PhabricatorShapedRequest(246config.actionURI,247onresponse,248get_data);249250var trigger = JX.bind(request, request.trigger);251252JX.DOM.listen(form_node, 'keydown', null, trigger);253254JX.DOM.listen(form_node, 'shouldRefresh', null, force_preview);255request.start();256257var old_device = JX.Device.getDevice();258259var ondevicechange = function() {260var new_device = JX.Device.getDevice();261262var panel = JX.$(config.panelID);263if (new_device == 'desktop') {264request.setRateLimit(500);265266// Force an immediate refresh if we switched from another device type267// to desktop.268if (old_device != new_device) {269force_preview();270}271} else {272// On mobile, don't show live previews and only save drafts every273// 10 seconds.274request.setRateLimit(10000);275JX.DOM.hide(panel);276}277278old_device = new_device;279};280281ondevicechange();282283JX.Stratcom.listen('phabricator-device-change', null, ondevicechange);284}285286restore_draft_actions(config.drafts || []);287288});289290291