diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ 'core.pkg.js' => '2ff7879f', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '58712637', - 'differential.pkg.js' => '3a7c5866', + 'differential.pkg.js' => '6375358e', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '84c8f8fd', 'favicon.ico' => '30672e08', @@ -390,15 +390,14 @@ 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '408bf173', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', - 'rsrc/js/application/diff/DiffChangeset.js' => '454cfe59', - 'rsrc/js/application/diff/DiffChangesetList.js' => '50bc5b50', - 'rsrc/js/application/diff/DiffInline.js' => '38a957be', + 'rsrc/js/application/diff/DiffChangeset.js' => '4c9c47ad', + 'rsrc/js/application/diff/DiffChangesetList.js' => '589a30aa', + 'rsrc/js/application/diff/DiffInline.js' => '98c12b2f', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', - 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '9ed8d2b6', 'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d', 'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', - 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '995c805a', + 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '89d11432', 'rsrc/js/application/differential/behavior-keyboard-nav.js' => '92904457', 'rsrc/js/application/differential/behavior-populate.js' => '5e41c819', 'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb', @@ -572,7 +571,6 @@ 'd3' => 'a11a5ff2', 'differential-changeset-view-css' => '41af6d25', 'differential-core-view-css' => '5b7b8ff4', - 'differential-inline-comment-editor' => '9ed8d2b6', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', 'differential-revision-history-css' => '0e8eb855', @@ -624,7 +622,7 @@ 'javelin-behavior-diff-preview-link' => '051c7832', 'javelin-behavior-differential-comment-jump' => '4fdb476d', 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', - 'javelin-behavior-differential-edit-inline-comments' => '995c805a', + 'javelin-behavior-differential-edit-inline-comments' => '89d11432', 'javelin-behavior-differential-feedback-preview' => 'b064af76', 'javelin-behavior-differential-keyboard-navigation' => '92904457', 'javelin-behavior-differential-populate' => '5e41c819', @@ -785,9 +783,9 @@ 'phabricator-darklog' => 'c8e1ffe3', 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', - 'phabricator-diff-changeset' => '454cfe59', - 'phabricator-diff-changeset-list' => '50bc5b50', - 'phabricator-diff-inline' => '38a957be', + 'phabricator-diff-changeset' => '4c9c47ad', + 'phabricator-diff-changeset-list' => '589a30aa', + 'phabricator-diff-inline' => '98c12b2f', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -1132,9 +1130,6 @@ 'javelin-dom', 'javelin-workflow', ), - '38a957be' => array( - 'javelin-dom', - ), '3ab51e2c' => array( 'javelin-behavior', 'javelin-behavior-device', @@ -1214,17 +1209,6 @@ 'javelin-behavior', 'javelin-dom', ), - '454cfe59' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - 'javelin-router', - 'javelin-behavior-device', - 'javelin-vector', - 'phabricator-diff-inline', - ), '469c0d9e' => array( 'javelin-behavior', 'javelin-dom', @@ -1286,6 +1270,17 @@ 'javelin-uri', 'phabricator-notification', ), + '4c9c47ad' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + 'javelin-router', + 'javelin-behavior-device', + 'javelin-vector', + 'phabricator-diff-inline', + ), '4d863052' => array( 'javelin-dom', 'javelin-util', @@ -1312,9 +1307,6 @@ 'javelin-typeahead-source', 'javelin-util', ), - '50bc5b50' => array( - 'javelin-install', - ), '519705ea' => array( 'javelin-install', 'javelin-dom', @@ -1356,6 +1348,9 @@ 'javelin-vector', 'javelin-dom', ), + '589a30aa' => array( + 'javelin-install', + ), '58dea2fa' => array( 'javelin-install', 'javelin-util', @@ -1596,6 +1591,13 @@ 'phabricator-draggable-list', 'javelin-workboard-column', ), + '89d11432' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'javelin-util', + 'javelin-vector', + ), '8a41885b' => array( 'javelin-install', 'javelin-dom', @@ -1675,13 +1677,8 @@ 'javelin-dom', 'javelin-reactor-dom', ), - '995c805a' => array( - 'javelin-behavior', - 'javelin-stratcom', + '98c12b2f' => array( 'javelin-dom', - 'javelin-util', - 'javelin-vector', - 'differential-inline-comment-editor', ), '9a6dd75c' => array( 'javelin-behavior', @@ -1706,14 +1703,6 @@ '9d9685d6' => array( 'phui-oi-list-view-css', ), - '9ed8d2b6' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-request', - 'javelin-workflow', - ), '9f36c42d' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2456,10 +2445,10 @@ 'javelin-behavior-phabricator-object-selector', 'javelin-behavior-repository-crossreference', 'javelin-behavior-load-blame', - 'differential-inline-comment-editor', 'javelin-behavior-differential-toggle-files', 'javelin-behavior-differential-user-select', 'javelin-behavior-aphront-more', + 'phabricator-diff-inline', 'phabricator-diff-changeset', 'phabricator-diff-changeset-list', ), diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php --- a/resources/celerity/packages.php +++ b/resources/celerity/packages.php @@ -203,10 +203,11 @@ 'javelin-behavior-repository-crossreference', 'javelin-behavior-load-blame', - 'differential-inline-comment-editor', 'javelin-behavior-differential-toggle-files', 'javelin-behavior-differential-user-select', 'javelin-behavior-aphront-more', + + 'phabricator-diff-inline', 'phabricator-diff-changeset', 'phabricator-diff-changeset-list', ), diff --git a/src/infrastructure/diff/PhabricatorInlineCommentController.php b/src/infrastructure/diff/PhabricatorInlineCommentController.php --- a/src/infrastructure/diff/PhabricatorInlineCommentController.php +++ b/src/infrastructure/diff/PhabricatorInlineCommentController.php @@ -94,19 +94,6 @@ $op = $this->getOperation(); switch ($op) { - case 'busy': - if ($request->isFormPost()) { - return new AphrontAjaxResponse(); - } - - return $this->newDialog() - ->setTitle(pht('Already Editing')) - ->appendParagraph( - pht( - 'You are already editing an inline comment. Finish editing '. - 'your current comment before adding new comments.')) - ->addCancelButton('/') - ->addSubmitButton(pht('Jump to Inline')); case 'hide': case 'show': if (!$request->validateCSRF()) { diff --git a/webroot/rsrc/js/application/diff/DiffChangeset.js b/webroot/rsrc/js/application/diff/DiffChangeset.js --- a/webroot/rsrc/js/application/diff/DiffChangeset.js +++ b/webroot/rsrc/js/application/diff/DiffChangeset.js @@ -433,6 +433,18 @@ return inline; }, + newInlineReply: function(original) { + var inline = new JX.DiffInline() + .setChangeset(this) + .bindToReply(original); + + this._inlines.push(inline); + + inline.create(); + + return inline; + }, + getInlineByID: function(id) { // TODO: Currently, this will only find inlines which the user has // already interacted with! Inlines are built lazily as events arrive. diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -41,6 +41,12 @@ 'click', ['differential-inline-comment', 'differential-inline-delete'], ondelete); + + var onreply = JX.bind(this, this._ifawake, this._onaction, 'reply'); + JX.Stratcom.listen( + 'click', + ['differential-inline-comment', 'differential-inline-reply'], + onreply); }, properties: { @@ -410,6 +416,9 @@ case 'delete': inline.delete(is_ref); break; + case 'reply': + inline.reply(); + break; } }, diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -24,6 +24,7 @@ _displaySide: null, _isNewFile: null, _undoRow: null, + _replyToCommentPHID: null, _isDeleted: false, _isInvisible: false, @@ -66,32 +67,50 @@ }, bindToRange: function(data) { - this._id = null; - this._phid = null; - - this._hidden = false; - this._displaySide = data.displaySide; this._number = data.number; this._length = data.length; this._isNewFile = data.isNewFile; this._changesetID = data.changesetID; + // Insert the comment after any other comments which already appear on + // the same row. + var parent_row = JX.DOM.findAbove(data.target, 'tr'); + var target_row = parent_row.nextSibling; + while (target_row && JX.Stratcom.hasSigil(target_row, 'inline-row')) { + target_row = target_row.nextSibling; + } + var row = this._newRow(); - JX.Stratcom.getData(row).inline = this; - this._row = row; + parent_row.parentNode.insertBefore(row, target_row); this.setInvisible(true); - // Insert the comment after any other comments which already appear on - // the same row. - var parent_row = JX.DOM.findAbove(data.target, 'tr'); + return this; + }, + + bindToReply: function(inline) { + this._displaySide = inline._displaySide; + this._number = inline._number; + this._length = inline._length; + this._isNewFile = inline._isNewFile; + this._changesetID = inline._changesetID; + + this._replyToCommentPHID = inline._phid; + + // TODO: This should insert correctly into the thread, not just at the + // bottom. + var parent_row = inline._row; var target_row = parent_row.nextSibling; while (target_row && JX.Stratcom.hasSigil(target_row, 'inline-row')) { target_row = target_row.nextSibling; } + + var row = this._newRow(); parent_row.parentNode.insertBefore(row, target_row); + this.setInvisible(true); + return this; }, @@ -100,7 +119,16 @@ sigil: 'inline-row' }; - return JX.$N('tr', attributes); + var row = JX.$N('tr', attributes); + + JX.Stratcom.getData(row).inline = this; + this._row = row; + + this._id = null; + this._phid = null; + this._hidden = false; + + return row; }, setHidden: function(hidden) { @@ -172,6 +200,11 @@ .send(); }, + reply: function() { + var changeset = this.getChangeset(); + return changeset.newInlineReply(this); + }, + edit: function() { var uri = this._getInlineURI(); var handler = JX.bind(this, this._oneditresponse); @@ -238,6 +271,10 @@ return this._changesetID; }, + getReplyToCommentPHID: function() { + return this._replyToCommentPHID; + }, + setDeleted: function(deleted) { this._isDeleted = deleted; this._redraw(); @@ -266,7 +303,7 @@ length: this.getLineLength(), is_new: this.isNewFile(), changesetID: this.getChangesetID(), - replyToCommentPHID: '' + replyToCommentPHID: this.getReplyToCommentPHID() || '', }; }, diff --git a/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js b/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js deleted file mode 100644 --- a/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js +++ /dev/null @@ -1,360 +0,0 @@ -/** - * @provides differential-inline-comment-editor - * @requires javelin-dom - * javelin-util - * javelin-stratcom - * javelin-install - * javelin-request - * javelin-workflow - */ - -JX.install('DifferentialInlineCommentEditor', { - - construct : function(uri) { - this._uri = uri; - }, - - events : ['done'], - - members : { - _uri : null, - _undoText : null, - _completed: false, - _skipOverInlineCommentRows : function(node) { - // TODO: Move this semantic information out of class names. - while (node && node.className.indexOf('inline') !== -1) { - node = node.nextSibling; - } - return node; - }, - _buildRequestData : function() { - return { - op : this.getOperation(), - on_right : this.getOnRight(), - id : this.getID(), - number : this.getLineNumber(), - is_new : (this.getIsNew() ? 1 : 0), - length : this.getLength(), - changesetID : this.getChangesetID(), - text : this.getText() || '', - renderer: this.getRenderer(), - replyToCommentPHID: this.getReplyToCommentPHID() || '', - }; - }, - _draw : function(content, exact_row) { - var row = this.getRow(); - var table = this.getTable(); - var target = exact_row ? row : this._skipOverInlineCommentRows(row); - - function copyRows(dst, src, before) { - var rows = JX.DOM.scry(src, 'tr'); - for (var ii = 0; ii < rows.length; ii++) { - - // Find the table this belongs to. If it's a sub-table, like a - // table in an inline comment, don't copy it. - if (JX.DOM.findAbove(rows[ii], 'table') !== src) { - continue; - } - - if (before) { - dst.insertBefore(rows[ii], before); - } else { - dst.appendChild(rows[ii]); - } - } - return rows; - } - - return copyRows(table, content, target); - }, - _removeUndoLink : function() { - var rows = JX.DifferentialInlineCommentEditor._undoRows; - if (rows) { - for (var ii = 0; ii < rows.length; ii++) { - JX.DOM.remove(rows[ii]); - } - } - JX.DifferentialInlineCommentEditor._undoRows = []; - }, - _undo : function() { - this._removeUndoLink(); - - if (this._undoText) { - this.setText(this._undoText); - } else { - this.setOperation('undelete'); - } - - this.start(); - }, - _registerUndoListener : function() { - if (!JX.DifferentialInlineCommentEditor._activeEditor) { - JX.Stratcom.listen( - 'click', - 'differential-inline-comment-undo', - function(e) { - JX.DifferentialInlineCommentEditor._activeEditor._undo(); - e.kill(); - }); - } - JX.DifferentialInlineCommentEditor._activeEditor = this; - }, - _setRowState : function(state) { - var is_hidden = (state == 'hidden'); - var is_loading = (state == 'loading'); - var row = this.getRow(); - JX.DOM.alterClass(row, 'differential-inline-hidden', is_hidden); - JX.DOM.alterClass(row, 'differential-inline-loading', is_loading); - }, - _didContinueWorkflow : function(response) { - var drawn = this._draw(JX.$H(response).getNode()); - - var op = this.getOperation(); - if (op == 'edit') { - this._setRowState('hidden'); - } - - JX.DOM.find( - drawn[0], - 'textarea', - 'differential-inline-comment-edit-textarea').focus(); - - var oncancel = JX.bind(this, function(e) { - e.kill(); - - this._didCancelWorkflow(); - - if (op == 'edit') { - this._setRowState('visible'); - } - - JX.DOM.remove(drawn[0]); - }); - JX.DOM.listen(drawn[0], 'click', 'inline-edit-cancel', oncancel); - - var onsubmit = JX.bind(this, function(e) { - e.kill(); - - JX.Workflow.newFromForm(e.getTarget()) - .setHandler(JX.bind(this, function(response) { - JX.DOM.remove(drawn[0]); - if (op == 'edit') { - this._setRowState('visible'); - } - this._didCompleteWorkflow(response); - })) - .start(); - - JX.DOM.alterClass(drawn[0], 'differential-inline-loading', true); - }); - JX.DOM.listen( - drawn[0], - ['submit', 'didSyntheticSubmit'], - 'inline-edit-form', - onsubmit); - }, - - - _didCompleteWorkflow : function(response) { - var op = this.getOperation(); - - // We don't get any markup back if the user deletes a comment, or saves - // an empty comment (which effects a delete). - if (response.markup) { - this._draw(JX.$H(response.markup).getNode()); - } - - if (op == 'delete' || op == 'refdelete') { - this._undoText = null; - this._drawUndo(); - } else { - this._removeUndoLink(); - } - - // These operations remove the old row (edit adds a new row first). - var remove_old = (op == 'edit' || op == 'delete' || op == 'refdelete'); - if (remove_old) { - this._setRowState('hidden'); - } - - if (op == 'undelete') { - this._setRowState('visible'); - } - - this._completed = true; - - this._didUpdate(); - this.invoke('done'); - }, - - - _didCancelWorkflow : function() { - this.invoke('done'); - - switch (this.getOperation()) { - case 'delete': - case 'refdelete': - if (!this._completed) { - this._setRowState('visible'); - } - return; - case 'undelete': - return; - } - - var textarea; - try { - textarea = JX.DOM.find( - document.body, // TODO: use getDialogRootNode() when available - 'textarea', - 'differential-inline-comment-edit-textarea'); - } catch (ex) { - // The close handler is called whenever the dialog closes, even if the - // user closed it by completing the workflow with "Save". The - // JX.Workflow API should probably be refined to allow programmatic - // distinction of close caused by 'cancel' vs 'submit'. Testing for - // presence of the textarea serves as a proxy for detecting a 'cancel'. - return; - } - - var text = textarea.value; - - // If the user hasn't edited the text (i.e., no change from original for - // 'edit' or no text at all), don't offer them an undo. - if (text == this.getOriginalText() || text === '') { - return; - } - - // Save the text so we can 'undo' back to it. - this._undoText = text; - - this._drawUndo(); - }, - - _drawUndo: function() { - var templates = this.getTemplates(); - var template = this.getOnRight() ? templates.r : templates.l; - template = JX.$H(template).getNode(); - - // NOTE: Operation order matters here; we can't remove anything until - // after we draw the new rows because _draw uses the old rows to figure - // out where to place the comment. - - // We use 'exact_row' to put the "undo" text directly above the affected - // comment. - var exact_row = true; - var rows = this._draw(template, exact_row); - - this._removeUndoLink(); - - JX.DifferentialInlineCommentEditor._undoRows = rows; - }, - - _onBusyWorkflow: function() { - // If the user clicks the "Jump to Inline" button, scroll to the row - // being edited. - JX.DOM.scrollTo(this.getRow()); - }, - - start : function() { - var op = this.getOperation(); - - // The user is already editing a comment, we're going to give them an - // error message. - if (op == 'busy') { - var onbusy = JX.bind(this, this._onBusyWorkflow); - - new JX.Workflow(this._uri, {op: op}) - .setHandler(onbusy) - .start(); - - return this; - } - - this._registerUndoListener(); - var data = this._buildRequestData(); - - if (op == 'delete' || op == 'refdelete' || op == 'undelete') { - this._setRowState('loading'); - - var oncomplete = JX.bind(this, this._didCompleteWorkflow); - var oncancel = JX.bind(this, this._didCancelWorkflow); - - new JX.Workflow(this._uri, data) - .setHandler(oncomplete) - .setCloseHandler(oncancel) - .start(); - } else { - var handler = JX.bind(this, this._didContinueWorkflow); - - if (op == 'edit') { - this._setRowState('loading'); - } - - new JX.Request(this._uri, handler) - .setData(data) - .send(); - } - - return this; - }, - - deleteByID: function(id) { - var data = { - op: 'refdelete', - id: id - }; - - new JX.Workflow(this._uri, data) - .setHandler(JX.bind(this, function() { - this._didUpdate(); - })) - .start(); - }, - - _didUpdate: function() { - // After making changes to inline comments, refresh the transaction - // preview at the bottom of the page. - - // TODO: This isn't the cleanest way to find the preview form, but - // rendering no longer has direct access to it. - var forms = JX.DOM.scry(document.body, 'form', 'transaction-append'); - if (forms.length) { - JX.DOM.invoke(forms[0], 'shouldRefresh'); - } - } - - }, - - statics : { - /** - * Global refernece to the 'undo' rows currently rendered in the document. - */ - _undoRows : null, - - /** - * Global listener for the 'undo' click associated with the currently - * displayed 'undo' link. When an editor is start()ed, it becomes the active - * editor. - */ - _activeEditor : null - }, - - properties : { - operation : null, - row : null, - table : null, - onRight : null, - ID : null, - lineNumber : null, - changesetID : null, - length : null, - isNew : null, - text : null, - templates : null, - originalText : null, - renderer: null, - replyToCommentPHID: null - } - -}); diff --git a/webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js b/webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js --- a/webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js +++ b/webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js @@ -5,7 +5,6 @@ * javelin-dom * javelin-util * javelin-vector - * differential-inline-comment-editor */ JX.behavior('differential-edit-inline-comments', function(config) { @@ -126,13 +125,6 @@ setSelectedCells([]); } - JX.DifferentialInlineCommentEditor.listen('done', function() { - selecting = false; - editor = false; - hideReticle(); - set_link_state(false); - }); - function isOnRight(node) { return node.parentNode.firstChild != node; } @@ -150,10 +142,6 @@ } } - var set_link_state = function(active) { - JX.DOM.alterClass(JX.$(config.stage), 'inline-editor-active', active); - }; - JX.Stratcom.listen( 'mousedown', ['differential-changeset', 'tag:th'], @@ -163,14 +151,6 @@ return; } - if (editor) { - new JX.DifferentialInlineCommentEditor(config.uri) - .setOperation('busy') - .setRow(editor.getRow().previousSibling) - .start(); - return; - } - if (selecting) { return; } @@ -290,8 +270,6 @@ origin = null; target = null; - set_link_state(true); - e.kill(); }); @@ -310,75 +288,4 @@ } }); - var action_handler = function(op, e) { - // NOTE: We prevent this event, rather than killing it, because some - // actions are now handled by DiffChangesetList. - e.prevent(); - - if (editor) { - return; - } - - var node = e.getNode('differential-inline-comment'); - - // If we're on a touch device, we didn't highlight the affected lines - // earlier because we can't use hover events to mutate the document. - // Highlight them now. - updateReticleForComment(e); - - handle_inline_action(node, op); - }; - - var handle_inline_action = function(node, op) { - var data = JX.Stratcom.getData(node); - - var original = data.original; - var reply_phid = null; - if (op == 'reply') { - // If the user hit "reply", the original text is empty (a new reply), not - // the text of the comment they're replying to. - original = ''; - reply_phid = data.phid; - } - - var row = JX.DOM.findAbove(node, 'tr'); - var changeset_root = JX.DOM.findAbove( - node, - 'div', - 'differential-changeset'); - var view = JX.DiffChangeset.getForNode(changeset_root); - - editor = new JX.DifferentialInlineCommentEditor(config.uri) - .setTemplates(view.getUndoTemplates()) - .setOperation(op) - .setID(data.id) - .setChangesetID(data.changesetID) - .setLineNumber(data.number) - .setLength(data.length) - .setOnRight(data.on_right) - .setOriginalText(original) - .setRow(row) - .setTable(row.parentNode) - .setReplyToCommentPHID(reply_phid) - .setRenderer(view.getRenderer()) - .start(); - - set_link_state(true); - }; - - for (var op in {'reply': 1}) { - JX.Stratcom.listen( - 'click', - ['differential-inline-comment', 'differential-inline-' + op], - JX.bind(null, action_handler, op)); - } - - JX.Stratcom.listen( - 'differential-inline-action', - null, - function(e) { - var data = e.getData(); - handle_inline_action(data.node, data.op); - }); - });