Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/js/application/diff/DiffInline.js
| Show All 13 Lines | members: { | ||||
| _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, | ||||
| _replyToCommentPHID: null, | _replyToCommentPHID: null, | ||||
| _originalText: null, | _originalState: null, | ||||
| _snippet: null, | _snippet: null, | ||||
| _menuItems: null, | _menuItems: null, | ||||
| _documentEngineKey: null, | _documentEngineKey: 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, | _editRow: null, | ||||
| _undoRow: null, | _undoRow: null, | ||||
| _undoType: null, | _undoType: null, | ||||
| _undoText: null, | _undoState: null, | ||||
| _draftRequest: null, | _draftRequest: null, | ||||
| _skipFocus: false, | _skipFocus: false, | ||||
| _menu: null, | _menu: null, | ||||
| _startOffset: null, | _startOffset: null, | ||||
| _endOffset: null, | _endOffset: null, | ||||
| _isSelected: false, | _isSelected: false, | ||||
| Show All 17 Lines | bindToRow: function(row) { | ||||
| 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); | ||||
| var original = '' + data.original; | this._originalState = data.contentState; | ||||
| if (original.length) { | |||||
| this._originalText = original; | |||||
| } else { | |||||
| this._originalText = null; | |||||
| } | |||||
| this._isNewFile = data.isNewFile; | this._isNewFile = data.isNewFile; | ||||
| 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; | ||||
| ▲ Show 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | canDone: function() { | ||||
| return true; | return true; | ||||
| }, | }, | ||||
| canCollapse: function() { | canCollapse: function() { | ||||
| return this._hasMenuAction('collapse'); | return this._hasMenuAction('collapse'); | ||||
| }, | }, | ||||
| getRawText: function() { | |||||
| return this._originalText; | |||||
| }, | |||||
| _newRow: function() { | _newRow: function() { | ||||
| var attributes = { | var attributes = { | ||||
| sigil: 'inline-row' | sigil: 'inline-row' | ||||
| }; | }; | ||||
| var row = JX.$N('tr', attributes); | var row = JX.$N('tr', attributes); | ||||
| JX.Stratcom.getData(row).inline = this; | JX.Stratcom.getData(row).inline = this; | ||||
| this._row = row; | this._row = row; | ||||
| this._id = null; | this._id = null; | ||||
| this._phid = null; | this._phid = null; | ||||
| this._isCollapsed = false; | this._isCollapsed = false; | ||||
| this._originalText = null; | this._originalState = null; | ||||
| return row; | return row; | ||||
| }, | }, | ||||
| setCollapsed: function(collapsed) { | setCollapsed: function(collapsed) { | ||||
| this._closeMenu(); | this._closeMenu(); | ||||
| this._isCollapsed = collapsed; | this._isCollapsed = collapsed; | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | _ondone: function(response) { | ||||
| JX.DOM.alterClass(comment, 'inline-state-is-draft', response.draftState); | JX.DOM.alterClass(comment, 'inline-state-is-draft', response.draftState); | ||||
| this._isFixed = response.isChecked; | this._isFixed = response.isChecked; | ||||
| this._isDraftDone = !!response.draftState; | this._isDraftDone = !!response.draftState; | ||||
| this._didUpdate(); | this._didUpdate(); | ||||
| }, | }, | ||||
| create: function(text) { | create: function(content_state) { | ||||
| var changeset = this.getChangeset(); | var changeset = this.getChangeset(); | ||||
| if (!this._documentEngineKey) { | if (!this._documentEngineKey) { | ||||
| this._documentEngineKey = changeset.getResponseDocumentEngineKey(); | this._documentEngineKey = changeset.getResponseDocumentEngineKey(); | ||||
| } | } | ||||
| var uri = this._getInlineURI(); | var uri = this._getInlineURI(); | ||||
| var handler = JX.bind(this, this._oncreateresponse); | var handler = JX.bind(this, this._oncreateresponse); | ||||
| var data = this._newRequestData('new', text); | var data = this._newRequestData('new', content_state); | ||||
| this.setLoading(true); | this.setLoading(true); | ||||
| new JX.Request(uri, handler) | new JX.Request(uri, handler) | ||||
| .setData(data) | .setData(data) | ||||
| .send(); | .send(); | ||||
| }, | }, | ||||
| _getContentState: function() { | |||||
| var state; | |||||
| if (this._editRow) { | |||||
| state = this._readFormState(this._editRow); | |||||
| } else { | |||||
| state = this._originalState; | |||||
| } | |||||
| return state; | |||||
| }, | |||||
| reply: function(with_quote) { | reply: function(with_quote) { | ||||
| this._closeMenu(); | this._closeMenu(); | ||||
| var text; | var content_state = this._newContentState(); | ||||
| if (with_quote) { | if (with_quote) { | ||||
| text = this.getRawText(); | var text = this._getContentState().text; | ||||
| text = '> ' + text.replace(/\n/g, '\n> ') + '\n\n'; | text = '> ' + text.replace(/\n/g, '\n> ') + '\n\n'; | ||||
| } else { | content_state.text = text; | ||||
| text = ''; | |||||
| } | } | ||||
| var changeset = this.getChangeset(); | var changeset = this.getChangeset(); | ||||
| return changeset.newInlineReply(this, text); | return changeset.newInlineReply(this, content_state); | ||||
| }, | }, | ||||
| edit: function(text, skip_focus) { | edit: function(content_state, skip_focus) { | ||||
| this._closeMenu(); | this._closeMenu(); | ||||
| this._skipFocus = !!skip_focus; | this._skipFocus = !!skip_focus; | ||||
| // If you edit an inline ("A"), modify the text ("AB"), cancel, and then | // If you edit an inline ("A"), modify the text ("AB"), cancel, and then | ||||
| // edit it again: discard the undo state ("AB"). Otherwise we end up | // edit it again: discard the undo state ("AB"). Otherwise we end up | ||||
| // with an open editor and an active "Undo" link, which is weird. | // with an open editor and an active "Undo" link, which is weird. | ||||
| if (this._undoRow) { | if (this._undoRow) { | ||||
| JX.DOM.remove(this._undoRow); | JX.DOM.remove(this._undoRow); | ||||
| this._undoRow = null; | this._undoRow = null; | ||||
| this._undoType = null; | this._undoType = null; | ||||
| this._undoText = null; | this._undoText = null; | ||||
| } | } | ||||
| var uri = this._getInlineURI(); | var uri = this._getInlineURI(); | ||||
| var handler = JX.bind(this, this._oneditresponse); | var handler = JX.bind(this, this._oneditresponse); | ||||
| var data = this._newRequestData('edit', text || null); | var data = this._newRequestData('edit', content_state); | ||||
| this.setLoading(true); | this.setLoading(true); | ||||
| new JX.Request(uri, handler) | new JX.Request(uri, handler) | ||||
| .setData(data) | .setData(data) | ||||
| .send(); | .send(); | ||||
| }, | }, | ||||
| ▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | members: { | ||||
| }, | }, | ||||
| setLoading: function(loading) { | setLoading: function(loading) { | ||||
| this._isLoading = loading; | this._isLoading = loading; | ||||
| this._redraw(); | this._redraw(); | ||||
| return this; | return this; | ||||
| }, | }, | ||||
| _newRequestData: function(operation, text) { | _newRequestData: function(operation, content_state) { | ||||
| var data = { | var data = { | ||||
| op: operation, | op: operation, | ||||
| is_new: this.isNewFile(), | is_new: this.isNewFile(), | ||||
| on_right: ((this.getDisplaySide() == 'right') ? 1 : 0), | on_right: ((this.getDisplaySide() == 'right') ? 1 : 0), | ||||
| renderer: this.getChangeset().getRendererKey(), | renderer: this.getChangeset().getRendererKey() | ||||
| text: text || null | |||||
| }; | }; | ||||
| if (operation === 'new') { | if (operation === 'new') { | ||||
| var create_data = { | var create_data = { | ||||
| changesetID: this.getChangesetID(), | changesetID: this.getChangesetID(), | ||||
| documentEngineKey: this._documentEngineKey, | documentEngineKey: this._documentEngineKey, | ||||
| replyToCommentPHID: this.getReplyToCommentPHID(), | replyToCommentPHID: this.getReplyToCommentPHID(), | ||||
| startOffset: this._startOffset, | startOffset: this._startOffset, | ||||
| endOffset: this._endOffset, | endOffset: this._endOffset, | ||||
| number: this.getLineNumber(), | number: this.getLineNumber(), | ||||
| length: this.getLineLength() | length: this.getLineLength() | ||||
| }; | }; | ||||
| JX.copy(data, create_data); | JX.copy(data, create_data); | ||||
| } else { | } else { | ||||
| var edit_data = { | var edit_data = { | ||||
| id: this._id | id: this._id | ||||
| }; | }; | ||||
| JX.copy(data, edit_data); | JX.copy(data, edit_data); | ||||
| } | } | ||||
| if (content_state) { | |||||
| data.hasContentState = 1; | |||||
| JX.copy(data, content_state); | |||||
| } | |||||
| return data; | return data; | ||||
| }, | }, | ||||
| _oneditresponse: function(response) { | _oneditresponse: function(response) { | ||||
| var rows = JX.$H(response.view).getNode(); | var rows = JX.$H(response.view).getNode(); | ||||
| this._readInlineState(response.inline); | this._readInlineState(response.inline); | ||||
| this._drawEditRows(rows); | this._drawEditRows(rows); | ||||
| Show All 18 Lines | _ondeleteresponse: function() { | ||||
| if (this._undoRow) { | if (this._undoRow) { | ||||
| JX.DOM.remove(this._undoRow); | JX.DOM.remove(this._undoRow); | ||||
| this._undoRow = null; | this._undoRow = null; | ||||
| } | } | ||||
| // If there's an existing editor, remove it. This happens when you | // If there's an existing editor, remove it. This happens when you | ||||
| // delete a comment from the comment preview area. In this case, we | // delete a comment from the comment preview area. In this case, we | ||||
| // read and preserve the text so "Undo" restores it. | // read and preserve the text so "Undo" restores it. | ||||
| var text; | var state = null; | ||||
| if (this._editRow) { | if (this._editRow) { | ||||
| text = this._readText(this._editRow); | state = this._readFormState(this._editRow); | ||||
| JX.DOM.remove(this._editRow); | JX.DOM.remove(this._editRow); | ||||
| this._editRow = null; | this._editRow = null; | ||||
| } | } | ||||
| this._drawUndeleteRows(text); | this._drawUndeleteRows(state); | ||||
| this.setLoading(false); | this.setLoading(false); | ||||
| this.setDeleted(true); | this.setDeleted(true); | ||||
| this._didUpdate(); | this._didUpdate(); | ||||
| }, | }, | ||||
| _drawUndeleteRows: function(text) { | _drawUndeleteRows: function(content_state) { | ||||
| this._undoType = 'undelete'; | this._undoType = 'undelete'; | ||||
| this._undoText = text || null; | this._undoState = content_state || null; | ||||
| return this._drawUndoRows('undelete', this._row); | return this._drawUndoRows('undelete', this._row); | ||||
| }, | }, | ||||
| _drawUneditRows: function(text) { | _drawUneditRows: function(content_state) { | ||||
| this._undoType = 'unedit'; | this._undoType = 'unedit'; | ||||
| this._undoText = text; | this._undoState = content_state; | ||||
| return this._drawUndoRows('unedit', null, text); | return this._drawUndoRows('unedit', null); | ||||
| }, | }, | ||||
| _drawUndoRows: function(mode, cursor, text) { | _drawUndoRows: function(mode, cursor) { | ||||
| 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); | ||||
| }, | }, | ||||
| _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); | ||||
| this._editRow = this._drawRows(rows, null, 'edit'); | this._editRow = this._drawRows(rows, null, 'edit'); | ||||
| }, | }, | ||||
| _drawRows: function(rows, cursor, type, text) { | _drawRows: function(rows, cursor, type) { | ||||
| var first_row = JX.DOM.scry(rows, 'tr')[0]; | var first_row = JX.DOM.scry(rows, 'tr')[0]; | ||||
| 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 result_row; | ||||
| var next_row; | var next_row; | ||||
| Show All 36 Lines | _drawRows: function(rows, cursor, type) { | ||||
| row = next_row; | row = next_row; | ||||
| } | } | ||||
| JX.Stratcom.invoke('resize'); | JX.Stratcom.invoke('resize'); | ||||
| return result_row; | return result_row; | ||||
| }, | }, | ||||
| save: function(form) { | save: function() { | ||||
| var handler = JX.bind(this, this._onsubmitresponse); | var handler = JX.bind(this, this._onsubmitresponse); | ||||
| this.setLoading(true); | this.setLoading(true); | ||||
| JX.Workflow.newFromForm(form) | var uri = this._getInlineURI(); | ||||
| .setHandler(handler) | var data = this._newRequestData('save', this._getContentState()); | ||||
| .start(); | |||||
| new JX.Request(uri, handler) | |||||
| .setData(data) | |||||
| .send(); | |||||
| }, | }, | ||||
| undo: function() { | undo: function() { | ||||
| JX.DOM.remove(this._undoRow); | JX.DOM.remove(this._undoRow); | ||||
| this._undoRow = null; | this._undoRow = null; | ||||
| if (this._undoType === '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 (this._undoText !== null) { | if (this._undoState !== null) { | ||||
| this.edit(this._undoText); | this.edit(this._undoState); | ||||
| } | } | ||||
| }, | }, | ||||
| _onundelete: function() { | _onundelete: function() { | ||||
| this.setLoading(false); | this.setLoading(false); | ||||
| this._didUpdate(); | this._didUpdate(); | ||||
| }, | }, | ||||
| cancel: function() { | cancel: function() { | ||||
| var text = this._readText(this._editRow); | var state = this._readFormState(this._editRow); | ||||
| JX.DOM.remove(this._editRow); | JX.DOM.remove(this._editRow); | ||||
| this._editRow = null; | this._editRow = null; | ||||
| if (text && text.length && (text != this._originalText)) { | var is_empty = this._isVoidContentState(state); | ||||
| this._drawUneditRows(text); | var is_same = this._isSameContentState(state, this._originalState); | ||||
| if (!is_empty && !is_same) { | |||||
| this._drawUneditRows(state); | |||||
| } | } | ||||
| // If this was an empty box and we typed some text and then hit cancel, | // If this was an empty box and we typed some text and then hit cancel, | ||||
| // don't show the empty concrete inline. | // don't show the empty concrete inline. | ||||
| if (!this._originalText) { | if (!this._isVoidContentState(this._originalState)) { | ||||
| this.setInvisible(true); | this.setInvisible(true); | ||||
| } else { | } else { | ||||
| this.setInvisible(false); | this.setInvisible(false); | ||||
| } | } | ||||
| // If you "undo" to restore text ("AB") and then "Cancel", we put you | // If you "undo" to restore text ("AB") and then "Cancel", we put you | ||||
| // back in the original text state ("A"). We also send the original | // back in the original text state ("A"). We also send the original | ||||
| // text ("A") to the server as the current persistent state. | // text ("A") to the server as the current persistent state. | ||||
| var uri = this._getInlineURI(); | var uri = this._getInlineURI(); | ||||
| var data = this._newRequestData('cancel', this._originalText); | var data = this._newRequestData('cancel', this._originalState); | ||||
| var handler = JX.bind(this, this._onCancelResponse); | var handler = JX.bind(this, this._onCancelResponse); | ||||
| this.setLoading(true); | this.setLoading(true); | ||||
| new JX.Request(uri, handler) | new JX.Request(uri, handler) | ||||
| .setData(data) | .setData(data) | ||||
| .send(); | .send(); | ||||
| this._didUpdate(true); | this._didUpdate(true); | ||||
| }, | }, | ||||
| _onCancelResponse: function(response) { | _onCancelResponse: function(response) { | ||||
| this.setEditing(false); | this.setEditing(false); | ||||
| this.setLoading(false); | this.setLoading(false); | ||||
| // If the comment was empty when we started editing it (there's no | // If the comment was empty when we started editing it (there's no | ||||
| // original text) and empty when we finished editing it (there's no | // original text) and empty when we finished editing it (there's no | ||||
| // undo row), just delete the comment. | // undo row), just delete the comment. | ||||
| if (!this._originalText && !this.isUndo()) { | if (this._isVoidContentState(this._originalState) && !this.isUndo()) { | ||||
| this.setDeleted(true); | this.setDeleted(true); | ||||
| JX.DOM.remove(this._row); | JX.DOM.remove(this._row); | ||||
| this._row = null; | this._row = null; | ||||
| this._didUpdate(); | this._didUpdate(); | ||||
| } | } | ||||
| }, | }, | ||||
| _readText: function(row) { | _readFormState: 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 { | ||||
| text: textarea.value | |||||
| }; | |||||
| }, | }, | ||||
| _onsubmitresponse: function(response) { | _onsubmitresponse: function(response) { | ||||
| if (this._editRow) { | if (this._editRow) { | ||||
| JX.DOM.remove(this._editRow); | JX.DOM.remove(this._editRow); | ||||
| this._editRow = null; | this._editRow = null; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | _getDraftState: function() { | ||||
| if (this.isDeleted()) { | if (this.isDeleted()) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| if (!this.isEditing()) { | if (!this.isEditing()) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| var text = this._readText(this._editRow); | var state = this._readFormState(this._editRow); | ||||
| if (text === null) { | if (this._isVoidContentState(state)) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return { | var draft_data = { | ||||
| op: 'draft', | op: 'draft', | ||||
| id: this.getID(), | id: this.getID(), | ||||
| text: text | |||||
| }; | }; | ||||
| JX.copy(draft_data, state); | |||||
| return draft_data; | |||||
| }, | }, | ||||
| triggerDraft: function() { | triggerDraft: function() { | ||||
| if (this._draftRequest) { | if (this._draftRequest) { | ||||
| this._draftRequest.trigger(); | this._draftRequest.trigger(); | ||||
| } | } | ||||
| }, | }, | ||||
| ▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | _hasMenuAction: function(action) { | ||||
| } | } | ||||
| return false; | return false; | ||||
| }, | }, | ||||
| _closeMenu: function() { | _closeMenu: function() { | ||||
| if (this._menu) { | if (this._menu) { | ||||
| this._menu.close(); | this._menu.close(); | ||||
| } | } | ||||
| }, | |||||
| _isVoidContentState: function(state) { | |||||
| return !state.text.length; | |||||
| }, | |||||
| _isSameContentState: function(u, v) { | |||||
| return (u.text === v.text); | |||||
| }, | |||||
| _newContentState: function() { | |||||
| return { | |||||
| text: '' | |||||
| }; | |||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||