diff options
author | Fatih Acet <acetfatih@gmail.com> | 2018-06-27 21:20:41 +0000 |
---|---|---|
committer | Tim Zallmann <tzallmann@gitlab.com> | 2018-06-27 21:20:41 +0000 |
commit | fbf747194f2a655aab3670c30cc6f054c29bbfe7 (patch) | |
tree | 57fb1be412df30689face16c86ff8abe0c89c20c /app/assets | |
parent | 5c13af58b89c6b6721ba018e519738b291f7f72b (diff) | |
download | gitlab-ce-fbf747194f2a655aab3670c30cc6f054c29bbfe7.tar.gz |
Componentize diff lines and diff comments
Diffstat (limited to 'app/assets')
10 files changed, 596 insertions, 340 deletions
diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue index 8999fd2ac96..a74ea4bfaaf 100644 --- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue +++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue @@ -4,14 +4,7 @@ import { s__ } from '~/locale'; import { mapState, mapGetters, mapActions } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; import DiffGutterAvatars from './diff_gutter_avatars.vue'; -import { - MATCH_LINE_TYPE, - CONTEXT_LINE_TYPE, - OLD_NO_NEW_LINE_TYPE, - NEW_NO_NEW_LINE_TYPE, - LINE_POSITION_RIGHT, - UNFOLD_COUNT, -} from '../constants'; +import { LINE_POSITION_RIGHT, UNFOLD_COUNT } from '../constants'; import * as utils from '../store/utils'; export default { @@ -63,6 +56,21 @@ export default { required: false, default: false, }, + isMatchLine: { + type: Boolean, + required: false, + default: false, + }, + isMetaLine: { + type: Boolean, + required: false, + default: false, + }, + isContextLine: { + type: Boolean, + required: false, + default: false, + }, }, computed: { ...mapState({ @@ -70,15 +78,6 @@ export default { diffFiles: state => state.diffs.diffFiles, }), ...mapGetters(['isLoggedIn', 'discussionsByLineCode']), - isMatchLine() { - return this.lineType === MATCH_LINE_TYPE; - }, - isContextLine() { - return this.lineType === CONTEXT_LINE_TYPE; - }, - isMetaLine() { - return this.lineType === OLD_NO_NEW_LINE_TYPE || this.lineType === NEW_NO_NEW_LINE_TYPE; - }, lineHref() { return this.lineCode ? `#${this.lineCode}` : '#'; }, @@ -109,9 +108,9 @@ export default { }, }, methods: { - ...mapActions(['loadMoreLines']), + ...mapActions(['loadMoreLines', 'showCommentForm']), handleCommentButton() { - this.$emit('showCommentForm', { lineCode: this.lineCode }); + this.showCommentForm({ lineCode: this.lineCode }); }, handleLoadMoreLines() { if (this.isRequesting) { diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue new file mode 100644 index 00000000000..68fe6787f9b --- /dev/null +++ b/app/assets/javascripts/diffs/components/diff_table_cell.vue @@ -0,0 +1,131 @@ +<script> +import { mapGetters } from 'vuex'; +import DiffLineGutterContent from './diff_line_gutter_content.vue'; +import { + MATCH_LINE_TYPE, + CONTEXT_LINE_TYPE, + EMPTY_CELL_TYPE, + OLD_LINE_TYPE, + OLD_NO_NEW_LINE_TYPE, + NEW_NO_NEW_LINE_TYPE, + LINE_HOVER_CLASS_NAME, + LINE_UNFOLD_CLASS_NAME, +} from '../constants'; + +export default { + components: { + DiffLineGutterContent, + }, + props: { + line: { + type: Object, + required: true, + }, + diffFile: { + type: Object, + required: true, + }, + showCommentButton: { + type: Boolean, + required: false, + default: false, + }, + linePosition: { + type: String, + required: false, + default: '', + }, + lineType: { + type: String, + required: false, + default: '', + }, + isContentLine: { + type: Boolean, + required: false, + default: false, + }, + isBottom: { + type: Boolean, + required: false, + default: false, + }, + isHover: { + type: Boolean, + required: false, + default: false, + }, + }, + computed: { + ...mapGetters(['isLoggedIn', 'isInlineView']), + normalizedLine() { + if (this.isInlineView) { + return this.line; + } + + return this.lineType === OLD_LINE_TYPE ? this.line.left : this.line.right; + }, + isMatchLine() { + return this.normalizedLine.type === MATCH_LINE_TYPE; + }, + isContextLine() { + return this.normalizedLine.type === CONTEXT_LINE_TYPE; + }, + isMetaLine() { + return ( + this.normalizedLine.type === OLD_NO_NEW_LINE_TYPE || + this.normalizedLine.type === NEW_NO_NEW_LINE_TYPE || + this.normalizedLine.type === EMPTY_CELL_TYPE + ); + }, + classNameMap() { + const { type } = this.normalizedLine; + + return { + [type]: type, + [LINE_UNFOLD_CLASS_NAME]: this.isMatchLine, + [LINE_HOVER_CLASS_NAME]: + this.isLoggedIn && + this.isHover && + !this.isMatchLine && + !this.isContextLine && + !this.isMetaLine, + }; + }, + lineNumber() { + const { lineType, normalizedLine } = this; + + return lineType === OLD_LINE_TYPE ? normalizedLine.oldLine : normalizedLine.newLine; + }, + }, +}; +</script> + +<template> + <td + v-if="isContentLine" + :class="lineType" + class="line_content" + v-html="normalizedLine.richText" + > + </td> + <td + v-else + :class="classNameMap" + > + <diff-line-gutter-content + :file-hash="diffFile.fileHash" + :line-type="normalizedLine.type" + :line-code="normalizedLine.lineCode" + :line-position="linePosition" + :line-number="lineNumber" + :meta-data="normalizedLine.metaData" + :show-comment-button="showCommentButton" + :context-lines-path="diffFile.contextLinesPath" + :is-bottom="isBottom" + :is-match-line="isMatchLine" + :is-context-line="isContentLine" + :is-meta-line="isMetaLine" + /> + </td> +</template> diff --git a/app/assets/javascripts/diffs/components/diff_table_row.vue b/app/assets/javascripts/diffs/components/diff_table_row.vue new file mode 100644 index 00000000000..8716fdaf44d --- /dev/null +++ b/app/assets/javascripts/diffs/components/diff_table_row.vue @@ -0,0 +1,191 @@ +<script> +import $ from 'jquery'; +import { mapGetters } from 'vuex'; +import DiffTableCell from './diff_table_cell.vue'; +import { + NEW_LINE_TYPE, + OLD_LINE_TYPE, + CONTEXT_LINE_TYPE, + CONTEXT_LINE_CLASS_NAME, + OLD_NO_NEW_LINE_TYPE, + PARALLEL_DIFF_VIEW_TYPE, + NEW_NO_NEW_LINE_TYPE, + LINE_POSITION_LEFT, + LINE_POSITION_RIGHT, +} from '../constants'; + +export default { + components: { + DiffTableCell, + }, + props: { + diffFile: { + type: Object, + required: true, + }, + line: { + type: Object, + required: true, + }, + isBottom: { + type: Boolean, + required: false, + default: false, + }, + }, + data() { + return { + isHover: false, + isLeftHover: false, + isRightHover: false, + }; + }, + computed: { + ...mapGetters(['isInlineView', 'isParallelView']), + isContextLine() { + return this.line.left + ? this.line.left.type === CONTEXT_LINE_TYPE + : this.line.type === CONTEXT_LINE_TYPE; + }, + classNameMap() { + return { + [this.line.type]: this.line.type, + [CONTEXT_LINE_CLASS_NAME]: this.isContextLine, + [PARALLEL_DIFF_VIEW_TYPE]: this.isParallelView, + }; + }, + inlineRowId() { + const { lineCode, oldLine, newLine } = this.line; + + return lineCode || `${this.diffFile.fileHash}_${oldLine}_${newLine}`; + }, + parallelViewLeftLineType() { + if (this.line.right.type === NEW_NO_NEW_LINE_TYPE) { + return OLD_NO_NEW_LINE_TYPE; + } + + return this.line.left.type; + }, + }, + created() { + this.newLineType = NEW_LINE_TYPE; + this.oldLineType = OLD_LINE_TYPE; + this.linePositionLeft = LINE_POSITION_LEFT; + this.linePositionRight = LINE_POSITION_RIGHT; + }, + methods: { + handleMouseMove(e) { + const isHover = e.type === 'mouseover'; + + if (this.isInlineView) { + this.isHover = isHover; + } else { + const hoveringCell = e.target.closest('td'); + const allCellsInHoveringRow = Array.from(e.currentTarget.children); + const hoverIndex = allCellsInHoveringRow.indexOf(hoveringCell); + + if (hoverIndex >= 2) { + this.isRightHover = isHover; + } else { + this.isLeftHover = isHover; + } + } + }, + // Prevent text selecting on both sides of parallel diff view + // Backport of the same code from legacy diff notes. + handleParallelLineMouseDown(e) { + const line = $(e.currentTarget); + const table = line.closest('table'); + + table.removeClass('left-side-selected right-side-selected'); + const [lineClass] = ['left-side', 'right-side'].filter(name => line.hasClass(name)); + + if (lineClass) { + table.addClass(`${lineClass}-selected`); + } + }, + }, +}; +</script> + +<template> + <tr + v-if="isInlineView" + :id="inlineRowId" + :class="classNameMap" + class="line_holder" + @mouseover="handleMouseMove" + @mouseout="handleMouseMove" + > + <diff-table-cell + :diff-file="diffFile" + :line="line" + :line-type="oldLineType" + :is-bottom="isBottom" + :is-hover="isHover" + :show-comment-button="true" + class="diff-line-num old_line" + /> + <diff-table-cell + :diff-file="diffFile" + :line="line" + :line-type="newLineType" + :is-bottom="isBottom" + :is-hover="isHover" + class="diff-line-num new_line" + /> + <diff-table-cell + :class="line.type" + :diff-file="diffFile" + :line="line" + :is-content-line="true" + /> + </tr> + + <tr + v-else + :class="classNameMap" + class="line_holder" + @mouseover="handleMouseMove" + @mouseout="handleMouseMove" + > + <diff-table-cell + :diff-file="diffFile" + :line="line" + :line-type="oldLineType" + :line-position="linePositionLeft" + :is-bottom="isBottom" + :is-hover="isLeftHover" + :show-comment-button="true" + class="diff-line-num old_line" + /> + <diff-table-cell + :id="line.left.lineCode" + :diff-file="diffFile" + :line="line" + :is-content-line="true" + :line-type="parallelViewLeftLineType" + class="line_content parallel left-side" + @mousedown.native="handleParallelLineMouseDown" + /> + <diff-table-cell + :diff-file="diffFile" + :line="line" + :line-type="newLineType" + :line-position="linePositionRight" + :is-bottom="isBottom" + :is-hover="isRightHover" + :show-comment-button="true" + class="diff-line-num new_line" + /> + <diff-table-cell + :id="line.right.lineCode" + :diff-file="diffFile" + :line="line" + :is-content-line="true" + :line-type="line.right.type" + class="line_content parallel right-side" + @mousedown.native="handleParallelLineMouseDown" + /> + </tr> +</template> diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue new file mode 100644 index 00000000000..0e935f1d68e --- /dev/null +++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue @@ -0,0 +1,82 @@ +<script> +import { mapState, mapGetters } from 'vuex'; +import diffDiscussions from './diff_discussions.vue'; +import diffLineNoteForm from './diff_line_note_form.vue'; + +export default { + components: { + diffDiscussions, + diffLineNoteForm, + }, + props: { + line: { + type: Object, + required: true, + }, + diffFile: { + type: Object, + required: true, + }, + diffLines: { + type: Array, + required: true, + }, + lineIndex: { + type: Number, + required: true, + }, + }, + computed: { + ...mapState({ + diffLineCommentForms: state => state.diffs.diffLineCommentForms, + }), + ...mapGetters(['discussionsByLineCode']), + isDiscussionExpanded() { + if (!this.discussions.length) { + return false; + } + + return this.discussions.every(discussion => discussion.expanded); + }, + hasCommentForm() { + return this.diffLineCommentForms[this.line.lineCode]; + }, + discussions() { + return this.discussionsByLineCode[this.line.lineCode] || []; + }, + shouldRender() { + return this.isDiscussionExpanded || this.hasCommentForm; + }, + className() { + return this.discussions.length ? '' : 'js-temp-notes-holder'; + }, + }, +}; +</script> + +<template> + <tr + v-if="shouldRender" + :class="className" + class="notes_holder" + > + <td + class="notes_line" + colspan="2" + ></td> + <td class="notes_content"> + <div class="content"> + <diff-discussions + :discussions="discussions" + /> + <diff-line-note-form + v-if="diffLineCommentForms[line.lineCode]" + :diff-file="diffFile" + :diff-lines="diffLines" + :line="line" + :note-target-line="diffLines[lineIndex]" + /> + </div> + </td> + </tr> +</template> diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue index 21376117bef..e72f85df77a 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_view.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue @@ -1,34 +1,12 @@ <script> import diffContentMixin from '../mixins/diff_content'; -import { - MATCH_LINE_TYPE, - CONTEXT_LINE_TYPE, - OLD_NO_NEW_LINE_TYPE, - NEW_NO_NEW_LINE_TYPE, - LINE_HOVER_CLASS_NAME, - LINE_UNFOLD_CLASS_NAME, -} from '../constants'; +import inlineDiffCommentRow from './inline_diff_comment_row.vue'; export default { - mixins: [diffContentMixin], - methods: { - handleMouse(lineCode, isOver) { - this.hoveredLineCode = isOver ? lineCode : null; - }, - getLineClass(line) { - const isSameLine = this.hoveredLineCode && this.hoveredLineCode === line.lineCode; - const isMatchLine = line.type === MATCH_LINE_TYPE; - const isContextLine = line.type === CONTEXT_LINE_TYPE; - const isMetaLine = line.type === OLD_NO_NEW_LINE_TYPE || line.type === NEW_NO_NEW_LINE_TYPE; - - return { - [line.type]: line.type, - [LINE_UNFOLD_CLASS_NAME]: isMatchLine, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && isSameLine && !isMatchLine && !isContextLine && !isMetaLine, - }; - }, + components: { + inlineDiffCommentRow, }, + mixins: [diffContentMixin], }; </script> @@ -41,76 +19,19 @@ export default { <template v-for="(line, index) in normalizedDiffLines" > - <tr - :id="line.lineCode || `${fileHash}_${line.oldLine}_${line.newLine}`" + <diff-table-row + :diff-file="diffFile" + :line="line" + :is-bottom="index + 1 === diffLinesLength" :key="line.lineCode" - :class="getRowClass(line)" - class="line_holder" - @mouseover="handleMouse(line.lineCode, true)" - @mouseout="handleMouse(line.lineCode, false)" - > - <td - :class="getLineClass(line)" - class="diff-line-num old_line" - > - <diff-line-gutter-content - :file-hash="fileHash" - :line-type="line.type" - :line-code="line.lineCode" - :line-number="line.oldLine" - :meta-data="line.metaData" - :show-comment-button="true" - :context-lines-path="diffFile.contextLinesPath" - :is-bottom="index + 1 === diffLinesLength" - @showCommentForm="handleShowCommentForm" - /> - </td> - <td - :class="getLineClass(line)" - class="diff-line-num new_line" - > - <diff-line-gutter-content - :file-hash="fileHash" - :line-type="line.type" - :line-code="line.lineCode" - :line-number="line.newLine" - :meta-data="line.metaData" - :is-bottom="index + 1 === diffLinesLength" - :context-lines-path="diffFile.contextLinesPath" - /> - </td> - <td - :class="line.type" - class="line_content" - v-html="line.richText" - > - </td> - </tr> - <tr - v-if="isDiscussionExpanded(line.lineCode) || diffLineCommentForms[line.lineCode]" + /> + <inline-diff-comment-row + :diff-file="diffFile" + :diff-lines="normalizedDiffLines" + :line="line" + :line-index="index" :key="index" - :class="discussionsByLineCode[line.lineCode] ? '' : 'js-temp-notes-holder'" - class="notes_holder" - > - <td - class="notes_line" - colspan="2" - ></td> - <td class="notes_content"> - <div class="content"> - <diff-discussions - :discussions="discussionsByLineCode[line.lineCode] || []" - /> - <diff-line-note-form - v-if="diffLineCommentForms[line.lineCode]" - :diff-file="diffFile" - :diff-lines="diffLines" - :line="line" - :note-target-line="diffLines[index]" - /> - </div> - </td> - </tr> + /> </template> </tbody> </table> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue new file mode 100644 index 00000000000..5f33ec7a3c2 --- /dev/null +++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue @@ -0,0 +1,129 @@ +<script> +import { mapState, mapGetters } from 'vuex'; +import diffDiscussions from './diff_discussions.vue'; +import diffLineNoteForm from './diff_line_note_form.vue'; + +export default { + components: { + diffDiscussions, + diffLineNoteForm, + }, + props: { + line: { + type: Object, + required: true, + }, + diffFile: { + type: Object, + required: true, + }, + diffLines: { + type: Array, + required: true, + }, + lineIndex: { + type: Number, + required: true, + }, + }, + computed: { + ...mapState({ + diffLineCommentForms: state => state.diffs.diffLineCommentForms, + }), + ...mapGetters(['discussionsByLineCode']), + leftLineCode() { + return this.line.left.lineCode; + }, + rightLineCode() { + return this.line.right.lineCode; + }, + hasDiscussion() { + const discussions = this.discussionsByLineCode; + + return discussions[this.leftLineCode] || discussions[this.rightLineCode]; + }, + hasExpandedDiscussionOnLeft() { + const discussions = this.discussionsByLineCode[this.leftLineCode]; + + return discussions ? discussions.every(discussion => discussion.expanded) : false; + }, + hasExpandedDiscussionOnRight() { + const discussions = this.discussionsByLineCode[this.rightLineCode]; + + return discussions ? discussions.every(discussion => discussion.expanded) : false; + }, + hasAnyExpandedDiscussion() { + return this.hasExpandedDiscussionOnLeft || this.hasExpandedDiscussionOnRight; + }, + shouldRenderDiscussionsRow() { + const hasDiscussion = this.hasDiscussion && this.hasAnyExpandedDiscussion; + const hasCommentFormOnLeft = this.diffLineCommentForms[this.leftLineCode]; + const hasCommentFormOnRight = this.diffLineCommentForms[this.rightLineCode]; + + return hasDiscussion || hasCommentFormOnLeft || hasCommentFormOnRight; + }, + shouldRenderDiscussionsOnLeft() { + return this.discussionsByLineCode[this.leftLineCode] && this.hasExpandedDiscussionOnLeft; + }, + shouldRenderDiscussionsOnRight() { + return ( + this.discussionsByLineCode[this.rightLineCode] && + this.hasExpandedDiscussionOnRight && + this.line.right.type + ); + }, + className() { + return this.hasDiscussion ? '' : 'js-temp-notes-holder'; + }, + }, +}; +</script> + +<template> + <tr + v-if="shouldRenderDiscussionsRow" + :class="className" + class="notes_holder" + > + <td class="notes_line old"></td> + <td class="notes_content parallel old"> + <div + v-if="shouldRenderDiscussionsOnLeft" + class="content" + > + <diff-discussions + :discussions="discussionsByLineCode[leftLineCode]" + /> + </div> + <diff-line-note-form + v-if="diffLineCommentForms[leftLineCode] && + diffLineCommentForms[leftLineCode]" + :diff-file="diffFile" + :diff-lines="diffLines" + :line="line.left" + :note-target-line="diffLines[lineIndex].left" + position="left" + /> + </td> + <td class="notes_line new"></td> + <td class="notes_content parallel new"> + <div + v-if="shouldRenderDiscussionsOnRight" + class="content" + > + <diff-discussions + :discussions="discussionsByLineCode[rightLineCode]" + /> + </div> + <diff-line-note-form + v-if="diffLineCommentForms[rightLineCode] && + diffLineCommentForms[rightLineCode] && line.right.type" + :diff-file="diffFile" + :diff-lines="diffLines" + :line="line.right" + :note-target-line="diffLines[lineIndex].right" + position="right" + /> + </td> + </tr> +</template> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue index 60edbcbbda8..ed92b4ee249 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue @@ -1,17 +1,12 @@ <script> import diffContentMixin from '../mixins/diff_content'; -import { - EMPTY_CELL_TYPE, - MATCH_LINE_TYPE, - CONTEXT_LINE_TYPE, - OLD_NO_NEW_LINE_TYPE, - NEW_NO_NEW_LINE_TYPE, - LINE_HOVER_CLASS_NAME, - LINE_UNFOLD_CLASS_NAME, - LINE_POSITION_RIGHT, -} from '../constants'; +import parallelDiffCommentRow from './parallel_diff_comment_row.vue'; +import { EMPTY_CELL_TYPE } from '../constants'; export default { + components: { + parallelDiffCommentRow, + }, mixins: [diffContentMixin], computed: { parallelDiffLines() { @@ -26,77 +21,6 @@ export default { }); }, }, - methods: { - hasDiscussion(line) { - const discussions = this.discussionsByLineCode; - const hasDiscussion = discussions[line.left.lineCode] || discussions[line.right.lineCode]; - - return hasDiscussion; - }, - getClassName(line, position) { - const { type, lineCode } = line[position]; - const isMatchLine = type === MATCH_LINE_TYPE; - const isContextLine = !isMatchLine && type !== EMPTY_CELL_TYPE && type !== CONTEXT_LINE_TYPE; - const isMetaLine = type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE; - const isSameLine = this.hoveredLineCode && this.hoveredLineCode === lineCode; - const isSameSection = position === this.hoveredSection; - - return { - [type]: type, - [LINE_UNFOLD_CLASS_NAME]: isMatchLine, - [LINE_HOVER_CLASS_NAME]: - this.isLoggedIn && isContextLine && isSameLine && isSameSection && !isMetaLine, - }; - }, - handleMouse(e, line, isHover) { - if (isHover) { - const cell = e.target.closest('td'); - - if (this.$refs.leftLines.indexOf(cell) > -1) { - this.hoveredLineCode = line.left.lineCode; - this.hoveredSection = 'left'; - } else if (this.$refs.rightLines.indexOf(cell) > -1) { - this.hoveredLineCode = line.right.lineCode; - this.hoveredSection = 'right'; - } - } else { - this.hoveredLineCode = null; - this.hoveredSection = null; - } - }, - shouldRenderDiscussionsRow(line) { - const hasDiscussion = this.hasDiscussion(line) && this.hasAnyExpandedDiscussion(line); - const hasCommentFormOnLeft = this.diffLineCommentForms[line.left.lineCode]; - const hasCommentFormOnRight = this.diffLineCommentForms[line.right.lineCode]; - - return hasDiscussion || hasCommentFormOnLeft || hasCommentFormOnRight; - }, - shouldRenderDiscussions(line, position) { - const { lineCode } = line[position]; - let render = this.discussionsByLineCode[lineCode] && this.isDiscussionExpanded(lineCode); - - // Avoid rendering context line discussions on the right side in parallel view - if (position === LINE_POSITION_RIGHT) { - render = render && line.right.type; - } - - return render; - }, - hasAnyExpandedDiscussion(line) { - const isLeftExpanded = this.isDiscussionExpanded(line.left.lineCode); - const isRightExpanded = this.isDiscussionExpanded(line.right.lineCode); - - return isLeftExpanded || isRightExpanded; - }, - getLineCode(line, side) { - const { lineCode } = side; - if (lineCode) { - return lineCode; - } - - return `${this.fileHash}_${line.left.oldLine}_${line.right.newLine}`; - }, - }, }; </script> @@ -104,119 +28,26 @@ export default { <div :class="userColorScheme" :data-commit-id="commitId" - class="code diff-wrap-lines js-syntax-highlight text-file"> + class="code diff-wrap-lines js-syntax-highlight text-file" + > <table> <tbody> <template v-for="(line, index) in parallelDiffLines" > - <tr + <diff-table-row + :diff-file="diffFile" + :line="line" + :is-bottom="index + 1 === diffLinesLength" :key="index" - :class="getRowClass(line)" - class="line_holder parallel" - @mouseover="handleMouse($event, line, true)" - @mouseout="handleMouse($event, line, false)" - > - <td - ref="leftLines" - :class="getClassName(line, 'left')" - class="diff-line-num old_line" - > - <diff-line-gutter-content - :file-hash="fileHash" - :line-type="line.left.type" - :line-code="line.left.lineCode" - :line-number="line.left.oldLine" - :meta-data="line.left.metaData" - :show-comment-button="true" - :context-lines-path="diffFile.contextLinesPath" - :is-bottom="index + 1 === diffLinesLength" - line-position="left" - @showCommentForm="handleShowCommentForm" - /> - </td> - <td - ref="leftLines" - :class="getClassName(line, 'left')" - :id="getLineCode(line, line.left)" - class="line_content parallel left-side" - v-html="line.left.richText" - > - </td> - <td - ref="rightLines" - :class="getClassName(line, 'right')" - class="diff-line-num new_line" - > - <diff-line-gutter-content - :file-hash="fileHash" - :line-type="line.right.type" - :line-code="line.right.lineCode" - :line-number="line.right.newLine" - :meta-data="line.right.metaData" - :show-comment-button="true" - :context-lines-path="diffFile.contextLinesPath" - :is-bottom="index + 1 === diffLinesLength" - line-position="right" - @showCommentForm="handleShowCommentForm" - /> - </td> - <td - ref="rightLines" - :class="getClassName(line, 'right')" - :id="getLineCode(line, line.right)" - class="line_content parallel right-side" - v-html="line.right.richText" - > - </td> - </tr> - <tr - v-if="shouldRenderDiscussionsRow(line)" + /> + <parallel-diff-comment-row :key="line.left.lineCode || line.right.lineCode" - :class="hasDiscussion(line) ? '' : 'js-temp-notes-holder'" - class="notes_holder" - > - <td class="notes_line old"></td> - <td class="notes_content parallel old"> - <div - v-if="shouldRenderDiscussions(line, 'left')" - class="content" - > - <diff-discussions - :discussions="discussionsByLineCode[line.left.lineCode]" - /> - </div> - <diff-line-note-form - v-if="diffLineCommentForms[line.left.lineCode] && - diffLineCommentForms[line.left.lineCode]" - :diff-file="diffFile" - :diff-lines="diffLines" - :line="line.left" - :note-target-line="diffLines[index].left" - position="left" - /> - </td> - <td class="notes_line new"></td> - <td class="notes_content parallel new"> - <div - v-if="shouldRenderDiscussions(line, 'right')" - class="content" - > - <diff-discussions - :discussions="discussionsByLineCode[line.right.lineCode]" - /> - </div> - <diff-line-note-form - v-if="diffLineCommentForms[line.right.lineCode] && - diffLineCommentForms[line.right.lineCode] && line.right.type" - :diff-file="diffFile" - :diff-lines="diffLines" - :line="line.right" - :note-target-line="diffLines[index].right" - position="right" - /> - </td> - </tr> + :line="line" + :diff-file="diffFile" + :diff-lines="parallelDiffLines" + :line-index="index" + /> </template> </tbody> </table> diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js index d314f08e60e..2fa8367f528 100644 --- a/app/assets/javascripts/diffs/constants.js +++ b/app/assets/javascripts/diffs/constants.js @@ -14,6 +14,8 @@ export const TEXT_DIFF_POSITION_TYPE = 'text'; export const LINE_POSITION_LEFT = 'left'; export const LINE_POSITION_RIGHT = 'right'; +export const LINE_SIDE_LEFT = 'left-side'; +export const LINE_SIDE_RIGHT = 'right-side'; export const DIFF_VIEW_COOKIE_NAME = 'diff_view'; export const LINE_HOVER_CLASS_NAME = 'is-over'; diff --git a/app/assets/javascripts/diffs/mixins/diff_content.js b/app/assets/javascripts/diffs/mixins/diff_content.js index bef06ad2b52..ebb511d3a7e 100644 --- a/app/assets/javascripts/diffs/mixins/diff_content.js +++ b/app/assets/javascripts/diffs/mixins/diff_content.js @@ -1,9 +1,9 @@ -import { mapState, mapGetters, mapActions } from 'vuex'; +import { mapGetters } from 'vuex'; import diffDiscussions from '../components/diff_discussions.vue'; import diffLineGutterContent from '../components/diff_line_gutter_content.vue'; import diffLineNoteForm from '../components/diff_line_note_form.vue'; +import diffTableRow from '../components/diff_table_row.vue'; import { trimFirstCharOfLineContent } from '../store/utils'; -import { CONTEXT_LINE_TYPE, CONTEXT_LINE_CLASS_NAME } from '../constants'; export default { props: { @@ -16,22 +16,14 @@ export default { required: true, }, }, - data() { - return { - hoveredLineCode: null, - hoveredSection: null, - }; - }, components: { diffDiscussions, + diffTableRow, diffLineNoteForm, diffLineGutterContent, }, computed: { - ...mapState({ - diffLineCommentForms: state => state.diffs.diffLineCommentForms, - }), - ...mapGetters(['discussionsByLineCode', 'isLoggedIn', 'commit']), + ...mapGetters(['commit']), commitId() { return this.commit && this.commit.id; }, @@ -41,15 +33,15 @@ export default { normalizedDiffLines() { return this.diffLines.map(line => { if (line.richText) { - return this.trimFirstChar(line); + return trimFirstCharOfLineContent(line); } if (line.left) { - Object.assign(line, { left: this.trimFirstChar(line.left) }); + Object.assign(line, { left: trimFirstCharOfLineContent(line.left) }); } if (line.right) { - Object.assign(line, { right: this.trimFirstChar(line.right) }); + Object.assign(line, { right: trimFirstCharOfLineContent(line.right) }); } return line; @@ -62,28 +54,4 @@ export default { return this.diffFile.fileHash; }, }, - methods: { - ...mapActions(['showCommentForm', 'cancelCommentForm']), - getRowClass(line) { - const isContextLine = line.left - ? line.left.type === CONTEXT_LINE_TYPE - : line.type === CONTEXT_LINE_TYPE; - - return { - [line.type]: line.type, - [CONTEXT_LINE_CLASS_NAME]: isContextLine, - }; - }, - trimFirstChar(line) { - return trimFirstCharOfLineContent(line); - }, - handleShowCommentForm(params) { - this.showCommentForm({ lineCode: params.lineCode }); - }, - isDiscussionExpanded(lineCode) { - const discussions = this.discussionsByLineCode[lineCode]; - - return discussions ? discussions.every(discussion => discussion.expanded) : false; - }, - }, }; diff --git a/app/assets/stylesheets/highlight/white_base.scss b/app/assets/stylesheets/highlight/white_base.scss index 8cc5252648d..90a5250c247 100644 --- a/app/assets/stylesheets/highlight/white_base.scss +++ b/app/assets/stylesheets/highlight/white_base.scss @@ -102,7 +102,9 @@ pre.code, // Diff line .line_holder { - &.match .line_content { + &.match .line_content, + .new-nonewline.line_content, + .old-nonewline.line_content { @include matchLine; } |