gitlab-org--gitlab-foss/app/assets/javascripts/notes.js
Nur Rony 58f78d0571 makes system notes less intrusive to a conversation
adds dicussion icon and color change in system note links

adds discussion icons and sticky note icon for other system notes for now

fixes scss lint error

adds faded commit lists

hides first paragraph in commit list box

css tweak for commit list system notes

adds commit-list toggle functionality, css tweaks and css classnames more readable

small css fix in header. makes links bold in system note

renames class no-shade to hide-shade

adds entry for this merge request in changelog

removes commented line

removes the avatar-icon from discussion header

minor css tweaks to make the commit list alignment with header text

uses monospaced font to make the commit list lined up with all

removes icon from system note and align bullet list

resolves scss lint warings

adds helper function to extract system note message from first p tag

adds helper functions to check commit list count and haml cleanup

adds changelog entry under 8.14

adds changelog entry with changelog cli

removes helper and regex and makes commit list li count using JS

makes link in system note normal

brakeman build failure resolved

fixing rspec test based on new design for discussion

shows system note in lowercase

removes extra spaces from comments

adds code commenting for functions

adds semi-colon in some lines

fixes rspec given when merge build success

removes commented codes

rewrite changelog yml file

moves isMetaKey to common utils file

fixes some indentation issues

removes unnecessary variables and resolves some discussions

replaces jQuery parent function with siblings

fixes scss issues and variable spelling mistake

uses constant rather using hardcoded number for visible li count in long commit list

makes system note header all lowercase

uses color variables and adjust gradient a little

some minor changes for adding css classes

renames functions name for readability

changes changelog title

minor scss newline changes

makes system note less intrusive to a conversation
2016-11-17 14:41:08 +06:00

895 lines
32 KiB
JavaScript

