505 lines
15 KiB
CoffeeScript
505 lines
15 KiB
CoffeeScript
class Notes
|
|
@interval: null
|
|
|
|
constructor: (notes_url, note_ids, last_fetched_at) ->
|
|
@notes_url = notes_url
|
|
@notes_url = gon.relative_url_root + @notes_url if gon.relative_url_root?
|
|
@note_ids = note_ids
|
|
@last_fetched_at = last_fetched_at
|
|
@initRefresh()
|
|
@setupMainTargetNoteForm()
|
|
@cleanBinding()
|
|
@addBinding()
|
|
|
|
addBinding: ->
|
|
# add note to UI after creation
|
|
$(document).on "ajax:success", ".js-main-target-form", @addNote
|
|
$(document).on "ajax:success", ".js-discussion-note-form", @addDiscussionNote
|
|
|
|
# change note in UI after update
|
|
$(document).on "ajax:success", "form.edit_note", @updateNote
|
|
|
|
# Edit note link
|
|
$(document).on "click", ".js-note-edit", @showEditForm
|
|
$(document).on "click", ".note-edit-cancel", @cancelEdit
|
|
|
|
# remove a note (in general)
|
|
$(document).on "click", ".js-note-delete", @removeNote
|
|
|
|
# delete note attachment
|
|
$(document).on "click", ".js-note-attachment-delete", @removeAttachment
|
|
|
|
# Preview button
|
|
$(document).on "click", ".js-note-preview-button", @previewNote
|
|
|
|
# Preview button
|
|
$(document).on "click", ".js-note-write-button", @writeNote
|
|
|
|
# reset main target form after submit
|
|
$(document).on "ajax:complete", ".js-main-target-form", @resetMainTargetForm
|
|
|
|
# attachment button
|
|
$(document).on "click", ".js-choose-note-attachment-button", @chooseNoteAttachment
|
|
|
|
# update the file name when an attachment is selected
|
|
$(document).on "change", ".js-note-attachment-input", @updateFormAttachment
|
|
|
|
# reply to diff/discussion notes
|
|
$(document).on "click", ".js-discussion-reply-button", @replyToDiscussionNote
|
|
|
|
# add diff note
|
|
$(document).on "click", ".js-add-diff-note-button", @addDiffNote
|
|
|
|
# hide diff note form
|
|
$(document).on "click", ".js-close-discussion-note-form", @cancelDiscussionForm
|
|
|
|
# fetch notes when tab becomes visible
|
|
$(document).on "visibilitychange", @visibilityChange
|
|
|
|
@notes_forms = '.js-main-target-form textarea, .js-discussion-note-form textarea'
|
|
$(document).on('keypress', @notes_forms, (e)->
|
|
if e.keyCode == 10 || (e.ctrlKey && e.keyCode == 13)
|
|
$(@).parents('form').submit()
|
|
)
|
|
|
|
cleanBinding: ->
|
|
$(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 "click", ".js-note-preview-button"
|
|
$(document).off "click", ".js-note-write-button"
|
|
$(document).off "ajax:complete", ".js-main-target-form"
|
|
$(document).off "click", ".js-choose-note-attachment-button"
|
|
$(document).off "click", ".js-discussion-reply-button"
|
|
$(document).off "click", ".js-add-diff-note-button"
|
|
$(document).off "visibilitychange"
|
|
$(document).off "keypress", @notes_forms
|
|
|
|
|
|
initRefresh: ->
|
|
clearInterval(Notes.interval)
|
|
Notes.interval = setInterval =>
|
|
@refresh()
|
|
, 15000
|
|
|
|
refresh: ->
|
|
@getContent() unless document.hidden
|
|
|
|
getContent: ->
|
|
$.ajax
|
|
url: @notes_url
|
|
data: "last_fetched_at=" + @last_fetched_at
|
|
dataType: "json"
|
|
success: (data) =>
|
|
notes = data.notes
|
|
@last_fetched_at = data.last_fetched_at
|
|
$.each notes, (i, note) =>
|
|
@renderNote(note)
|
|
|
|
|
|
###
|
|
Render note in main comments area.
|
|
|
|
Note: for rendering inline notes use renderDiscussionNote
|
|
###
|
|
renderNote: (note) ->
|
|
# render note if it not present in loaded list
|
|
# or skip if rendered
|
|
if @isNewNote(note)
|
|
@note_ids.push(note.id)
|
|
$('ul.main-notes-list').append(note.html)
|
|
code = "#note_" + note.id + " .highlight pre code"
|
|
$(code).each (i, e) ->
|
|
hljs.highlightBlock(e)
|
|
|
|
|
|
###
|
|
Check if note does not exists on page
|
|
###
|
|
isNewNote: (note) ->
|
|
$.inArray(note.id, @note_ids) == -1
|
|
|
|
|
|
###
|
|
Render note in discussion area.
|
|
|
|
Note: for rendering inline notes use renderDiscussionNote
|
|
###
|
|
renderDiscussionNote: (note) ->
|
|
@note_ids.push(note.id)
|
|
form = $("form[rel='" + note.discussion_id + "']")
|
|
row = form.closest("tr")
|
|
|
|
# is this the first note of discussion?
|
|
if row.is(".js-temp-notes-holder")
|
|
# insert the note and the reply button after the temp row
|
|
row.after note.discussion_html
|
|
|
|
# remove the note (will be added again below)
|
|
row.next().find(".note").remove()
|
|
|
|
# Add note to 'Changes' page discussions
|
|
$(".notes[rel='" + note.discussion_id + "']").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_with_diff_html)
|
|
else
|
|
# append new note to all matching discussions
|
|
$(".notes[rel='" + note.discussion_id + "']").append note.html
|
|
|
|
# cleanup after successfully creating a diff/discussion note
|
|
@removeDiscussionNoteForm(form)
|
|
|
|
###
|
|
Shows write note textarea.
|
|
###
|
|
writeNote: (e) ->
|
|
e.preventDefault()
|
|
form = $(this).closest("form")
|
|
# toggle tabs
|
|
form.find(".js-note-write-button").parent().addClass "active"
|
|
form.find(".js-note-preview-button").parent().removeClass "active"
|
|
|
|
# toggle content
|
|
form.find(".note-write-holder").show()
|
|
form.find(".note-preview-holder").hide()
|
|
|
|
###
|
|
Shows the note preview.
|
|
|
|
Lets the server render GFM into Html and displays it.
|
|
###
|
|
previewNote: (e) ->
|
|
e.preventDefault()
|
|
form = $(this).closest("form")
|
|
# toggle tabs
|
|
form.find(".js-note-write-button").parent().removeClass "active"
|
|
form.find(".js-note-preview-button").parent().addClass "active"
|
|
|
|
# toggle content
|
|
form.find(".note-write-holder").hide()
|
|
form.find(".note-preview-holder").show()
|
|
|
|
preview = form.find(".js-note-preview")
|
|
noteText = form.find(".js-note-text").val()
|
|
if noteText.trim().length is 0
|
|
preview.text "Nothing to preview."
|
|
else
|
|
preview.text "Loading..."
|
|
$.post($(this).data("url"),
|
|
note: noteText
|
|
).success (previewData) ->
|
|
preview.html previewData
|
|
|
|
###
|
|
Called in response the main target form has been successfully submitted.
|
|
|
|
Removes any errors.
|
|
Resets text and preview.
|
|
Resets buttons.
|
|
###
|
|
resetMainTargetForm: ->
|
|
form = $(".js-main-target-form")
|
|
|
|
# remove validation errors
|
|
form.find(".js-errors").remove()
|
|
|
|
# reset text and preview
|
|
form.find(".js-note-write-button").click()
|
|
form.find(".js-note-text").val("").trigger "input"
|
|
|
|
###
|
|
Called when clicking the "Choose File" button.
|
|
|
|
Opens the file selection dialog.
|
|
###
|
|
chooseNoteAttachment: ->
|
|
form = $(this).closest("form")
|
|
form.find(".js-note-attachment-input").click()
|
|
|
|
###
|
|
Shows the main form and does some setup on it.
|
|
|
|
Sets some hidden fields in the form.
|
|
###
|
|
setupMainTargetNoteForm: ->
|
|
|
|
# find the form
|
|
form = $(".js-new-note-form")
|
|
|
|
# insert the form after the button
|
|
form.clone().replaceAll $(".js-main-target-form")
|
|
form = form.prev("form")
|
|
|
|
# show the form
|
|
@setupNoteForm(form)
|
|
|
|
# fix classes
|
|
form.removeClass "js-new-note-form"
|
|
form.addClass "js-main-target-form"
|
|
|
|
# remove unnecessary fields and buttons
|
|
form.find("#note_line_code").remove()
|
|
form.find(".js-close-discussion-note-form").remove()
|
|
|
|
###
|
|
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
|
|
###
|
|
setupNoteForm: (form) ->
|
|
disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button")
|
|
form.removeClass "js-new-note-form"
|
|
|
|
# setup preview buttons
|
|
form.find(".js-note-write-button, .js-note-preview-button").tooltip placement: "left"
|
|
previewButton = form.find(".js-note-preview-button")
|
|
form.find(".js-note-text").on "input", ->
|
|
if $(this).val().trim() isnt ""
|
|
previewButton.removeClass("turn-off").addClass "turn-on"
|
|
else
|
|
previewButton.removeClass("turn-on").addClass "turn-off"
|
|
|
|
|
|
# remove notify commit author checkbox for non-commit notes
|
|
form.find(".js-notify-commit-author").remove() if form.find("#note_noteable_type").val() isnt "Commit"
|
|
GitLab.GfmAutoComplete.setup()
|
|
form.show()
|
|
|
|
|
|
###
|
|
Called in response to the new note form being submitted
|
|
|
|
Adds new note to list.
|
|
###
|
|
addNote: (xhr, note, status) =>
|
|
@renderNote(note)
|
|
@updateVotes()
|
|
|
|
###
|
|
Called in response to the new note form being submitted
|
|
|
|
Adds new note to list.
|
|
###
|
|
addDiscussionNote: (xhr, note, status) =>
|
|
@renderDiscussionNote(note)
|
|
|
|
###
|
|
Called in response to the edit note form being submitted
|
|
|
|
Updates the current note field.
|
|
###
|
|
updateNote: (xhr, note, status) =>
|
|
note_li = $("#note_" + note.id)
|
|
note_li.replaceWith(note.html)
|
|
code = "#note_" + note.id + " .highlight pre code"
|
|
$(code).each (i, e) ->
|
|
hljs.highlightBlock(e)
|
|
|
|
###
|
|
Called in response to clicking the edit note link
|
|
|
|
Replaces the note text with the note edit form
|
|
Adds a hidden div with the original content of the note to fill the edit note form with
|
|
if the user cancels
|
|
###
|
|
showEditForm: (e) ->
|
|
e.preventDefault()
|
|
note = $(this).closest(".note")
|
|
note.find(".note-text").hide()
|
|
|
|
# Show the attachment delete link
|
|
note.find(".js-note-attachment-delete").show()
|
|
GitLab.GfmAutoComplete.setup()
|
|
form = note.find(".note-edit-form")
|
|
form.show()
|
|
textarea = form.find("textarea")
|
|
textarea.focus()
|
|
disableButtonIfEmptyField textarea, form.find(".js-comment-button")
|
|
|
|
###
|
|
Called in response to clicking the edit note link
|
|
|
|
Hides edit form
|
|
###
|
|
cancelEdit: (e) ->
|
|
e.preventDefault()
|
|
note = $(this).closest(".note")
|
|
note.find(".note-text").show()
|
|
note.find(".js-note-attachment-delete").hide()
|
|
note.find(".note-edit-form").hide()
|
|
|
|
###
|
|
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.
|
|
###
|
|
removeNote: ->
|
|
note = $(this).closest(".note")
|
|
notes = note.closest(".notes")
|
|
|
|
# check if this is the last note for this line
|
|
if notes.find(".note").length is 1
|
|
|
|
# for discussions
|
|
notes.closest(".discussion").remove()
|
|
|
|
# for diff lines
|
|
notes.closest("tr").remove()
|
|
|
|
note.remove()
|
|
|
|
###
|
|
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
|
|
###
|
|
removeAttachment: ->
|
|
note = $(this).closest(".note")
|
|
note.find(".note-attachment").remove()
|
|
note.find(".note-text").show()
|
|
note.find(".js-note-attachment-delete").hide()
|
|
note.find(".note-edit-form").hide()
|
|
|
|
###
|
|
Called when clicking on the "reply" button for a diff line.
|
|
|
|
Shows the note form below the notes.
|
|
###
|
|
replyToDiscussionNote: (e) =>
|
|
form = $(".js-new-note-form")
|
|
replyLink = $(e.target).closest(".js-discussion-reply-button")
|
|
replyLink.hide()
|
|
|
|
# insert the form after the button
|
|
form.clone().insertAfter replyLink
|
|
|
|
# show the form
|
|
@setupDiscussionNoteForm(replyLink, replyLink.next("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.
|
|
###
|
|
setupDiscussionNoteForm: (dataHolder, form) =>
|
|
# setup note target
|
|
form.attr "rel", dataHolder.data("discussionId")
|
|
form.find("#note_commit_id").val dataHolder.data("commitId")
|
|
form.find("#note_line_code").val dataHolder.data("lineCode")
|
|
form.find("#note_noteable_type").val dataHolder.data("noteableType")
|
|
form.find("#note_noteable_id").val dataHolder.data("noteableId")
|
|
@setupNoteForm form
|
|
form.find(".js-note-text").focus()
|
|
form.addClass "js-discussion-note-form"
|
|
|
|
###
|
|
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
|
|
###
|
|
setupNoteForm: (form) =>
|
|
disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button")
|
|
form.removeClass "js-new-note-form"
|
|
form.removeClass "js-new-note-form"
|
|
GitLab.GfmAutoComplete.setup()
|
|
|
|
# setup preview buttons
|
|
previewButton = form.find(".js-note-preview-button")
|
|
form.find(".js-note-text").on "input", ->
|
|
if $(this).val().trim() isnt ""
|
|
previewButton.removeClass("turn-off").addClass "turn-on"
|
|
else
|
|
previewButton.removeClass("turn-on").addClass "turn-off"
|
|
|
|
form.show()
|
|
|
|
###
|
|
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.
|
|
###
|
|
addDiffNote: (e) =>
|
|
e.preventDefault()
|
|
link = e.target
|
|
form = $(".js-new-note-form")
|
|
row = $(link).closest("tr")
|
|
nextRow = row.next()
|
|
|
|
# does it already have notes?
|
|
if nextRow.is(".notes_holder")
|
|
replyButton = nextRow.find(".js-discussion-reply-button")
|
|
if replyButton.length > 0
|
|
$.proxy(@replyToDiscussionNote, replyButton).call()
|
|
else
|
|
# add a notes row and insert the form
|
|
row.after "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\" colspan=\"2\"></td><td class=\"notes_content\"></td></tr>"
|
|
form.clone().appendTo row.next().find(".notes_content")
|
|
|
|
# show the form
|
|
@setupDiscussionNoteForm $(link), row.next().find("form")
|
|
|
|
###
|
|
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.
|
|
###
|
|
removeDiscussionNoteForm: (form)->
|
|
row = form.closest("tr")
|
|
|
|
# show the reply button (will only work for replies)
|
|
form.prev(".js-discussion-reply-button").show()
|
|
if row.is(".js-temp-notes-holder")
|
|
# remove temporary row for diff lines
|
|
row.remove()
|
|
else
|
|
# only remove the form
|
|
form.remove()
|
|
|
|
|
|
cancelDiscussionForm: (e) =>
|
|
e.preventDefault()
|
|
form = $(".js-new-note-form")
|
|
form = $(e.target).closest(".js-discussion-note-form")
|
|
@removeDiscussionNoteForm(form)
|
|
|
|
updateVotes: ->
|
|
(new NotesVotes).updateVotes()
|
|
|
|
###
|
|
Called after an attachment file has been selected.
|
|
|
|
Updates the file name for the selected attachment.
|
|
###
|
|
updateFormAttachment: ->
|
|
form = $(this).closest("form")
|
|
|
|
# get only the basename
|
|
filename = $(this).val().replace(/^.*[\\\/]/, "")
|
|
form.find(".js-attachment-filename").text filename
|
|
|
|
###
|
|
Called when the tab visibility changes
|
|
###
|
|
visibilityChange: =>
|
|
@refresh()
|
|
|
|
@Notes = Notes
|