IssueNotesRefactor: Implement jumping to target note.

This commit is contained in:
Fatih Acet 2017-07-07 02:13:10 +03:00
parent b72db79668
commit 993936fbd0
6 changed files with 60 additions and 4 deletions

View File

@ -162,10 +162,11 @@
gl.utils.scrollToElement = function($el) {
var top = $el.offset().top;
gl.mrTabsHeight = gl.mrTabsHeight || $('.merge-request-tabs').height();
var mrTabsHeight = $('.merge-request-tabs').height() || 0;
var headerHeight = $('.navbar-gitlab').height() || 0;
return $('body, html').animate({
scrollTop: top - (gl.mrTabsHeight)
scrollTop: top - mrTabsHeight - headerHeight
}, 200);
};

View File

@ -1,6 +1,7 @@
<script>
/* global Flash */
import { mapGetters } from 'vuex';
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import IssueNoteHeader from './issue_note_header.vue';
import IssueNoteActions from './issue_note_actions.vue';
@ -26,6 +27,9 @@ export default {
IssueNoteBody,
},
computed: {
...mapGetters([
'targetNoteHash',
]),
author() {
return this.note.author;
},
@ -33,11 +37,15 @@ export default {
return {
'is-editing': this.isEditing,
'disabled-content': this.isDeleting,
target: this.targetNoteHash === this.noteAnchorId,
};
},
canReportAsAbuse() {
return this.note.report_abuse_path && this.author.id !== window.gon.current_user_id;
},
noteAnchorId() {
return `note_${this.note.id}`;
},
},
methods: {
editHandler() {
@ -98,6 +106,7 @@ export default {
<template>
<li
class="note timeline-entry"
:id="noteAnchorId"
:class="classNameBindings">
<div class="timeline-entry-inner">
<div class="timeline-icon">
@ -115,6 +124,7 @@ export default {
:noteId="note.id"
actionText="commented" />
<issue-note-actions
:authorId="author.id"
:accessLevel="note.human_access"
:canAward="note.emoji_awardable"
:canEdit="note.current_user.can_edit"

View File

@ -56,6 +56,9 @@ export default {
this.isExpanded = !this.isExpanded;
this.toggleHandler();
},
updateTargetNoteHash() {
this.$store.commit('setTargetNoteHash', this.noteTimestampLink);
},
},
};
</script>
@ -79,7 +82,9 @@ export default {
v-if="actionTextHtml"
v-html="actionTextHtml"
class="system-note-message"></span>
<a :href="noteTimestampLink">
<a
:href="noteTimestampLink"
@click="updateTargetNoteHash">
<time-ago-tooltip
:time="createdAt"
tooltipPlacement="bottom" />

View File

@ -43,6 +43,19 @@ export default {
componentData(note) {
return note.individual_note ? note.notes[0] : note;
},
checkLocationHash() {
const hash = gl.utils.getLocationHash();
const $el = $(`#${hash}`);
if (hash && $el) {
const isInViewport = gl.utils.isInViewport($el[0]);
this.$store.commit('setTargetNoteHash', hash);
if (!isInViewport) {
gl.utils.scrollToElement($el);
}
}
},
},
mounted() {
const { discussionsPath, notesPath, lastFetchedAt } = this.$el.parentNode.dataset;
@ -50,6 +63,11 @@ export default {
this.$store.dispatch('fetchNotes', discussionsPath)
.then(() => {
this.isLoading = false;
// Scroll to note if we have hash fragment in the page URL
Vue.nextTick(() => {
this.checkLocationHash();
});
})
.catch(() => {
new Flash('Something went wrong while fetching issue comments. Please try again.'); // eslint-disable-line

View File

@ -1,4 +1,5 @@
<script>
import { mapGetters } from 'vuex';
import iconsMap from './issue_note_icons';
import IssueNoteHeader from './issue_note_header.vue';
@ -17,11 +18,25 @@ export default {
components: {
IssueNoteHeader,
},
computed: {
...mapGetters([
'targetNoteHash',
]),
noteAnchorId() {
return `note_${this.note.id}`;
},
isTargetNote() {
return this.targetNoteHash === this.noteAnchorId;
},
},
};
</script>
<template>
<li class="note system-note timeline-entry">
<li
:id="noteAnchorId"
:class="{ target: isTargetNote }"
class="note system-note timeline-entry">
<div class="timeline-entry-inner">
<div class="timeline-icon">
<span v-html="svg"></span>

View File

@ -6,18 +6,25 @@ const findNoteObjectById = (notes, id) => notes.filter(n => n.id === id)[0];
const state = {
notes: [],
targetNoteHash: null,
};
const getters = {
notes(storeState) {
return storeState.notes;
},
targetNoteHash(storeState) {
return storeState.targetNoteHash;
},
};
const mutations = {
setInitialNotes(storeState, notes) {
storeState.notes = notes;
},
setTargetNoteHash(storeState, hash) {
storeState.targetNoteHash = hash;
},
toggleDiscussion(storeState, { discussionId }) {
const discussion = findNoteObjectById(storeState.notes, discussionId);