/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, camelcase, no-unused-expressions, quotes, max-len, one-var, one-var-declaration-per-line, default-case, prefer-template, no-undef, consistent-return, no-alert, no-return-assign, no-param-reassign, prefer-arrow-callback, no-else-return, comma-dangle, no-new, brace-style, no-lonely-if, vars-on-top, no-unused-vars, semi, indent, no-sequences, no-shadow, newline-per-chained-call, no-useless-escape, radix, padded-blocks, max-len */
/*= require autosave */
/*= require autosize */
/*= require dropzone */
/*= require dropzone_input */
/*= require gfm_auto_complete */
/*= require jquery.atwho */
/*= require task_list */
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
this.Notes = (function() {
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
Notes.interval = null;
function Notes(notes_url, note_ids, last_fetched_at, view) {
this.updateTargetButtons = bind(this.updateTargetButtons, this);
this.updateCloseButton = bind(this.updateCloseButton, this);
this.visibilityChange = bind(this.visibilityChange, this);
this.cancelDiscussionForm = bind(this.cancelDiscussionForm, this);
this.addDiffNote = bind(this.addDiffNote, this);
this.setupDiscussionNoteForm = bind(this.setupDiscussionNoteForm, this);
this.replyToDiscussionNote = bind(this.replyToDiscussionNote, this);
this.removeNote = bind(this.removeNote, this);
this.cancelEdit = bind(this.cancelEdit, this);
this.updateNote = bind(this.updateNote, this);
this.addDiscussionNote = bind(this.addDiscussionNote, this);
this.addNoteError = bind(this.addNoteError, this);
this.addNote = bind(this.addNote, this);
this.resetMainTargetForm = bind(this.resetMainTargetForm, this);
this.refresh = bind(this.refresh, this);
this.keydownNoteText = bind(this.keydownNoteText, this);
this.toggleCommitList = bind(this.toggleCommitList, this);
this.notes_url = notes_url;
this.note_ids = note_ids;
this.last_fetched_at = last_fetched_at;
this.view = view;
this.noteable_url = document.URL;
this.notesCountBadge || (this.notesCountBadge = $(".issuable-details").find(".notes-tab .badge"));
this.basePollingInterval = 15000;
this.maxPollingSteps = 4;
this.cleanBinding();
this.addBinding();
this.setPollingInterval();
this.setupMainTargetNoteForm();
this.initTaskList();
this.collapseLongCommitList();
}
Notes.prototype.addBinding = function() {
// add note to UI after creation
$(document).on("ajax:success", ".js-main-target-form", this.addNote);
$(document).on("ajax:success", ".js-discussion-note-form", this.addDiscussionNote);
// catch note ajax errors
$(document).on("ajax:error", ".js-main-target-form", this.addNoteError);
// change note in UI after update
$(document).on("ajax:success", "form.edit-note", this.updateNote);
// Edit note link
$(document).on("click", ".js-note-edit", this.showEditForm);
$(document).on("click", ".note-edit-cancel", this.cancelEdit);
// Reopen and close actions for Issue/MR combined with note form submit
$(document).on("click", ".js-comment-button", this.updateCloseButton);
$(document).on("keyup input", ".js-note-text", this.updateTargetButtons);
// resolve a discussion
$(document).on('click', '.js-comment-resolve-button', this.resolveDiscussion);
// remove a note (in general)
$(document).on("click", ".js-note-delete", this.removeNote);
// delete note attachment
$(document).on("click", ".js-note-attachment-delete", this.removeAttachment);
// reset main target form after submit
$(document).on("ajax:complete", ".js-main-target-form", this.reenableTargetFormSubmitButton);
$(document).on("ajax:success", ".js-main-target-form", this.resetMainTargetForm);
// reset main target form when clicking discard
$(document).on("click", ".js-note-discard", this.resetMainTargetForm);
// update the file name when an attachment is selected
$(document).on("change", ".js-note-attachment-input", this.updateFormAttachment);
// reply to diff/discussion notes
$(document).on("click", ".js-discussion-reply-button", this.replyToDiscussionNote);
// add diff note
$(document).on("click", ".js-add-diff-note-button", this.addDiffNote);
// hide diff note form
$(document).on("click", ".js-close-discussion-note-form", this.cancelDiscussionForm);
// toggle commit list
$(document).on("click", '.system-note-commit-list-toggler', this.toggleCommitList);
// fetch notes when tab becomes visible
$(document).on("visibilitychange", this.visibilityChange);
// when issue status changes, we need to refresh data
$(document).on("issuable:change", this.refresh);
// when a key is clicked on the notes
return $(document).on("keydown", ".js-note-text", this.keydownNoteText);
};
Notes.prototype.cleanBinding = function() {
$(document).off("ajax:success", ".js-main-target-form");
$(document).off("ajax:success", ".js-discussion-note-form");
$(document).off("ajax:success", "form.edit-note");
$(document).off("click", ".js-note-edit");
$(document).off("click", ".note-edit-cancel");
$(document).off("click", ".js-note-delete");
$(document).off("click", ".js-note-attachment-delete");
$(document).off("ajax:complete", ".js-main-target-form");
$(document).off("ajax:success", ".js-main-target-form");
$(document).off("click", ".js-discussion-reply-button");
$(document).off("click", ".js-add-diff-note-button");
$(document).off("visibilitychange");
$(document).off("keyup", ".js-note-text");
$(document).off("click", ".js-note-target-reopen");
$(document).off("click", ".js-note-target-close");
$(document).off("click", ".js-note-discard");
$(document).off("keydown", ".js-note-text");
$(document).off('click', '.js-comment-resolve-button');
$('.note .js-task-list-container').taskList('disable');
return $(document).off('tasklist:changed', '.note .js-task-list-container');
};
Notes.prototype.keydownNoteText = function(e) {
var $textarea, discussionNoteForm, editNote, myLastNote, myLastNoteEditBtn, newText, originalText;
if (gl.utils.isMetaKey(e)) {
return;
}
$textarea = $(e.target);
// Edit previous note when UP arrow is hit
switch (e.which) {
case 38:
if ($textarea.val() !== '') {
return;
}
myLastNote = $("li.note[data-author-id='" + gon.current_user_id + "'][data-editable]:last");
if (myLastNote.length) {
myLastNoteEditBtn = myLastNote.find('.js-note-edit');
return myLastNoteEditBtn.trigger('click', [true, myLastNote]);
}
break;
// Cancel creating diff note or editing any note when ESCAPE is hit
case 27:
discussionNoteForm = $textarea.closest('.js-discussion-note-form');
if (discussionNoteForm.length) {
if ($textarea.val() !== '') {
if (!confirm('Are you sure you want to cancel creating this comment?')) {
return;
}
}
this.removeDiscussionNoteForm(discussionNoteForm);
return;
}
editNote = $textarea.closest('.note');
if (editNote.length) {
originalText = $textarea.closest('form').data('original-note');
newText = $textarea.val();
if (originalText !== newText) {
if (!confirm('Are you sure you want to cancel editing this comment?')) {
return;
}
}
return this.removeNoteEditForm(editNote);
}
}
};
Notes.prototype.initRefresh = function() {
clearInterval(Notes.interval);
return Notes.interval = setInterval((function(_this) {
return function() {
return _this.refresh();
};
})(this), this.pollingInterval);
};
Notes.prototype.refresh = function() {
if (!document.hidden && document.URL.indexOf(this.noteable_url) === 0) {
return this.getContent();
}
};
Notes.prototype.getContent = function() {
if (this.refreshing) {
return;
}
this.refreshing = true;
return $.ajax({
url: this.notes_url,
data: "last_fetched_at=" + this.last_fetched_at,
dataType: "json",
success: (function(_this) {
return function(data) {
var notes;
notes = data.notes;
_this.last_fetched_at = data.last_fetched_at;
_this.setPollingInterval(data.notes.length);
return $.each(notes, function(i, note) {
if (note.discussion_html != null) {
return _this.renderDiscussionNote(note);
} else {
return _this.renderNote(note);
}
});
};
})(this)
}).always((function(_this) {
return function() {
return _this.refreshing = false;
};
})(this));
};
/*
Increase @pollingInterval up to 120 seconds on every function call,
if `shouldReset` has a truthy value, 'null' or 'undefined' the variable
will reset to @basePollingInterval.
Note: this function is used to gradually increase the polling interval
if there aren't new notes coming from the server
*/
Notes.prototype.setPollingInterval = function(shouldReset) {
var nthInterval;
if (shouldReset == null) {
shouldReset = true;
}
nthInterval = this.basePollingInterval * Math.pow(2, this.maxPollingSteps - 1);
if (shouldReset) {
this.pollingInterval = this.basePollingInterval;
} else if (this.pollingInterval < nthInterval) {
this.pollingInterval *= 2;
}
return this.initRefresh();
};
/*
Render note in main comments area.
Note: for rendering inline notes use renderDiscussionNote
*/
Notes.prototype.renderNote = function(note) {
var $notesList, votesBlock;
if (!note.valid) {
if (note.award) {
new Flash('You have already awarded this emoji!', 'alert', this.parentTimeline);
}
else {
if (note.errors.commands_only) {
new Flash(note.errors.commands_only, 'notice', this.parentTimeline);
this.refresh();
}
}
return;
}
if (note.award) {
votesBlock = $('.js-awards-block').eq(0);
gl.awardsHandler.addAwardToEmojiBar(votesBlock, note.name);
return gl.awardsHandler.scrollToAwards();
// render note if it not present in loaded list
// or skip if rendered
} else if (this.isNewNote(note)) {
this.note_ids.push(note.id);
$notesList = $('ul.main-notes-list');
$notesList.append(note.html).syntaxHighlight();
// Update datetime format on the recent note
gl.utils.localTimeAgo($notesList.find("#note_" + note.id + " .js-timeago"), false);
this.collapseLongCommitList();
this.initTaskList();
this.refresh();
return this.updateNotesCount(1);
}
};
/*
Check if note does not exists on page
*/
Notes.prototype.isNewNote = function(note) {
return $.inArray(note.id, this.note_ids) === -1;
};
Notes.prototype.isParallelView = function() {
return this.view === 'parallel';
};
/*
Render note in discussion area.
Note: for rendering inline notes use renderDiscussionNote
*/
Notes.prototype.renderDiscussionNote = function(note) {
var discussionContainer, form, note_html, row;
if (!this.isNewNote(note)) {
return;
}
this.note_ids.push(note.id);
form = $("#new-discussion-note-form-" + note.discussion_id);
if ((note.original_discussion_id != null) && form.length === 0) {
form = $("#new-discussion-note-form-" + note.original_discussion_id);
}
row = form.closest("tr");
note_html = $(note.html);
note_html.syntaxHighlight();
// is this the first note of discussion?
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
if ((note.original_discussion_id != null) && discussionContainer.length === 0) {
discussionContainer = $(".notes[data-discussion-id='" + note.original_discussion_id + "']");
}
if (discussionContainer.length === 0) {
// insert the note and the reply button after the temp row
row.after(note.diff_discussion_html);
// remove the note (will be added again below)
row.next().find(".note").remove();
// Before that, the container didn't exist
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
// Add note to 'Changes' page discussions
discussionContainer.append(note_html);
// Init discussion on 'Discussion' page if it is merge request page
if ($('body').attr('data-page').indexOf('projects:merge_request') === 0) {
$('ul.main-notes-list').append(note.discussion_html).syntaxHighlight();
}
} else {
// append new note to all matching discussions
discussionContainer.append(note_html);
}
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
gl.diffNotesCompileComponents();
}
gl.utils.localTimeAgo($('.js-timeago', note_html), false);
return this.updateNotesCount(1);
};
/*
Called in response the main target form has been successfully submitted.
Removes any errors.
Resets text and preview.
Resets buttons.
*/
Notes.prototype.resetMainTargetForm = function(e) {
var form;
form = $(".js-main-target-form");
// remove validation errors
form.find(".js-errors").remove();
// reset text and preview
form.find(".js-md-write-button").click();
form.find(".js-note-text").val("").trigger("input");
form.find(".js-note-text").data("autosave").reset();
var event = document.createEvent('Event');
event.initEvent('autosize:update', true, false);
form.find('.js-autosize')[0].dispatchEvent(event);
this.updateTargetButtons(e);
};
Notes.prototype.reenableTargetFormSubmitButton = function() {
var form;
form = $(".js-main-target-form");
return form.find(".js-note-text").trigger("input");
};
/*
Shows the main form and does some setup on it.
Sets some hidden fields in the form.
*/
Notes.prototype.setupMainTargetNoteForm = function() {
var form;
// find the form
form = $(".js-new-note-form");
// Set a global clone of the form for later cloning
this.formClone = form.clone();
// show the form
this.setupNoteForm(form);
// fix classes
form.removeClass("js-new-note-form");
form.addClass("js-main-target-form");
form.find("#note_line_code").remove();
form.find("#note_position").remove();
form.find("#note_type").remove();
form.find('.js-comment-resolve-button').closest('comment-and-resolve-btn').remove();
return this.parentTimeline = form.parents('.timeline');
};
/*
General note form setup.
deactivates the submit button when text is empty
hides the preview button when text is empty
setup GFM auto complete
show the form
*/
Notes.prototype.setupNoteForm = function(form) {
var textarea;
new GLForm(form);
textarea = form.find(".js-note-text");
return new Autosave(textarea, ["Note", form.find("#note_noteable_type").val(), form.find("#note_noteable_id").val(), form.find("#note_commit_id").val(), form.find("#note_type").val(), form.find("#note_line_code").val(), form.find("#note_position").val()]);
};
/*
Called in response to the new note form being submitted
Adds new note to list.
*/
Notes.prototype.addNote = function(xhr, note, status) {
return this.renderNote(note);
};
Notes.prototype.addNoteError = function(xhr, note, status) {
return new Flash('Your comment could not be submitted! Please check your network connection and try again.', 'alert', this.parentTimeline);
};
/*
Called in response to the new note form being submitted
Adds new note to list.
*/
Notes.prototype.addDiscussionNote = function(xhr, note, status) {
var $form = $(xhr.target);
if ($form.attr('data-resolve-all') != null) {
var projectPath = $form.data('project-path');
var discussionId = $form.data('discussion-id');
var mergeRequestId = $form.data('noteable-iid');
if (ResolveService != null) {
ResolveService.toggleResolveForDiscussion(projectPath, mergeRequestId, discussionId);
}
}
this.renderDiscussionNote(note);
// cleanup after successfully creating a diff/discussion note
this.removeDiscussionNoteForm($form);
};
/*
Called in response to the edit note form being submitted
Updates the current note field.
*/
Notes.prototype.updateNote = function(_xhr, note, _status) {
var $html, $note_li;
// Convert returned HTML to a jQuery object so we can modify it further
$html = $(note.html);
gl.utils.localTimeAgo($('.js-timeago', $html));
$html.syntaxHighlight();
$html.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-' + note.id);
$note_li.replaceWith($html);
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
gl.diffNotesCompileComponents();
}
};
/*
Called in response to clicking the edit note link
Replaces the note text with the note edit form
Adds a data attribute to the form with the original content of the note for cancellations
*/
Notes.prototype.showEditForm = function(e, scrollTo, myLastNote) {
var $noteText, done, form, note;
e.preventDefault();
note = $(this).closest(".note");
note.addClass("is-editting");
form = note.find(".note-edit-form");
form.addClass('current-note-edit-form');
// Show the attachment delete link
note.find(".js-note-attachment-delete").show();
done = function($noteText) {
var noteTextVal;
// Neat little trick to put the cursor at the end
noteTextVal = $noteText.val();
// Store the original note text in a data attribute to retrieve if a user cancels edit.
form.find('form.edit-note').data('original-note', noteTextVal);
return $noteText.val('').val(noteTextVal);
};
new GLForm(form);
if ((scrollTo != null) && (myLastNote != null)) {
// scroll to the bottom
// so the open of the last element doesn't make a jump
$('html, body').scrollTop($(document).height());
return $('html, body').animate({
scrollTop: myLastNote.offset().top - 150
}, 500, function() {
var $noteText;
$noteText = form.find(".js-note-text");
$noteText.focus();
return done($noteText);
});
} else {
$noteText = form.find('.js-note-text');
$noteText.focus();
return done($noteText);
}
};
/*
Called in response to clicking the edit note link
Hides edit form and restores the original note text to the editor textarea.
*/
Notes.prototype.cancelEdit = function(e) {
var note;
e.preventDefault();
note = $(e.target).closest('.note');
return this.removeNoteEditForm(note);
};
Notes.prototype.removeNoteEditForm = function(note) {
var form;
form = note.find(".current-note-edit-form");
note.removeClass("is-editting");
form.removeClass("current-note-edit-form");
// Replace markdown textarea text with original note text.
return form.find(".js-note-text").val(form.find('form.edit-note').data('original-note'));
};
/*
Called in response to deleting a note of any kind.
Removes the actual note from view.
Removes the whole discussion if the last note is being removed.
*/
Notes.prototype.removeNote = function(e) {
var noteId;
noteId = $(e.currentTarget).closest(".note").attr("id");
$(".note[id='" + noteId + "']").each((function(_this) {
// A same note appears in the "Discussion" and in the "Changes" tab, we have
// to remove all. Using $(".note[id='noteId']") ensure we get all the notes,
// where $("#noteId") would return only one.
return function(i, el) {
var note, notes;
note = $(el);
notes = note.closest(".notes");
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
if (gl.diffNoteApps[noteId]) {
gl.diffNoteApps[noteId].$destroy();
}
}
// check if this is the last note for this line
if (notes.find(".note").length === 1) {
// "Discussions" tab
notes.closest(".timeline-entry").remove();
// "Changes" tab / commit view
notes.closest("tr").remove();
}
return note.remove();
};
})(this));
// Decrement the "Discussions" counter only once
return this.updateNotesCount(-1);
};
/*
Called in response to clicking the delete attachment link
Removes the attachment wrapper view, including image tag if it exists
Resets the note editing form
*/
Notes.prototype.removeAttachment = function() {
var note;
note = $(this).closest(".note");
note.find(".note-attachment").remove();
note.find(".note-body > .note-text").show();
note.find(".note-header").show();
return note.find(".current-note-edit-form").remove();
};
/*
Called when clicking on the "reply" button for a diff line.
Shows the note form below the notes.
*/
Notes.prototype.replyToDiscussionNote = function(e) {
var form, replyLink;
form = this.formClone.clone();
replyLink = $(e.target).closest(".js-discussion-reply-button");
// insert the form after the button
replyLink
.closest('.discussion-reply-holder')
.hide()
.after(form);
// show the form
return this.setupDiscussionNoteForm(replyLink, form);
};
/*
Shows the diff or discussion form and does some setup on it.
Sets some hidden fields in the form.
Note: dataHolder must have the "discussionId", "lineCode", "noteableType"
and "noteableId" data attributes set.
*/
Notes.prototype.setupDiscussionNoteForm = function(dataHolder, form) {
// setup note target
form.attr('id', "new-discussion-note-form-" + (dataHolder.data("discussionId")));
form.attr("data-line-code", dataHolder.data("lineCode"));
form.find("#note_type").val(dataHolder.data("noteType"));
form.find("#line_type").val(dataHolder.data("lineType"));
form.find("#note_commit_id").val(dataHolder.data("commitId"));
form.find("#note_line_code").val(dataHolder.data("lineCode"));
form.find("#note_position").val(dataHolder.attr("data-position"));
form.find("#note_noteable_type").val(dataHolder.data("noteableType"));
form.find("#note_noteable_id").val(dataHolder.data("noteableId"));
form.find('.js-note-discard').show().removeClass('js-note-discard').addClass('js-close-discussion-note-form').text(form.find('.js-close-discussion-note-form').data('cancel-text'));
form.find('.js-note-target-close').remove();
this.setupNoteForm(form);
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
var $commentBtn = form.find('comment-and-resolve-btn');
$commentBtn
.attr(':discussion-id', "'" + dataHolder.data('discussionId') + "'");
gl.diffNotesCompileComponents();
}
form.find(".js-note-text").focus();
form
.find('.js-comment-resolve-button')
.attr('data-discussion-id', dataHolder.data('discussionId'));
form
.removeClass('js-main-target-form')
.addClass("discussion-form js-discussion-note-form");
};
/*
Called when clicking on the "add a comment" button on the side of a diff line.
Inserts a temporary row for the form below the line.
Sets up the form and shows it.
*/
Notes.prototype.addDiffNote = function(e) {
var $link, addForm, hasNotes, lineType, newForm, nextRow, noteForm, notesContent, replyButton, row, rowCssToAdd, targetContent;
e.preventDefault();
$link = $(e.currentTarget);
row = $link.closest("tr");
nextRow = row.next();
hasNotes = nextRow.is(".notes_holder");
addForm = false;
notesContentSelector = ".notes_content";
rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\" colspan=\"2\"></td><td class=\"notes_content\"><div class=\"content\"></div></td></tr>";
// In parallel view, look inside the correct left/right pane
if (this.isParallelView()) {
lineType = $link.data("lineType");
notesContentSelector += "." + lineType;
rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line old\"></td><td class=\"notes_content parallel old\"><div class=\"content\"></div></td><td class=\"notes_line new\"></td><td class=\"notes_content parallel new\"><div class=\"content\"></div></td></tr>";
}
notesContentSelector += " .content";
if (hasNotes) {
nextRow.show();
notesContent = nextRow.find(notesContentSelector);
if (notesContent.length) {
notesContent.show();
replyButton = notesContent.find(".js-discussion-reply-button:visible");
if (replyButton.length) {
e.target = replyButton[0];
$.proxy(this.replyToDiscussionNote, replyButton[0], e).call();
} else {
// In parallel view, the form may not be present in one of the panes
noteForm = notesContent.find(".js-discussion-note-form");
if (noteForm.length === 0) {
addForm = true;
}
}
}
} else {
// add a notes row and insert the form
row.after(rowCssToAdd);
nextRow = row.next();
notesContent = nextRow.find(notesContentSelector);
addForm = true;
}
if (addForm) {
newForm = this.formClone.clone();
newForm.appendTo(notesContent);
// show the form
return this.setupDiscussionNoteForm($link, newForm);
}
};
/*
Called in response to "cancel" on a diff note form.
Shows the reply button again.
Removes the form and if necessary it's temporary row.
*/
Notes.prototype.removeDiscussionNoteForm = function(form) {
var glForm, row;
row = form.closest("tr");
glForm = form.data('gl-form');
glForm.destroy();
form.find(".js-note-text").data("autosave").reset();
// show the reply button (will only work for replies)
form
.prev('.discussion-reply-holder')
.show();
if (row.is(".js-temp-notes-holder")) {
// remove temporary row for diff lines
return row.remove();
} else {
// only remove the form
return form.remove();
}
};
Notes.prototype.cancelDiscussionForm = function(e) {
var form;
e.preventDefault();
form = $(e.target).closest(".js-discussion-note-form");
return this.removeDiscussionNoteForm(form);
};
/*
Called after an attachment file has been selected.
Updates the file name for the selected attachment.
*/
Notes.prototype.updateFormAttachment = function() {
var filename, form;
form = $(this).closest("form");
// get only the basename
filename = $(this).val().replace(/^.*[\\\/]/, "");
return form.find(".js-attachment-filename").text(filename);
};
/*
Called when the tab visibility changes
*/
Notes.prototype.visibilityChange = function() {
return this.refresh();
};
Notes.prototype.updateCloseButton = function(e) {
var closebtn, form, textarea;
textarea = $(e.target);
form = textarea.parents('form');
closebtn = form.find('.js-note-target-close');
return closebtn.text(closebtn.data('original-text'));
};
Notes.prototype.updateTargetButtons = function(e) {
var closebtn, closetext, discardbtn, form, reopenbtn, reopentext, textarea;
textarea = $(e.target);
form = textarea.parents('form');
reopenbtn = form.find('.js-note-target-reopen');
closebtn = form.find('.js-note-target-close');
discardbtn = form.find('.js-note-discard');
if (textarea.val().trim().length > 0) {
reopentext = reopenbtn.data('alternative-text');
closetext = closebtn.data('alternative-text');
if (reopenbtn.text() !== reopentext) {
reopenbtn.text(reopentext);
}
if (closebtn.text() !== closetext) {
closebtn.text(closetext);
}
if (reopenbtn.is(':not(.btn-comment-and-reopen)')) {
reopenbtn.addClass('btn-comment-and-reopen');
}
if (closebtn.is(':not(.btn-comment-and-close)')) {
closebtn.addClass('btn-comment-and-close');
}
if (discardbtn.is(':hidden')) {
return discardbtn.show();
}
} else {
reopentext = reopenbtn.data('original-text');
closetext = closebtn.data('original-text');
if (reopenbtn.text() !== reopentext) {
reopenbtn.text(reopentext);
}
if (closebtn.text() !== closetext) {
closebtn.text(closetext);
}
if (reopenbtn.is('.btn-comment-and-reopen')) {
reopenbtn.removeClass('btn-comment-and-reopen');
}
if (closebtn.is('.btn-comment-and-close')) {
closebtn.removeClass('btn-comment-and-close');
}
if (discardbtn.is(':visible')) {
return discardbtn.hide();
}
}
};
Notes.prototype.initTaskList = function() {
this.enableTaskList();
return $(document).on('tasklist:changed', '.note .js-task-list-container', this.updateTaskList);
};
Notes.prototype.enableTaskList = function() {
return $('.note .js-task-list-container').taskList('enable');
};
Notes.prototype.updateTaskList = function() {
return $('form', this).submit();
};
Notes.prototype.updateNotesCount = function(updateCount) {
return this.notesCountBadge.text(parseInt(this.notesCountBadge.text()) + updateCount);
};
Notes.prototype.resolveDiscussion = function() {
var $this = $(this);
var discussionId = $this.attr('data-discussion-id');
$this
.closest('form')
.attr('data-discussion-id', discussionId)
.attr('data-resolve-all', 'true')
.attr('data-project-path', $this.attr('data-project-path'));
};
Notes.prototype.toggleCommitList = function(e) {
const $element = $(e.target);
const $closestSystemCommitList = $element.siblings('.system-note-commit-list');
$closestSystemCommitList.toggleClass('hide-shade');
};
/**
Scans system notes with `ul` elements in system note body
then collapse long commit list pushed by user to make it less
intrusive.
*/
Notes.prototype.collapseLongCommitList = function() {
const systemNotes = $('#notes-list').find('li.system-note').has('ul');
$.each(systemNotes, function(index, systemNote) {
const $systemNote = $(systemNote);
const headerMessage = $systemNote.find('.note-text').find('p:first').text().replace(':', '');
$systemNote.find('.note-header .system-note-message').html(headerMessage);
if ($systemNote.find('li').length > MAX_VISIBLE_COMMIT_LIST_COUNT) {
$systemNote.find('.note-text').addClass('system-note-commit-list');
$systemNote.find('.system-note-commit-list-toggler').show();
} else {
$systemNote.find('.note-text').addClass('system-note-commit-list hide-shade');
}
});
};
return Notes;
})();
}).call(this);