debian-mirror-gitlab/app/assets/javascripts/notes.js.coffee

536 lines
16 KiB
CoffeeScript
Raw Normal View History

2015-09-11 14:41:01 +05:30
#= require autosave
#= require dropzone
#= require dropzone_input
#= require gfm_auto_complete
#= require jquery.atwho
#= require task_list
2015-04-26 12:48:37 +05:30
class @Notes
2014-09-02 18:07:02 +05:30
@interval: null
2015-09-11 14:41:01 +05:30
constructor: (notes_url, note_ids, last_fetched_at, view) ->
2014-09-02 18:07:02 +05:30
@notes_url = notes_url
@note_ids = note_ids
@last_fetched_at = last_fetched_at
2015-09-11 14:41:01 +05:30
@view = view
2015-04-26 12:48:37 +05:30
@noteable_url = document.URL
2014-09-02 18:07:02 +05:30
@initRefresh()
@setupMainTargetNoteForm()
@cleanBinding()
@addBinding()
2015-09-11 14:41:01 +05:30
@initTaskList()
2014-09-02 18:07:02 +05:30
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
2015-04-26 12:48:37 +05:30
# change note in UI after update
2014-09-02 18:07:02 +05:30
$(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
2015-04-26 12:48:37 +05:30
# Reopen and close actions for Issue/MR combined with note form submit
$(document).on "click", ".js-note-target-reopen", @targetReopen
$(document).on "click", ".js-note-target-close", @targetClose
$(document).on "click", ".js-comment-button", @updateCloseButton
$(document).on "keyup", ".js-note-text", @updateTargetButtons
2014-09-02 18:07:02 +05:30
# remove a note (in general)
$(document).on "click", ".js-note-delete", @removeNote
# delete note attachment
$(document).on "click", ".js-note-attachment-delete", @removeAttachment
# reset main target form after submit
2015-04-26 12:48:37 +05:30
$(document).on "ajax:complete", ".js-main-target-form", @reenableTargetFormSubmitButton
$(document).on "ajax:success", ".js-main-target-form", @resetMainTargetForm
2014-09-02 18:07:02 +05:30
# 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
2015-04-26 12:48:37 +05:30
# Chrome doesn't fire keypress or keyup for Command+Enter, so we need keydown.
2015-09-11 14:41:01 +05:30
$(document).on 'keydown', '.js-note-text', (e) ->
2015-04-26 12:48:37 +05:30
return if e.originalEvent.repeat
if e.keyCode == 10 || ((e.metaKey || e.ctrlKey) && e.keyCode == 13)
2015-09-11 14:41:01 +05:30
$(@).closest('form').submit()
2014-09-02 18:07:02 +05:30
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 "ajax:complete", ".js-main-target-form"
2015-04-26 12:48:37 +05:30
$(document).off "ajax:success", ".js-main-target-form"
2014-09-02 18:07:02 +05:30
$(document).off "click", ".js-discussion-reply-button"
$(document).off "click", ".js-add-diff-note-button"
$(document).off "visibilitychange"
2015-09-11 14:41:01 +05:30
$(document).off "keydown", ".js-note-text"
2015-04-26 12:48:37 +05:30
$(document).off "keyup", ".js-note-text"
$(document).off "click", ".js-note-target-reopen"
$(document).off "click", ".js-note-target-close"
2014-09-02 18:07:02 +05:30
2015-09-11 14:41:01 +05:30
$('.note .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.note .js-task-list-container'
2014-09-02 18:07:02 +05:30
initRefresh: ->
clearInterval(Notes.interval)
Notes.interval = setInterval =>
@refresh()
, 15000
refresh: ->
2015-04-26 12:48:37 +05:30
unless document.hidden or (@noteable_url != document.URL)
@getContent()
2014-09-02 18:07:02 +05:30
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)
2015-09-11 14:41:01 +05:30
@initTaskList()
2014-09-02 18:07:02 +05:30
###
Check if note does not exists on page
###
isNewNote: (note) ->
$.inArray(note.id, @note_ids) == -1
2015-09-11 14:41:01 +05:30
isParallelView: ->
@view == 'parallel'
2014-09-02 18:07:02 +05:30
###
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)
###
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
2015-04-26 12:48:37 +05:30
form.find(".js-md-write-button").click()
2014-09-02 18:07:02 +05:30
form.find(".js-note-text").val("").trigger "input"
2015-04-26 12:48:37 +05:30
form.find(".js-note-text").data("autosave").reset()
2014-09-02 18:07:02 +05:30
2015-04-26 12:48:37 +05:30
reenableTargetFormSubmitButton: ->
form = $(".js-main-target-form")
form.find(".js-note-text").trigger "input"
2014-09-02 18:07:02 +05:30
###
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"
2015-04-26 12:48:37 +05:30
form.find('.div-dropzone').remove()
2014-09-02 18:07:02 +05:30
# setup preview buttons
2015-04-26 12:48:37 +05:30
form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left"
previewButton = form.find(".js-md-preview-button")
textarea = form.find(".js-note-text")
textarea.on "input", ->
2014-09-02 18:07:02 +05:30
if $(this).val().trim() isnt ""
previewButton.removeClass("turn-off").addClass "turn-on"
else
previewButton.removeClass("turn-on").addClass "turn-off"
2015-04-26 12:48:37 +05:30
new Autosave textarea, [
"Note"
form.find("#note_commit_id").val()
form.find("#note_line_code").val()
form.find("#note_noteable_type").val()
form.find("#note_noteable_id").val()
]
2014-09-02 18:07:02 +05:30
# 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()
2015-04-26 12:48:37 +05:30
new DropzoneInput(form)
2014-09-02 18:07:02 +05:30
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) =>
2015-04-26 12:48:37 +05:30
note_li = $(".note-row-" + note.id)
2014-09-02 18:07:02 +05:30
note_li.replaceWith(note.html)
2015-04-26 12:48:37 +05:30
note_li.find('.note-edit-form').hide()
note_li.find('.note-body > .note-text').show()
2015-09-11 14:41:01 +05:30
note_li.find('js-task-list-container').taskList('enable')
@enableTaskList()
2014-09-02 18:07:02 +05:30
###
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")
2015-04-26 12:48:37 +05:30
note.find(".note-body > .note-text").hide()
note.find(".note-header").hide()
base_form = note.find(".note-edit-form")
form = base_form.clone().insertAfter(base_form)
2015-09-11 14:41:01 +05:30
form.addClass('current-note-edit-form gfm-form')
2015-04-26 12:48:37 +05:30
form.find('.div-dropzone').remove()
2014-09-02 18:07:02 +05:30
# Show the attachment delete link
note.find(".js-note-attachment-delete").show()
2015-04-26 12:48:37 +05:30
# Setup markdown form
2014-09-02 18:07:02 +05:30
GitLab.GfmAutoComplete.setup()
2015-04-26 12:48:37 +05:30
new DropzoneInput(form)
2014-09-02 18:07:02 +05:30
form.show()
textarea = form.find("textarea")
textarea.focus()
2015-09-11 14:41:01 +05:30
# HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?).
# The textarea has the correct value, Chrome just won't show it unless we
# modify it, so let's clear it and re-set it!
value = textarea.val()
textarea.val ""
textarea.val value
2014-09-02 18:07:02 +05:30
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")
2015-04-26 12:48:37 +05:30
note.find(".note-body > .note-text").show()
note.find(".note-header").show()
note.find(".current-note-edit-form").remove()
2014-09-02 18:07:02 +05:30
###
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()
2015-04-26 12:48:37 +05:30
note.find(".note-body > .note-text").show()
2014-09-02 18:07:02 +05:30
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")
2015-09-11 14:41:01 +05:30
form.find("#line_type").val dataHolder.data("lineType")
2014-09-02 18:07:02 +05:30
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"
###
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()
2015-04-26 12:48:37 +05:30
link = e.currentTarget
2014-09-02 18:07:02 +05:30
form = $(".js-new-note-form")
row = $(link).closest("tr")
nextRow = row.next()
2015-09-11 14:41:01 +05:30
hasNotes = nextRow.is(".notes_holder")
addForm = false
targetContent = ".notes_content"
rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\" colspan=\"2\"></td><td class=\"notes_content\"></td></tr>"
# In parallel view, look inside the correct left/right pane
if @isParallelView()
lineType = $(link).data("lineType")
targetContent += "." + lineType
rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\"></td><td class=\"notes_content parallel old\"></td><td class=\"notes_line\"></td><td class=\"notes_content parallel new\"></td></tr>"
if hasNotes
notesContent = nextRow.find(targetContent)
if notesContent.length
replyButton = notesContent.find(".js-discussion-reply-button:visible")
if replyButton.length
e.target = replyButton[0]
$.proxy(@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
2014-09-02 18:07:02 +05:30
else
# add a notes row and insert the form
2015-09-11 14:41:01 +05:30
row.after rowCssToAdd
addForm = true
if addForm
newForm = form.clone()
newForm.appendTo row.next().find(targetContent)
2014-09-02 18:07:02 +05:30
# show the form
2015-09-11 14:41:01 +05:30
@setupDiscussionNoteForm $(link), newForm
2014-09-02 18:07:02 +05:30
###
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")
2015-04-26 12:48:37 +05:30
form.find(".js-note-text").data("autosave").reset()
2014-09-02 18:07:02 +05:30
# 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: ->
2015-04-26 12:48:37 +05:30
true
2014-09-02 18:07:02 +05:30
###
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()
2015-04-26 12:48:37 +05:30
targetReopen: (e) =>
@submitNoteForm($(e.target).parents('form'))
targetClose: (e) =>
@submitNoteForm($(e.target).parents('form'))
submitNoteForm: (form) =>
noteText = form.find(".js-note-text").val()
if noteText.trim().length > 0
form.submit()
updateCloseButton: (e) =>
textarea = $(e.target)
form = textarea.parents('form')
form.find('.js-note-target-close').text('Close')
updateTargetButtons: (e) =>
textarea = $(e.target)
form = textarea.parents('form')
if textarea.val().trim().length > 0
form.find('.js-note-target-reopen').text('Comment & reopen')
form.find('.js-note-target-close').text('Comment & close')
else
form.find('.js-note-target-reopen').text('Reopen')
form.find('.js-note-target-close').text('Close')
2015-09-11 14:41:01 +05:30
initTaskList: ->
@enableTaskList()
$(document).on 'tasklist:changed', '.note .js-task-list-container', @updateTaskList
enableTaskList: ->
$('.note .js-task-list-container').taskList('enable')
updateTaskList: ->
$('form', this).submit()