diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee new file mode 100644 index 00000000000..58720cbc3dd --- /dev/null +++ b/app/assets/javascripts/notes.js.coffee @@ -0,0 +1,397 @@ +class Notes + constructor: (notes_url, note_ids) -> + @notes_url = notes_url + @notes_url = gon.relative_url_root + @notes_url if gon.relative_url_root? + @note_ids = note_ids + @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 + + # 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 + + # 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 + + 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 "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" + + + initRefresh: -> + setInterval => + @refresh() + , 15000 + + refresh: -> + @getContent() + + getContent: -> + $.ajax + url: @notes_url + dataType: "json" + success: (data) => + notes = data.notes + $.each notes, (i, note) => + # render note if it not present in loaded list + # or skip if rendered + if $.inArray(note.id, @note_ids) == -1 + @note_ids.push(note.id) + @renderNote(note) + + + ### + Render note in main comments area. + + Note: for rendering inline notes use renderDiscussionNote + ### + renderNote: (note) -> + $('ul.main-notes-list').append(note.html) + + ### + Render note in discussion area. + + Note: for rendering inline notes use renderDiscussionNote + ### + renderDiscussionNote: (note) -> + 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() + + # 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 the note preview. + + Lets the server render GFM into Html and displays it. + + Note: uses the Toggler behavior to toggle preview/edit views/buttons + ### + previewNote: (e) -> + e.preventDefault() + form = $(this).closest("form") + 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 + previewContainer = form.find(".js-toggler-container.note_text_and_preview") + previewContainer.removeClass "on" if previewContainer.is(".on") + 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-edit-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) => + @note_ids.push(note.id) + @renderNote(note) + + ### + Called in response to the new note form being submitted + + Adds new note to list. + ### + addDiscussionNote: (xhr, note, status) => + @note_ids.push(note.id) + @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) + + ### + 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() + form.find("textarea").focus() + + ### + 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) + 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() + 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") + $.proxy(@replyToDiscussionNote, nextRow.find(".js-discussion-reply-button")).call() + else + # add a notes row and insert the form + row.after "