Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/js/application/diff/DiffInline.js
| Show All 12 Lines | members: { | ||||
| _id: null, | _id: null, | ||||
| _phid: null, | _phid: null, | ||||
| _changesetID: null, | _changesetID: null, | ||||
| _row: null, | _row: null, | ||||
| _number: null, | _number: null, | ||||
| _length: null, | _length: null, | ||||
| _displaySide: null, | _displaySide: null, | ||||
| _isNewFile: null, | _isNewFile: null, | ||||
| _undoRow: null, | |||||
| _replyToCommentPHID: null, | _replyToCommentPHID: null, | ||||
| _originalText: null, | _originalText: null, | ||||
| _snippet: null, | _snippet: null, | ||||
| _isDeleted: false, | _isDeleted: false, | ||||
| _isInvisible: false, | _isInvisible: false, | ||||
| _isLoading: false, | _isLoading: false, | ||||
| _changeset: null, | _changeset: null, | ||||
| _isCollapsed: false, | _isCollapsed: false, | ||||
| _isDraft: null, | _isDraft: null, | ||||
| _isDraftDone: null, | _isDraftDone: null, | ||||
| _isFixed: null, | _isFixed: null, | ||||
| _isEditing: false, | _isEditing: false, | ||||
| _isNew: false, | _isNew: false, | ||||
| _isSynthetic: false, | _isSynthetic: false, | ||||
| _isHidden: false, | _isHidden: false, | ||||
| _editRow: null, | |||||
| _undoRow: null, | |||||
| _undoType: null, | |||||
| _undoText: null, | |||||
| bindToRow: function(row) { | bindToRow: function(row) { | ||||
| this._row = row; | this._row = row; | ||||
| var row_data = JX.Stratcom.getData(row); | var row_data = JX.Stratcom.getData(row); | ||||
| row_data.inline = this; | row_data.inline = this; | ||||
| this._isCollapsed = row_data.hidden || false; | this._isCollapsed = row_data.hidden || false; | ||||
| // TODO: Get smarter about this once we do more editing, this is pretty | // TODO: Get smarter about this once we do more editing, this is pretty | ||||
| // hacky. | // hacky. | ||||
| var comment = JX.DOM.find(row, 'div', 'differential-inline-comment'); | var comment = JX.DOM.find(row, 'div', 'differential-inline-comment'); | ||||
| var data = JX.Stratcom.getData(comment); | var data = JX.Stratcom.getData(comment); | ||||
| this._id = data.id; | this._readInlineState(data); | ||||
| this._phid = data.phid; | this._phid = data.phid; | ||||
| // TODO: This is very, very, very, very, very, very, very hacky. | if (data.on_right) { | ||||
| var td = comment.parentNode; | |||||
| var th = td.previousSibling; | |||||
| if (th.parentNode.firstChild != th) { | |||||
| this._displaySide = 'right'; | this._displaySide = 'right'; | ||||
| } else { | } else { | ||||
| this._displaySide = 'left'; | this._displaySide = 'left'; | ||||
| } | } | ||||
| this._number = parseInt(data.number, 10); | this._number = parseInt(data.number, 10); | ||||
| this._length = parseInt(data.length, 10); | this._length = parseInt(data.length, 10); | ||||
| this._originalText = data.original; | this._originalText = data.original; | ||||
| this._isNewFile = | this._isNewFile = data.isNewFile; | ||||
| (this.getDisplaySide() == 'right') || | |||||
| (data.left != data.right); | |||||
| this._replyToCommentPHID = data.replyToCommentPHID; | this._replyToCommentPHID = data.replyToCommentPHID; | ||||
| this._isDraft = data.isDraft; | this._isDraft = data.isDraft; | ||||
| this._isFixed = data.isFixed; | this._isFixed = data.isFixed; | ||||
| this._isGhost = data.isGhost; | this._isGhost = data.isGhost; | ||||
| this._isSynthetic = data.isSynthetic; | this._isSynthetic = data.isSynthetic; | ||||
| this._isDraftDone = data.isDraftDone; | this._isDraftDone = data.isDraftDone; | ||||
| this._changesetID = data.changesetID; | this._changesetID = data.changesetID; | ||||
| this._isNew = false; | this._isNew = false; | ||||
| this._snippet = data.snippet; | this._snippet = data.snippet; | ||||
| this._isEditing = data.isEditing; | |||||
| if (this._isEditing) { | |||||
| this.edit(); | |||||
| } else { | |||||
| this.setInvisible(false); | this.setInvisible(false); | ||||
| } | |||||
| return this; | return this; | ||||
| }, | }, | ||||
| isDraft: function() { | isDraft: function() { | ||||
| return this._isDraft; | return this._isDraft; | ||||
| }, | }, | ||||
| ▲ Show 20 Lines • Show All 299 Lines • ▼ Show 20 Lines | delete: function(is_ref) { | ||||
| var op; | var op; | ||||
| if (is_ref) { | if (is_ref) { | ||||
| op = 'refdelete'; | op = 'refdelete'; | ||||
| } else { | } else { | ||||
| op = 'delete'; | op = 'delete'; | ||||
| } | } | ||||
| // If there's an existing "unedit" undo element, remove it. | |||||
| if (this._undoRow) { | |||||
| JX.DOM.remove(this._undoRow); | |||||
| this._undoRow = null; | |||||
| } | |||||
| var data = this._newRequestData(op); | var data = this._newRequestData(op); | ||||
| this.setLoading(true); | this.setLoading(true); | ||||
| new JX.Workflow(uri, data) | new JX.Workflow(uri, data) | ||||
| .setHandler(handler) | .setHandler(handler) | ||||
| .start(); | .start(); | ||||
| }, | }, | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | _newRequestData: function(operation, text) { | ||||
| is_new: this.isNewFile(), | is_new: this.isNewFile(), | ||||
| changesetID: this.getChangesetID(), | changesetID: this.getChangesetID(), | ||||
| replyToCommentPHID: this.getReplyToCommentPHID() || '', | replyToCommentPHID: this.getReplyToCommentPHID() || '', | ||||
| text: text || '' | text: text || '' | ||||
| }; | }; | ||||
| }, | }, | ||||
| _oneditresponse: function(response) { | _oneditresponse: function(response) { | ||||
| var rows = JX.$H(response).getNode(); | var rows = JX.$H(response.view).getNode(); | ||||
| this._readInlineState(response.inline); | |||||
| this._drawEditRows(rows); | this._drawEditRows(rows); | ||||
| this.setLoading(false); | this.setLoading(false); | ||||
| this.setInvisible(true); | this.setInvisible(true); | ||||
| }, | }, | ||||
| _oncreateresponse: function(response) { | _oncreateresponse: function(response) { | ||||
| var rows = JX.$H(response).getNode(); | var rows = JX.$H(response.view).getNode(); | ||||
| this._readInlineState(response.inline); | |||||
| this._drawEditRows(rows); | this._drawEditRows(rows); | ||||
| }, | }, | ||||
| _readInlineState: function(state) { | |||||
| this._id = state.id; | |||||
| }, | |||||
| _ondeleteresponse: function() { | _ondeleteresponse: function() { | ||||
| this._drawUndeleteRows(); | this._drawUndeleteRows(); | ||||
| this.setLoading(false); | this.setLoading(false); | ||||
| this.setDeleted(true); | this.setDeleted(true); | ||||
| this._didUpdate(); | this._didUpdate(); | ||||
| }, | }, | ||||
| _drawUndeleteRows: function() { | _drawUndeleteRows: function() { | ||||
| this._undoType = 'undelete'; | |||||
| this._undoText = null; | |||||
| return this._drawUndoRows('undelete', this._row); | return this._drawUndoRows('undelete', this._row); | ||||
| }, | }, | ||||
| _drawUneditRows: function(text) { | _drawUneditRows: function(text) { | ||||
| this._undoType = 'unedit'; | |||||
| this._undoText = text; | |||||
| return this._drawUndoRows('unedit', null, text); | return this._drawUndoRows('unedit', null, text); | ||||
| }, | }, | ||||
| _drawUndoRows: function(mode, cursor, text) { | _drawUndoRows: function(mode, cursor, text) { | ||||
| var templates = this.getChangeset().getUndoTemplates(); | var templates = this.getChangeset().getUndoTemplates(); | ||||
| var template; | var template; | ||||
| if (this.getDisplaySide() == 'right') { | if (this.getDisplaySide() == 'right') { | ||||
| template = templates.r; | template = templates.r; | ||||
| } else { | } else { | ||||
| template = templates.l; | template = templates.l; | ||||
| } | } | ||||
| template = JX.$H(template).getNode(); | template = JX.$H(template).getNode(); | ||||
| this._undoRow = this._drawRows(template, cursor, mode, text); | this._undoRow = this._drawRows(template, cursor, mode, text); | ||||
| }, | }, | ||||
| _drawContentRows: function(rows) { | _drawContentRows: function(rows) { | ||||
| return this._drawRows(rows, null, 'content'); | return this._drawRows(rows, null, 'content'); | ||||
| }, | }, | ||||
| _drawEditRows: function(rows) { | _drawEditRows: function(rows) { | ||||
| this.setEditing(true); | this.setEditing(true); | ||||
| return this._drawRows(rows, null, 'edit'); | this._editRow = this._drawRows(rows, null, 'edit'); | ||||
| }, | }, | ||||
| _drawRows: function(rows, cursor, type, text) { | _drawRows: function(rows, cursor, type, text) { | ||||
| var first_row = JX.DOM.scry(rows, 'tr')[0]; | var first_row = JX.DOM.scry(rows, 'tr')[0]; | ||||
| var first_meta; | |||||
| var row = first_row; | var row = first_row; | ||||
| var anchor = cursor || this._row; | var anchor = cursor || this._row; | ||||
| cursor = cursor || this._row.nextSibling; | cursor = cursor || this._row.nextSibling; | ||||
| var result_row; | |||||
| var next_row; | var next_row; | ||||
| while (row) { | while (row) { | ||||
| // Grab this first, since it's going to change once we insert the row | // Grab this first, since it's going to change once we insert the row | ||||
| // into the document. | // into the document. | ||||
| next_row = row.nextSibling; | next_row = row.nextSibling; | ||||
| // Bind edit and undo rows to this DiffInline object so that | // Bind edit and undo rows to this DiffInline object so that | ||||
| // interactions like hovering work properly. | // interactions like hovering work properly. | ||||
| JX.Stratcom.getData(row).inline = this; | JX.Stratcom.getData(row).inline = this; | ||||
| anchor.parentNode.insertBefore(row, cursor); | anchor.parentNode.insertBefore(row, cursor); | ||||
| cursor = row; | cursor = row; | ||||
| var row_meta = { | if (!result_row) { | ||||
| node: row, | result_row = row; | ||||
| type: type, | |||||
| text: text || null, | |||||
| listeners: [] | |||||
| }; | |||||
| if (!first_meta) { | |||||
| first_meta = row_meta; | |||||
| } | |||||
| if (type == 'edit') { | |||||
| row_meta.listeners.push( | |||||
| JX.DOM.listen( | |||||
| row, | |||||
| ['submit', 'didSyntheticSubmit'], | |||||
| 'inline-edit-form', | |||||
| JX.bind(this, this._onsubmit, row_meta))); | |||||
| row_meta.listeners.push( | |||||
| JX.DOM.listen( | |||||
| row, | |||||
| 'click', | |||||
| 'inline-edit-cancel', | |||||
| JX.bind(this, this._oncancel, row_meta))); | |||||
| } else if (type == 'content') { | |||||
| // No special listeners for these rows. | |||||
| } else { | |||||
| row_meta.listeners.push( | |||||
| JX.DOM.listen( | |||||
| row, | |||||
| 'click', | |||||
| 'differential-inline-comment-undo', | |||||
| JX.bind(this, this._onundo, row_meta))); | |||||
| } | } | ||||
| // If the row has a textarea, focus it. This allows the user to start | // If the row has a textarea, focus it. This allows the user to start | ||||
| // typing a comment immediately after a "new", "edit", or "reply" | // typing a comment immediately after a "new", "edit", or "reply" | ||||
| // action. | // action. | ||||
| var textareas = JX.DOM.scry( | var textareas = JX.DOM.scry( | ||||
| row, | row, | ||||
| 'textarea', | 'textarea', | ||||
| 'differential-inline-comment-edit-textarea'); | 'differential-inline-comment-edit-textarea'); | ||||
| if (textareas.length) { | if (textareas.length) { | ||||
| var area = textareas[0]; | var area = textareas[0]; | ||||
| area.focus(); | area.focus(); | ||||
| var length = area.value.length; | var length = area.value.length; | ||||
| JX.TextAreaUtils.setSelectionRange(area, length, length); | JX.TextAreaUtils.setSelectionRange(area, length, length); | ||||
| } | } | ||||
| row = next_row; | row = next_row; | ||||
| } | } | ||||
| JX.Stratcom.invoke('resize'); | JX.Stratcom.invoke('resize'); | ||||
| return first_meta; | return result_row; | ||||
| }, | }, | ||||
| _onsubmit: function(row, e) { | save: function(form) { | ||||
| e.kill(); | var handler = JX.bind(this, this._onsubmitresponse); | ||||
| var handler = JX.bind(this, this._onsubmitresponse, row); | |||||
| this.setLoading(true); | this.setLoading(true); | ||||
| JX.Workflow.newFromForm(e.getTarget()) | JX.Workflow.newFromForm(form) | ||||
| .setHandler(handler) | .setHandler(handler) | ||||
| .start(); | .start(); | ||||
| }, | }, | ||||
| _onundo: function(row, e) { | undo: function() { | ||||
| e.kill(); | |||||
| this._removeRow(row); | JX.DOM.remove(this._undoRow); | ||||
| this._undoRow = null; | |||||
| if (row.type == 'undelete') { | if (this._undoType === 'undelete') { | ||||
| var uri = this._getInlineURI(); | var uri = this._getInlineURI(); | ||||
| var data = this._newRequestData('undelete'); | var data = this._newRequestData('undelete'); | ||||
| var handler = JX.bind(this, this._onundelete); | var handler = JX.bind(this, this._onundelete); | ||||
| this.setDeleted(false); | this.setDeleted(false); | ||||
| this.setLoading(true); | this.setLoading(true); | ||||
| new JX.Request(uri, handler) | new JX.Request(uri, handler) | ||||
| .setData(data) | .setData(data) | ||||
| .send(); | .send(); | ||||
| } | } | ||||
| if (row.type == 'unedit') { | if (this._undoType === 'unedit') { | ||||
| if (this.getID()) { | this.edit(this._undoText); | ||||
| this.edit(row.text); | |||||
| } else { | |||||
| this.create(row.text); | |||||
| } | |||||
| } | } | ||||
| }, | }, | ||||
| _onundelete: function() { | _onundelete: function() { | ||||
| this.setLoading(false); | this.setLoading(false); | ||||
| this._didUpdate(); | this._didUpdate(); | ||||
| }, | }, | ||||
| _oncancel: function(row, e) { | cancel: function() { | ||||
| e.kill(); | var text = this._readText(this._editRow); | ||||
| JX.DOM.remove(this._editRow); | |||||
| this._editRow = null; | |||||
| var text = this._readText(row.node); | |||||
| if (text && text.length && (text != this._originalText)) { | if (text && text.length && (text != this._originalText)) { | ||||
| this._drawUneditRows(text); | this._drawUneditRows(text); | ||||
| } | } | ||||
| this._removeRow(row); | |||||
| this.setEditing(false); | this.setEditing(false); | ||||
| this.setInvisible(false); | this.setInvisible(false); | ||||
| this._didUpdate(true); | this._didUpdate(true); | ||||
| }, | }, | ||||
| _readText: function(row) { | _readText: function(row) { | ||||
| var textarea; | var textarea; | ||||
| try { | try { | ||||
| textarea = JX.DOM.find( | textarea = JX.DOM.find( | ||||
| row, | row, | ||||
| 'textarea', | 'textarea', | ||||
| 'differential-inline-comment-edit-textarea'); | 'differential-inline-comment-edit-textarea'); | ||||
| } catch (ex) { | } catch (ex) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return textarea.value; | return textarea.value; | ||||
| }, | }, | ||||
| _onsubmitresponse: function(row, response) { | _onsubmitresponse: function(response) { | ||||
| this._removeRow(row); | if (this._editRow) { | ||||
| JX.DOM.remove(this._editRow); | |||||
| this._editRow = null; | |||||
| } | |||||
| this.setLoading(false); | this.setLoading(false); | ||||
| this.setInvisible(false); | this.setInvisible(false); | ||||
| this.setEditing(false); | this.setEditing(false); | ||||
| this._onupdate(response); | this._onupdate(response); | ||||
| }, | }, | ||||
| _onupdate: function(response) { | _onupdate: function(response) { | ||||
| var new_row; | var new_row; | ||||
| if (response.markup) { | if (response.view) { | ||||
| new_row = this._drawContentRows(JX.$H(response.markup).getNode()).node; | new_row = this._drawContentRows(JX.$H(response.view).getNode()); | ||||
| } | } | ||||
| // TODO: Save the old row so the action it's undo-able if it was a | // TODO: Save the old row so the action it's undo-able if it was a | ||||
| // delete. | // delete. | ||||
| var remove_old = true; | var remove_old = true; | ||||
| if (remove_old) { | if (remove_old) { | ||||
| JX.DOM.remove(this._row); | JX.DOM.remove(this._row); | ||||
| } | } | ||||
| Show All 32 Lines | _redraw: function() { | ||||
| var is_collapsed = (this._isCollapsed && !this._isHidden); | var is_collapsed = (this._isCollapsed && !this._isHidden); | ||||
| var row = this._row; | var row = this._row; | ||||
| JX.DOM.alterClass(row, 'differential-inline-hidden', is_invisible); | JX.DOM.alterClass(row, 'differential-inline-hidden', is_invisible); | ||||
| JX.DOM.alterClass(row, 'differential-inline-loading', is_loading); | JX.DOM.alterClass(row, 'differential-inline-loading', is_loading); | ||||
| JX.DOM.alterClass(row, 'inline-hidden', is_collapsed); | JX.DOM.alterClass(row, 'inline-hidden', is_collapsed); | ||||
| }, | }, | ||||
| _removeRow: function(row) { | |||||
| JX.DOM.remove(row.node); | |||||
| for (var ii = 0; ii < row.listeners.length; ii++) { | |||||
| row.listeners[ii].remove(); | |||||
| } | |||||
| }, | |||||
| _getInlineURI: function() { | _getInlineURI: function() { | ||||
| var changeset = this.getChangeset(); | var changeset = this.getChangeset(); | ||||
| var list = changeset.getChangesetList(); | var list = changeset.getChangesetList(); | ||||
| return list.getInlineURI(); | return list.getInlineURI(); | ||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||