mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-10 21:26:07 +10:00
Award Emoji This it first iteration of award emoji feature. We have plan to extend emoji picker by the next release. For now, you can add award by clicking to the emoji picker or posting a regular comment with emoji like "👍" and any other. You can post not only emoji that listed in the emoji picker. See merge request !1825
532 lines
16 KiB
CoffeeScript
532 lines
16 KiB
CoffeeScript
#= require autosave
|
|
#= require dropzone
|
|
#= require dropzone_input
|
|
#= require gfm_auto_complete
|
|
#= require jquery.atwho
|
|
#= require task_list
|
|
|
|
class @Notes
|
|
@interval: null
|
|
|
|
constructor: (notes_url, note_ids, last_fetched_at, view) ->
|
|
@notes_url = notes_url
|
|
@note_ids = note_ids
|
|
@last_fetched_at = last_fetched_at
|
|
@view = view
|
|
@noteable_url = document.URL
|
|
@initRefresh()
|
|
@setupMainTargetNoteForm()
|
|
@cleanBinding()
|
|
@addBinding()
|
|
@initTaskList()
|
|
|
|
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
|
|
|
|
# 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
|
|
|
|
# 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
|
|
$(document).on "ajax:complete", ".js-main-target-form", @reenableTargetFormSubmitButton
|
|
$(document).on "ajax:success", ".js-main-target-form", @resetMainTargetForm
|
|
|
|
# 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
|
|
|
|
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"
|
|
$(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"
|
|
|
|
$('.note .js-task-list-container').taskList('disable')
|
|
$(document).off 'tasklist:changed', '.note .js-task-list-container'
|
|
|
|
initRefresh: ->
|
|
clearInterval(Notes.interval)
|
|
Notes.interval = setInterval =>
|
|
@refresh()
|
|
, 15000
|
|
|
|
refresh: ->
|
|
unless document.hidden or (@noteable_url != document.URL)
|
|
@getContent()
|
|
|
|
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.award
|
|
@note_ids.push(note.id)
|
|
$('ul.main-notes-list').
|
|
append(note.html).
|
|
syntaxHighlight()
|
|
@initTaskList()
|
|
|
|
if note.award
|
|
awards_handler.addAwardToEmojiBar(note.note, note.emoji_path)
|
|
|
|
###
|
|
Check if note does not exists on page
|
|
###
|
|
isNewNote: (note) ->
|
|
$.inArray(note.id, @note_ids) == -1
|
|
|
|
isParallelView: ->
|
|
@view == 'parallel'
|
|
|
|
###
|
|
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
|
|
form.find(".js-md-write-button").click()
|
|
form.find(".js-note-text").val("").trigger "input"
|
|
|
|
form.find(".js-note-text").data("autosave").reset()
|
|
|
|
reenableTargetFormSubmitButton: ->
|
|
form = $(".js-main-target-form")
|
|
|
|
form.find(".js-note-text").trigger "input"
|
|
|
|
###
|
|
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"
|
|
form.find('.div-dropzone').remove()
|
|
|
|
# setup preview buttons
|
|
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", ->
|
|
if $(this).val().trim() isnt ""
|
|
previewButton.removeClass("turn-off").addClass "turn-on"
|
|
else
|
|
previewButton.removeClass("turn-on").addClass "turn-off"
|
|
|
|
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()
|
|
]
|
|
|
|
# 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()
|
|
new DropzoneInput(form)
|
|
form.show()
|
|
|
|
###
|
|
Called in response to the new note form being submitted
|
|
|
|
Adds new note to list.
|
|
###
|
|
addNote: (xhr, note, status) =>
|
|
@renderNote(note)
|
|
|
|
###
|
|
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) =>
|
|
# Convert returned HTML to a jQuery object so we can modify it further
|
|
$html = $(note.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_#{note.id}")
|
|
$note_li.replaceWith($html)
|
|
|
|
###
|
|
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-body > .note-text").hide()
|
|
note.find(".note-header").hide()
|
|
base_form = note.find(".note-edit-form")
|
|
form = base_form.clone().insertAfter(base_form)
|
|
form.addClass('current-note-edit-form gfm-form')
|
|
form.find('.div-dropzone').remove()
|
|
|
|
# Show the attachment delete link
|
|
note.find(".js-note-attachment-delete").show()
|
|
|
|
# Setup markdown form
|
|
GitLab.GfmAutoComplete.setup()
|
|
new DropzoneInput(form)
|
|
|
|
form.show()
|
|
textarea = form.find("textarea")
|
|
textarea.focus()
|
|
|
|
# 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
|
|
|
|
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-body > .note-text").show()
|
|
note.find(".note-header").show()
|
|
note.find(".current-note-edit-form").remove()
|
|
|
|
###
|
|
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-body > .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("#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_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()
|
|
link = e.currentTarget
|
|
form = $(".js-new-note-form")
|
|
row = $(link).closest("tr")
|
|
nextRow = row.next()
|
|
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
|
|
else
|
|
# add a notes row and insert the form
|
|
row.after rowCssToAdd
|
|
addForm = true
|
|
|
|
if addForm
|
|
newForm = form.clone()
|
|
newForm.appendTo row.next().find(targetContent)
|
|
|
|
# show the form
|
|
@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.
|
|
###
|
|
removeDiscussionNoteForm: (form)->
|
|
row = form.closest("tr")
|
|
|
|
form.find(".js-note-text").data("autosave").reset()
|
|
|
|
# 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)
|
|
|
|
###
|
|
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()
|
|
|
|
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')
|
|
|
|
initTaskList: ->
|
|
@enableTaskList()
|
|
$(document).on 'tasklist:changed', '.note .js-task-list-container', @updateTaskList
|
|
|
|
enableTaskList: ->
|
|
$('.note .js-task-list-container').taskList('enable')
|
|
|
|
updateTaskList: ->
|
|
$('form', this).submit()
|