merge_request_tabs.js.coffee 4.5 KB
Newer Older
R
Robert Speicher 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
# MergeRequestTabs
#
# Handles persisting and restoring the current tab selection and lazily-loading
# content on the MergeRequests#show page.
#
# ### Example Markup
#
#   <ul class="nav nav-tabs merge-request-tabs">
#     <li class="notes-tab active">
#       <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1">
#         Discussion
#       </a>
#     </li>
#     <li class="commits-tab">
#       <a data-action="commits" data-target="#commits" data-toggle="tab" href="/foo/bar/merge_requests/1/commits">
#         Commits
#       </a>
#     </li>
#     <li class="diffs-tab">
#       <a data-action="diffs" data-target="#diffs" data-toggle="tab" href="/foo/bar/merge_requests/1/diffs">
#         Diffs
#       </a>
#     </li>
#   </ul>
#
#   <div class="tab-content">
#     <div class="notes tab-pane active" id="notes">
#       Notes Content
#     </div>
#     <div class="commits tab-pane" id="commits">
#       Commits Content
#     </div>
#     <div class="diffs tab-pane" id="diffs">
#       Diffs Content
#     </div>
#   </div>
#
#   <div class="mr-loading-status">
#     <div class="loading">
#       Loading Animation
#     </div>
#   </div>
#
44 45 46 47
class @MergeRequestTabs
  diffsLoaded: false
  commitsLoaded: false

R
Robert Speicher 已提交
48 49 50 51
  constructor: (@opts = {}) ->
    # Store the `location` object, allowing for easier stubbing in tests
    @_location = location

52 53 54
    @bindEvents()
    @activateTab(@opts.action)

55
  bindEvents: ->
R
Robert Speicher 已提交
56
    $(document).on 'shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', @tabShown
57

R
Robert Speicher 已提交
58
  tabShown: (event) =>
59 60 61
    $target = $(event.target)
    action = $target.data('action')

R
Robert Speicher 已提交
62 63 64 65
    if action == 'commits'
      @loadCommits($target.attr('href'))
    else if action == 'diffs'
      @loadDiff($target.attr('href'))
66 67 68

    @setCurrentAction(action)

V
Valery Sizov 已提交
69 70 71
  scrollToElement: (container) ->
    if window.location.hash
      top = $(container + " " + window.location.hash).offset().top
72
      $('body').scrollTo(top)
V
Valery Sizov 已提交
73

R
Robert Speicher 已提交
74 75 76 77
  # Activate a tab based on the current action
  activateTab: (action) ->
    action = 'notes' if action == 'show'
    $(".merge-request-tabs a[data-action='#{action}']").tab('show')
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

  # Replaces the current Merge Request-specific action in the URL with a new one
  #
  # If the action is "notes", the URL is reset to the standard
  # `MergeRequests#show` route.
  #
  # Examples:
  #
  #   location.pathname # => "/namespace/project/merge_requests/1"
  #   setCurrentAction('diffs')
  #   location.pathname # => "/namespace/project/merge_requests/1/diffs"
  #
  #   location.pathname # => "/namespace/project/merge_requests/1/diffs"
  #   setCurrentAction('notes')
  #   location.pathname # => "/namespace/project/merge_requests/1"
  #
  #   location.pathname # => "/namespace/project/merge_requests/1/diffs"
  #   setCurrentAction('commits')
  #   location.pathname # => "/namespace/project/merge_requests/1/commits"
R
Robert Speicher 已提交
97 98 99
  #
  # Returns the new URL String
  setCurrentAction: (action) =>
100 101 102 103
    # Normalize action, just to be safe
    action = 'notes' if action == 'show'

    # Remove a trailing '/commits' or '/diffs'
104
    new_state = @_location.pathname.replace(/\/(commits|diffs)(\.html)?\/?$/, '')
105 106 107 108 109 110

    # Append the new action if we're on a tab other than 'notes'
    unless action == 'notes'
      new_state += "/#{action}"

    # Ensure parameters and hash come along for the ride
R
Robert Speicher 已提交
111
    new_state += @_location.search + @_location.hash
112 113 114 115 116 117 118

    # Replace the current history state with the new one without breaking
    # Turbolinks' history.
    #
    # See https://github.com/rails/turbolinks/issues/363
    history.replaceState {turbolinks: true, url: new_state}, document.title, new_state

R
Robert Speicher 已提交
119 120 121 122 123 124 125
    new_state

  loadCommits: (source) ->
    return if @commitsLoaded

    @_get
      url: "#{source}.json"
126 127 128
      success: (data) =>
        document.getElementById('commits').innerHTML = data.html
        $('.js-timeago').timeago()
R
Robert Speicher 已提交
129
        @commitsLoaded = true
V
Valery Sizov 已提交
130
        @scrollToElement(".commits")
131

R
Robert Speicher 已提交
132 133 134 135
  loadDiff: (source) ->
    return if @diffsLoaded

    @_get
136
      url: "#{source}.json" + @_location.search
137 138
      success: (data) =>
        document.getElementById('diffs').innerHTML = data.html
R
Robert Speicher 已提交
139
        @diffsLoaded = true
V
Valery Sizov 已提交
140
        @scrollToElement(".diffs")
141

142 143 144 145 146
  # Show or hide the loading spinner
  #
  # status - Boolean, true to show, false to hide
  toggleLoading: (status) ->
    $('.mr-loading-status .loading').toggle(status)
R
Robert Speicher 已提交
147 148 149

  _get: (options) ->
    defaults = {
150 151
      beforeSend: => @toggleLoading(true)
      complete:   => @toggleLoading(false)
R
Robert Speicher 已提交
152 153 154 155 156 157 158
      dataType: 'json'
      type: 'GET'
    }

    options = $.extend({}, defaults, options)

    $.ajax(options)