Commit 923bd2ecd28f633ef7e5a789ba3889a550cf45c7

Authored by Dmitriy Zaporozhets
1 parent f7e7dc7e

Write new Notes coffee class to handle comments

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Showing 1 changed file with 397 additions and 0 deletions   Show diff stats
app/assets/javascripts/notes.js.coffee 0 → 100644
... ... @@ -0,0 +1,397 @@
  1 +class Notes
  2 + constructor: (notes_url, note_ids) ->
  3 + @notes_url = notes_url
  4 + @notes_url = gon.relative_url_root + @notes_url if gon.relative_url_root?
  5 + @note_ids = note_ids
  6 + @initRefresh()
  7 + @setupMainTargetNoteForm()
  8 + @cleanBinding()
  9 + @addBinding()
  10 +
  11 + addBinding: ->
  12 + # add note to UI after creation
  13 + $(document).on "ajax:success", ".js-main-target-form", @addNote
  14 + $(document).on "ajax:success", ".js-discussion-note-form", @addDiscussionNote
  15 +
  16 + # change note in UI after update
  17 + $(document).on "ajax:success", "form.edit_note", @updateNote
  18 +
  19 + # Edit note link
  20 + $(document).on "click", ".js-note-edit", @showEditForm
  21 + $(document).on "click", ".note-edit-cancel", @cancelEdit
  22 +
  23 + # remove a note (in general)
  24 + $(document).on "click", ".js-note-delete", @removeNote
  25 +
  26 + # delete note attachment
  27 + $(document).on "click", ".js-note-attachment-delete", @removeAttachment
  28 +
  29 + # Preview button
  30 + $(document).on "click", ".js-note-preview-button", @previewNote
  31 +
  32 + # reset main target form after submit
  33 + $(document).on "ajax:complete", ".js-main-target-form", @resetMainTargetForm
  34 +
  35 + # attachment button
  36 + $(document).on "click", ".js-choose-note-attachment-button", @chooseNoteAttachment
  37 +
  38 + # reply to diff/discussion notes
  39 + $(document).on "click", ".js-discussion-reply-button", @replyToDiscussionNote
  40 +
  41 + # add diff note
  42 + $(document).on "click", ".js-add-diff-note-button", @addDiffNote
  43 +
  44 + cleanBinding: ->
  45 + $(document).off "ajax:success", ".js-main-target-form"
  46 + $(document).off "ajax:success", ".js-discussion-note-form"
  47 + $(document).off "ajax:success", "form.edit_note"
  48 + $(document).off "click", ".js-note-edit"
  49 + $(document).off "click", ".note-edit-cancel"
  50 + $(document).off "click", ".js-note-delete"
  51 + $(document).off "click", ".js-note-attachment-delete"
  52 + $(document).off "click", ".js-note-preview-button"
  53 + $(document).off "ajax:complete", ".js-main-target-form"
  54 + $(document).off "click", ".js-choose-note-attachment-button"
  55 + $(document).off "click", ".js-discussion-reply-button"
  56 + $(document).off "click", ".js-add-diff-note-button"
  57 +
  58 +
  59 + initRefresh: ->
  60 + setInterval =>
  61 + @refresh()
  62 + , 15000
  63 +
  64 + refresh: ->
  65 + @getContent()
  66 +
  67 + getContent: ->
  68 + $.ajax
  69 + url: @notes_url
  70 + dataType: "json"
  71 + success: (data) =>
  72 + notes = data.notes
  73 + $.each notes, (i, note) =>
  74 + # render note if it not present in loaded list
  75 + # or skip if rendered
  76 + if $.inArray(note.id, @note_ids) == -1
  77 + @note_ids.push(note.id)
  78 + @renderNote(note)
  79 +
  80 +
  81 + ###
  82 + Render note in main comments area.
  83 +
  84 + Note: for rendering inline notes use renderDiscussionNote
  85 + ###
  86 + renderNote: (note) ->
  87 + $('ul.main-notes-list').append(note.html)
  88 +
  89 + ###
  90 + Render note in discussion area.
  91 +
  92 + Note: for rendering inline notes use renderDiscussionNote
  93 + ###
  94 + renderDiscussionNote: (note) ->
  95 + form = $("form[rel='" + note.discussion_id + "']")
  96 + row = form.closest("tr")
  97 +
  98 + # is this the first note of discussion?
  99 + if row.is(".js-temp-notes-holder")
  100 + # insert the note and the reply button after the temp row
  101 + row.after note.discussion_html
  102 +
  103 + # remove the note (will be added again below)
  104 + row.next().find(".note").remove()
  105 +
  106 + # append new note to all matching discussions
  107 + $(".notes[rel='" + note.discussion_id + "']").append note.html
  108 +
  109 + # cleanup after successfully creating a diff/discussion note
  110 + @removeDiscussionNoteForm(form)
  111 +
  112 + ###
  113 + Shows the note preview.
  114 +
  115 + Lets the server render GFM into Html and displays it.
  116 +
  117 + Note: uses the Toggler behavior to toggle preview/edit views/buttons
  118 + ###
  119 + previewNote: (e) ->
  120 + e.preventDefault()
  121 + form = $(this).closest("form")
  122 + preview = form.find(".js-note-preview")
  123 + noteText = form.find(".js-note-text").val()
  124 + if noteText.trim().length is 0
  125 + preview.text "Nothing to preview."
  126 + else
  127 + preview.text "Loading..."
  128 + $.post($(this).data("url"),
  129 + note: noteText
  130 + ).success (previewData) ->
  131 + preview.html previewData
  132 +
  133 + ###
  134 + Called in response the main target form has been successfully submitted.
  135 +
  136 + Removes any errors.
  137 + Resets text and preview.
  138 + Resets buttons.
  139 + ###
  140 + resetMainTargetForm: ->
  141 + form = $(".js-main-target-form")
  142 +
  143 + # remove validation errors
  144 + form.find(".js-errors").remove()
  145 +
  146 + # reset text and preview
  147 + previewContainer = form.find(".js-toggler-container.note_text_and_preview")
  148 + previewContainer.removeClass "on" if previewContainer.is(".on")
  149 + form.find(".js-note-text").val("").trigger "input"
  150 +
  151 + ###
  152 + Called when clicking the "Choose File" button.
  153 +
  154 + Opens the file selection dialog.
  155 + ###
  156 + chooseNoteAttachment: ->
  157 + form = $(this).closest("form")
  158 + form.find(".js-note-attachment-input").click()
  159 +
  160 + ###
  161 + Shows the main form and does some setup on it.
  162 +
  163 + Sets some hidden fields in the form.
  164 + ###
  165 + setupMainTargetNoteForm: ->
  166 +
  167 + # find the form
  168 + form = $(".js-new-note-form")
  169 +
  170 + # insert the form after the button
  171 + form.clone().replaceAll $(".js-main-target-form")
  172 + form = form.prev("form")
  173 +
  174 + # show the form
  175 + @setupNoteForm(form)
  176 +
  177 + # fix classes
  178 + form.removeClass "js-new-note-form"
  179 + form.addClass "js-main-target-form"
  180 +
  181 + # remove unnecessary fields and buttons
  182 + form.find("#note_line_code").remove()
  183 + form.find(".js-close-discussion-note-form").remove()
  184 +
  185 + ###
  186 + General note form setup.
  187 +
  188 + deactivates the submit button when text is empty
  189 + hides the preview button when text is empty
  190 + setup GFM auto complete
  191 + show the form
  192 + ###
  193 + setupNoteForm: (form) ->
  194 + disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button")
  195 + form.removeClass "js-new-note-form"
  196 +
  197 + # setup preview buttons
  198 + form.find(".js-note-edit-button, .js-note-preview-button").tooltip placement: "left"
  199 + previewButton = form.find(".js-note-preview-button")
  200 + form.find(".js-note-text").on "input", ->
  201 + if $(this).val().trim() isnt ""
  202 + previewButton.removeClass("turn-off").addClass "turn-on"
  203 + else
  204 + previewButton.removeClass("turn-on").addClass "turn-off"
  205 +
  206 +
  207 + # remove notify commit author checkbox for non-commit notes
  208 + form.find(".js-notify-commit-author").remove() if form.find("#note_noteable_type").val() isnt "Commit"
  209 + GitLab.GfmAutoComplete.setup()
  210 + form.show()
  211 +
  212 +
  213 + ###
  214 + Called in response to the new note form being submitted
  215 +
  216 + Adds new note to list.
  217 + ###
  218 + addNote: (xhr, note, status) =>
  219 + @note_ids.push(note.id)
  220 + @renderNote(note)
  221 +
  222 + ###
  223 + Called in response to the new note form being submitted
  224 +
  225 + Adds new note to list.
  226 + ###
  227 + addDiscussionNote: (xhr, note, status) =>
  228 + @note_ids.push(note.id)
  229 + @renderDiscussionNote(note)
  230 +
  231 + ###
  232 + Called in response to the edit note form being submitted
  233 +
  234 + Updates the current note field.
  235 + ###
  236 + updateNote: (xhr, note, status) =>
  237 + note_li = $("#note_" + note.id)
  238 + note_li.replaceWith(note.html)
  239 +
  240 + ###
  241 + Called in response to clicking the edit note link
  242 +
  243 + Replaces the note text with the note edit form
  244 + Adds a hidden div with the original content of the note to fill the edit note form with
  245 + if the user cancels
  246 + ###
  247 + showEditForm: (e) ->
  248 + e.preventDefault()
  249 + note = $(this).closest(".note")
  250 + note.find(".note-text").hide()
  251 +
  252 + # Show the attachment delete link
  253 + note.find(".js-note-attachment-delete").show()
  254 + GitLab.GfmAutoComplete.setup()
  255 + form = note.find(".note-edit-form")
  256 + form.show()
  257 + form.find("textarea").focus()
  258 +
  259 + ###
  260 + Called in response to clicking the edit note link
  261 +
  262 + Hides edit form
  263 + ###
  264 + cancelEdit: (e) ->
  265 + e.preventDefault()
  266 + note = $(this).closest(".note")
  267 + note.find(".note-text").show()
  268 + note.find(".js-note-attachment-delete").hide()
  269 + note.find(".note-edit-form").hide()
  270 +
  271 + ###
  272 + Called in response to deleting a note of any kind.
  273 +
  274 + Removes the actual note from view.
  275 + Removes the whole discussion if the last note is being removed.
  276 + ###
  277 + removeNote: ->
  278 + note = $(this).closest(".note")
  279 + notes = note.closest(".notes")
  280 +
  281 + # check if this is the last note for this line
  282 + if notes.find(".note").length is 1
  283 +
  284 + # for discussions
  285 + notes.closest(".discussion").remove()
  286 +
  287 + # for diff lines
  288 + notes.closest("tr").remove()
  289 +
  290 + note.remove()
  291 +
  292 + ###
  293 + Called in response to clicking the delete attachment link
  294 +
  295 + Removes the attachment wrapper view, including image tag if it exists
  296 + Resets the note editing form
  297 + ###
  298 + removeAttachment: ->
  299 + note = $(this).closest(".note")
  300 + note.find(".note-attachment").remove()
  301 + note.find(".note-text").show()
  302 + note.find(".js-note-attachment-delete").hide()
  303 + note.find(".note-edit-form").hide()
  304 +
  305 + ###
  306 + Called when clicking on the "reply" button for a diff line.
  307 +
  308 + Shows the note form below the notes.
  309 + ###
  310 + replyToDiscussionNote: (e) =>
  311 + form = $(".js-new-note-form")
  312 + replyLink = $(e.target)
  313 + replyLink.hide()
  314 +
  315 + # insert the form after the button
  316 + form.clone().insertAfter replyLink
  317 +
  318 + # show the form
  319 + @setupDiscussionNoteForm(replyLink, replyLink.next("form"))
  320 +
  321 + ###
  322 + Shows the diff or discussion form and does some setup on it.
  323 +
  324 + Sets some hidden fields in the form.
  325 +
  326 + Note: dataHolder must have the "discussionId", "lineCode", "noteableType"
  327 + and "noteableId" data attributes set.
  328 + ###
  329 + setupDiscussionNoteForm: (dataHolder, form) =>
  330 + # setup note target
  331 + form.attr "rel", dataHolder.data("discussionId")
  332 + form.find("#note_commit_id").val dataHolder.data("commitId")
  333 + form.find("#note_line_code").val dataHolder.data("lineCode")
  334 + form.find("#note_noteable_type").val dataHolder.data("noteableType")
  335 + form.find("#note_noteable_id").val dataHolder.data("noteableId")
  336 + @setupNoteForm form
  337 + form.find(".js-note-text").focus()
  338 + form.addClass "js-discussion-note-form"
  339 +
  340 + ###
  341 + General note form setup.
  342 +
  343 + deactivates the submit button when text is empty
  344 + hides the preview button when text is empty
  345 + setup GFM auto complete
  346 + show the form
  347 + ###
  348 + setupNoteForm: (form) =>
  349 + disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button")
  350 + form.removeClass "js-new-note-form"
  351 + form.removeClass "js-new-note-form"
  352 + GitLab.GfmAutoComplete.setup()
  353 + form.show()
  354 +
  355 + ###
  356 + Called when clicking on the "add a comment" button on the side of a diff line.
  357 +
  358 + Inserts a temporary row for the form below the line.
  359 + Sets up the form and shows it.
  360 + ###
  361 + addDiffNote: (e) =>
  362 + e.preventDefault()
  363 + link = e.target
  364 + form = $(".js-new-note-form")
  365 + row = $(link).closest("tr")
  366 + nextRow = row.next()
  367 +
  368 + # does it already have notes?
  369 + if nextRow.is(".notes_holder")
  370 + $.proxy(@replyToDiscussionNote, nextRow.find(".js-discussion-reply-button")).call()
  371 + else
  372 + # add a notes row and insert the form
  373 + row.after "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\" colspan=\"2\"></td><td class=\"notes_content\"></td></tr>"
  374 + form.clone().appendTo row.next().find(".notes_content")
  375 +
  376 + # show the form
  377 + @setupDiscussionNoteForm $(link), row.next().find("form")
  378 +
  379 + ###
  380 + Called in response to "cancel" on a diff note form.
  381 +
  382 + Shows the reply button again.
  383 + Removes the form and if necessary it's temporary row.
  384 + ###
  385 + removeDiscussionNoteForm: (form)->
  386 + row = form.closest("tr")
  387 +
  388 + # show the reply button (will only work for replies)
  389 + form.prev(".js-discussion-reply-button").show()
  390 + if row.is(".js-temp-notes-holder")
  391 + # remove temporary row for diff lines
  392 + row.remove()
  393 + else
  394 + # only remove the form
  395 + form.remove()
  396 +
  397 +@Notes = Notes
... ...