Fix note highlight being lost after real time update

Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/33483
This commit is contained in:
Eric Eastwood 2017-06-12 13:18:41 -05:00
parent 64e85fdaff
commit 82181f6c0a
2 changed files with 70 additions and 3 deletions

View file

@ -56,6 +56,7 @@ const normalizeNewlines = function(str) {
this.toggleCommitList = this.toggleCommitList.bind(this);
this.postComment = this.postComment.bind(this);
this.clearFlashWrapper = this.clearFlash.bind(this);
this.onHashChange = this.onHashChange.bind(this);
this.notes_url = notes_url;
this.note_ids = note_ids;
@ -127,7 +128,9 @@ const normalizeNewlines = function(str) {
$(document).on('ajax:success', '.js-main-target-form', this.resetMainTargetForm);
$(document).on('ajax:complete', '.js-main-target-form', this.reenableTargetFormSubmitButton);
// when a key is clicked on the notes
return $(document).on('keydown', '.js-note-text', this.keydownNoteText);
$(document).on('keydown', '.js-note-text', this.keydownNoteText);
// When the URL fragment/hash has changed, `#note_xxx`
return $(window).on('hashchange', this.onHashChange);
};
Notes.prototype.cleanBinding = function() {
@ -148,6 +151,7 @@ const normalizeNewlines = function(str) {
$(document).off('ajax:success', '.js-main-target-form');
$(document).off('ajax:success', '.js-discussion-note-form');
$(document).off('ajax:complete', '.js-main-target-form');
$(window).off('hashchange', this.onHashChange);
};
Notes.initCommentTypeToggle = function (form) {
@ -298,8 +302,27 @@ const normalizeNewlines = function(str) {
Notes.prototype.setupNewNote = function($note) {
// Update datetime format on the recent note
gl.utils.localTimeAgo($note.find('.js-timeago'), false);
this.collapseLongCommitList();
this.taskList.init();
// This stops the note highlight, #note_xxx`, from being removed after real time update
// The `:target` selector does not re-evaluate after we replace element in the DOM
Notes.updateNoteTargetSelector($note);
this.$noteToCleanHighlight = $note;
};
Notes.prototype.onHashChange = function() {
if (this.$noteToCleanHighlight) {
Notes.updateNoteTargetSelector(this.$noteToCleanHighlight);
}
this.$noteToCleanHighlight = null;
};
Notes.updateNoteTargetSelector = function($note) {
const hash = gl.utils.getLocationHash();
$note.toggleClass('target', hash && $note.filter(`#${hash}`).length > 0);
};
/*
@ -597,13 +620,12 @@ const normalizeNewlines = function(str) {
$noteEntityEl = $(noteEntity.html);
$noteEntityEl.addClass('fade-in-full');
this.revertNoteEditForm($targetNote);
gl.utils.localTimeAgo($('.js-timeago', $noteEntityEl));
$noteEntityEl.renderGFM();
$noteEntityEl.find('.js-task-list-container').taskList('enable');
// Find the note's `li` element by ID and replace it with the updated HTML
$note_li = $('.note-row-' + noteEntity.id);
$note_li.replaceWith($noteEntityEl);
this.setupNewNote($noteEntityEl);
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
gl.diffNotesCompileComponents();

View file

@ -126,6 +126,7 @@ import '~/notes';
const deferred = $.Deferred();
spyOn($, 'ajax').and.returnValue(deferred.promise());
spyOn(this.notes, 'revertNoteEditForm');
spyOn(this.notes, 'setupNewNote');
$('.js-comment-button').click();
deferred.resolve(noteEntity);
@ -136,6 +137,46 @@ import '~/notes';
this.notes.updateNote(updatedNote, $targetNote);
expect(this.notes.revertNoteEditForm).toHaveBeenCalledWith($targetNote);
expect(this.notes.setupNewNote).toHaveBeenCalled();
});
});
describe('updateNoteTargetSelector', () => {
const hash = 'note_foo';
let $note;
beforeEach(() => {
$note = $(`<div id="${hash}"></div>`);
spyOn($note, 'filter').and.callThrough();
spyOn($note, 'toggleClass').and.callThrough();
});
it('sets target when hash matches', () => {
spyOn(gl.utils, 'getLocationHash');
gl.utils.getLocationHash.and.returnValue(hash);
Notes.updateNoteTargetSelector($note);
expect($note.filter).toHaveBeenCalledWith(`#${hash}`);
expect($note.toggleClass).toHaveBeenCalledWith('target', true);
});
it('unsets target when hash does not match', () => {
spyOn(gl.utils, 'getLocationHash');
gl.utils.getLocationHash.and.returnValue('note_doesnotexist');
Notes.updateNoteTargetSelector($note);
expect($note.toggleClass).toHaveBeenCalledWith('target', false);
});
it('unsets target when there is not a hash fragment anymore', () => {
spyOn(gl.utils, 'getLocationHash');
gl.utils.getLocationHash.and.returnValue(null);
Notes.updateNoteTargetSelector($note);
expect($note.toggleClass).toHaveBeenCalledWith('target', null);
});
});
@ -189,9 +230,13 @@ import '~/notes';
Notes.isUpdatedNote.and.returnValue(true);
const $note = $('<div>');
$notesList.find.and.returnValue($note);
const $newNote = $(note.html);
Notes.animateUpdateNote.and.returnValue($newNote);
Notes.prototype.renderNote.call(notes, note, null, $notesList);
expect(Notes.animateUpdateNote).toHaveBeenCalledWith(note.html, $note);
expect(notes.setupNewNote).toHaveBeenCalledWith($newNote);
});
describe('while editing', () => {