summaryrefslogtreecommitdiff
path: root/app/assets/javascripts
diff options
context:
space:
mode:
authorFatih Acet <acetfatih@gmail.com>2016-05-23 23:08:00 +0300
committerFatih Acet <acetfatih@gmail.com>2016-05-23 23:08:00 +0300
commitaa2a7dad59c0db8b15aadbb58a861237a36c95ee (patch)
treed55ab82ba5c5195b003f9b29c2c17646fffbdae6 /app/assets/javascripts
parentb99471ca5de6e867c44ea21bf85252cd174ccec7 (diff)
parentc002a560afae7db6a5c778bc78028243c2fc945a (diff)
downloadgitlab-ce-aa2a7dad59c0db8b15aadbb58a861237a36c95ee.tar.gz
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into #15643
# Conflicts: # app/assets/stylesheets/pages/issuable.scss
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/api.js.coffee35
-rw-r--r--app/assets/javascripts/blob/blob_gitignore_selector.js.coffee58
-rw-r--r--app/assets/javascripts/blob/edit_blob.js.coffee1
-rw-r--r--app/assets/javascripts/ci/build.coffee21
-rw-r--r--app/assets/javascripts/due_date_select.js.coffee35
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.coffee19
-rw-r--r--app/assets/javascripts/gl_dropdown.js.coffee82
-rw-r--r--app/assets/javascripts/issuable_form.js.coffee9
-rw-r--r--app/assets/javascripts/lib/type_utility.js.coffee9
-rw-r--r--app/assets/javascripts/merge_request_widget.js.coffee4
-rw-r--r--app/assets/javascripts/notes.js.coffee2
-rw-r--r--app/assets/javascripts/user_tabs.js.coffee9
12 files changed, 236 insertions, 48 deletions
diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee
index dd1bbb37551..3f61ea1eaf4 100644
--- a/app/assets/javascripts/api.js.coffee
+++ b/app/assets/javascripts/api.js.coffee
@@ -1,14 +1,15 @@
@Api =
- groups_path: "/api/:version/groups.json"
- group_path: "/api/:version/groups/:id.json"
- namespaces_path: "/api/:version/namespaces.json"
- group_projects_path: "/api/:version/groups/:id/projects.json"
- projects_path: "/api/:version/projects.json"
- labels_path: "/api/:version/projects/:id/labels"
- license_path: "/api/:version/licenses/:key"
+ groupsPath: "/api/:version/groups.json"
+ groupPath: "/api/:version/groups/:id.json"
+ namespacesPath: "/api/:version/namespaces.json"
+ groupProjectsPath: "/api/:version/groups/:id/projects.json"
+ projectsPath: "/api/:version/projects.json"
+ labelsPath: "/api/:version/projects/:id/labels"
+ licensePath: "/api/:version/licenses/:key"
+ gitignorePath: "/api/:version/gitignores/:key"
group: (group_id, callback) ->
- url = Api.buildUrl(Api.group_path)
+ url = Api.buildUrl(Api.groupPath)
url = url.replace(':id', group_id)
$.ajax(
@@ -22,7 +23,7 @@
# Return groups list. Filtered by query
# Only active groups retrieved
groups: (query, skip_ldap, callback) ->
- url = Api.buildUrl(Api.groups_path)
+ url = Api.buildUrl(Api.groupsPath)
$.ajax(
url: url
@@ -36,7 +37,7 @@
# Return namespaces list. Filtered by query
namespaces: (query, callback) ->
- url = Api.buildUrl(Api.namespaces_path)
+ url = Api.buildUrl(Api.namespacesPath)
$.ajax(
url: url
@@ -50,7 +51,7 @@
# Return projects list. Filtered by query
projects: (query, order, callback) ->
- url = Api.buildUrl(Api.projects_path)
+ url = Api.buildUrl(Api.projectsPath)
$.ajax(
url: url
@@ -64,7 +65,7 @@
callback(projects)
newLabel: (project_id, data, callback) ->
- url = Api.buildUrl(Api.labels_path)
+ url = Api.buildUrl(Api.labelsPath)
url = url.replace(':id', project_id)
data.private_token = gon.api_token
@@ -80,7 +81,7 @@
# Return group projects list. Filtered by query
groupProjects: (group_id, query, callback) ->
- url = Api.buildUrl(Api.group_projects_path)
+ url = Api.buildUrl(Api.groupProjectsPath)
url = url.replace(':id', group_id)
$.ajax(
@@ -95,7 +96,7 @@
# Return text for a specific license
licenseText: (key, data, callback) ->
- url = Api.buildUrl(Api.license_path).replace(':key', key)
+ url = Api.buildUrl(Api.licensePath).replace(':key', key)
$.ajax(
url: url
@@ -103,6 +104,12 @@
).done (license) ->
callback(license)
+ gitignoreText: (key, callback) ->
+ url = Api.buildUrl(Api.gitignorePath).replace(':key', key)
+
+ $.get url, (gitignore) ->
+ callback(gitignore)
+
buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root?
return url.replace(':version', gon.api_version)
diff --git a/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee b/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee
new file mode 100644
index 00000000000..cc8a497d081
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee
@@ -0,0 +1,58 @@
+class @BlobGitignoreSelector
+ constructor: (opts) ->
+ {
+ @dropdown
+ @editor
+ @$wrapper = @dropdown.closest('.gitignore-selector')
+ @$filenameInput = $('#file_name')
+ @data = @dropdown.data('filenames')
+ } = opts
+
+ @dropdown.glDropdown(
+ data: @data,
+ filterable: true,
+ selectable: true,
+ search:
+ fields: ['name']
+ clicked: @onClick
+ text: (gitignore) ->
+ gitignore.name
+ )
+
+ @toggleGitignoreSelector()
+ @bindEvents()
+
+ bindEvents: ->
+ @$filenameInput
+ .on 'keyup blur', (e) =>
+ @toggleGitignoreSelector()
+
+ toggleGitignoreSelector: ->
+ filename = @$filenameInput.val() or $('.editor-file-name').text().trim()
+ @$wrapper.toggleClass 'hidden', filename isnt '.gitignore'
+
+ onClick: (item, el, e) =>
+ e.preventDefault()
+ @requestIgnoreFile(item.name)
+
+ requestIgnoreFile: (name) ->
+ Api.gitignoreText name, @requestIgnoreFileSuccess.bind(@)
+
+ requestIgnoreFileSuccess: (gitignore) ->
+ @editor.setValue(gitignore.content, 1)
+ @editor.focus()
+
+class @BlobGitignoreSelectors
+ constructor: (opts) ->
+ {
+ @$dropdowns = $('.js-gitignore-selector')
+ @editor
+ } = opts
+
+ @$dropdowns.each (i, dropdown) =>
+ $dropdown = $(dropdown)
+
+ new BlobGitignoreSelector(
+ dropdown: $dropdown,
+ editor: @editor
+ )
diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee
index eea9aa972ee..79141e768b8 100644
--- a/app/assets/javascripts/blob/edit_blob.js.coffee
+++ b/app/assets/javascripts/blob/edit_blob.js.coffee
@@ -13,6 +13,7 @@ class @EditBlob
@initModePanesAndLinks()
new BlobLicenseSelector(@editor)
+ new BlobGitignoreSelectors(editor: @editor)
initModePanesAndLinks: ->
@$editModePanes = $(".js-edit-mode-pane")
diff --git a/app/assets/javascripts/ci/build.coffee b/app/assets/javascripts/ci/build.coffee
index 7afe8bf79e2..fca0c3bae5c 100644
--- a/app/assets/javascripts/ci/build.coffee
+++ b/app/assets/javascripts/ci/build.coffee
@@ -1,9 +1,12 @@
class CiBuild
@interval: null
+ @state: null
- constructor: (build_url, build_status) ->
+ constructor: (build_url, build_status, build_state) ->
clearInterval(CiBuild.interval)
+ @state = build_state
+
@initScrollButtonAffix()
if build_status == "running" || build_status == "pending"
@@ -26,14 +29,18 @@ class CiBuild
CiBuild.interval = setInterval =>
if window.location.href.split("#").first() is build_url
$.ajax
- url: build_url
+ url: build_url + "/trace.json?state=" + encodeURIComponent(@state)
dataType: "json"
- success: (build) =>
- if build.status == "running"
- $('#build-trace code').html build.trace_html
- $('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
+ success: (log) =>
+ @state = log.state
+ if log.status is "running"
+ if log.append
+ $('.fa-refresh').before log.html
+ else
+ $('#build-trace code').html log.html
+ $('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
@checkAutoscroll()
- else if build.status != build_status
+ else if log.status isnt build_status
Turbolinks.visit build_url
, 4000
diff --git a/app/assets/javascripts/due_date_select.js.coffee b/app/assets/javascripts/due_date_select.js.coffee
index a4304786cbb..3cc70185178 100644
--- a/app/assets/javascripts/due_date_select.js.coffee
+++ b/app/assets/javascripts/due_date_select.js.coffee
@@ -11,6 +11,7 @@ class @DueDateSelect
$block = $dropdown.closest('.block')
$selectbox = $dropdown.closest('.selectbox')
$value = $block.find('.value')
+ $valueContent = $block.find('.value-content')
$sidebarValue = $('.js-due-date-sidebar-value', $block)
fieldName = $dropdown.data('field-name')
@@ -23,11 +24,15 @@ class @DueDateSelect
$value.removeAttr('style')
)
- addDueDate = ->
+ addDueDate = (isDropdown) ->
# Create the post date
value = $("input[name='#{fieldName}']").val()
- date = new Date value.replace(new RegExp('-', 'g'), ',')
- mediumDate = $.datepicker.formatDate 'M d, yy', date
+
+ if value isnt ''
+ date = new Date value.replace(new RegExp('-', 'g'), ',')
+ mediumDate = $.datepicker.formatDate 'M d, yy', date
+ else
+ mediumDate = 'None'
data = {}
data[abilityName] = {}
@@ -39,23 +44,35 @@ class @DueDateSelect
data: data
beforeSend: ->
$loading.fadeIn()
- $dropdown.trigger('loading.gl.dropdown')
- $selectbox.hide()
+ if isDropdown
+ $dropdown.trigger('loading.gl.dropdown')
+ $selectbox.hide()
$value.removeAttr('style')
- $value.html(mediumDate)
+ $valueContent.html(mediumDate)
$sidebarValue.html(mediumDate)
+
+ if value isnt ''
+ $('.js-remove-due-date-holder').removeClass 'hidden'
+ else
+ $('.js-remove-due-date-holder').addClass 'hidden'
).done (data) ->
- $dropdown.trigger('loaded.gl.dropdown')
- $dropdown.dropdown('toggle')
+ if isDropdown
+ $dropdown.trigger('loaded.gl.dropdown')
+ $dropdown.dropdown('toggle')
$loading.fadeOut()
+ $block.on 'click', '.js-remove-due-date', (e) ->
+ e.preventDefault()
+ $("input[name='#{fieldName}']").val ''
+ addDueDate(false)
+
$datePicker.datepicker(
dateFormat: 'yy-mm-dd',
defaultDate: $("input[name='#{fieldName}']").val()
altField: "input[name='#{fieldName}']"
onSelect: ->
- addDueDate()
+ addDueDate(true)
)
$(document)
diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee
index 61e3f811e73..41dba342107 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.coffee
+++ b/app/assets/javascripts/gfm_auto_complete.js.coffee
@@ -18,6 +18,10 @@ GitLab.GfmAutoComplete =
Issues:
template: '<li><small>${id}</small> ${title}</li>'
+ # Milestones
+ Milestones:
+ template: '<li>${title}</li>'
+
# Add GFM auto-completion to all input fields, that accept GFM input.
setup: (wrap) ->
@input = $('.js-gfm-input')
@@ -82,6 +86,19 @@ GitLab.GfmAutoComplete =
search: "#{i.iid} #{i.title}"
@input.atwho
+ at: '%'
+ alias: 'milestones'
+ searchKey: 'search'
+ displayTpl: @Milestones.template
+ insertTpl: '${atwho-at}"${title}"'
+ callbacks:
+ beforeSave: (milestones) ->
+ $.map milestones, (m) ->
+ id: m.iid
+ title: sanitize(m.title)
+ search: "#{m.title}"
+
+ @input.atwho
at: '!'
alias: 'mergerequests'
searchKey: 'search'
@@ -105,6 +122,8 @@ GitLab.GfmAutoComplete =
@input.atwho 'load', '@', data.members
# load issues
@input.atwho 'load', 'issues', data.issues
+ # load milestones
+ @input.atwho 'load', 'milestones', data.milestones
# load merge requests
@input.atwho 'load', 'mergerequests', data.mergerequests
# load emojis
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index 1d1bfeb2e77..b3f1dc969b8 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -60,9 +60,36 @@ class GitLabDropdownFilter
results = data
if search_text isnt ''
- results = fuzzaldrinPlus.filter(data, search_text,
- key: @options.keys
- )
+ # When data is an array of objects therefore [object Array] e.g.
+ # [
+ # { prop: 'foo' },
+ # { prop: 'baz' }
+ # ]
+ if _.isArray(data)
+ results = fuzzaldrinPlus.filter(data, search_text,
+ key: @options.keys
+ )
+ else
+ # If data is grouped therefore an [object Object]. e.g.
+ # {
+ # groupName1: [
+ # { prop: 'foo' },
+ # { prop: 'baz' }
+ # ],
+ # groupName2: [
+ # { prop: 'abc' },
+ # { prop: 'def' }
+ # ]
+ # }
+ if gl.utils.isObject data
+ results = {}
+ for key, group of data
+ tmp = fuzzaldrinPlus.filter(group, search_text,
+ key: @options.keys
+ )
+
+ if tmp.length
+ results[key] = tmp.map (item) -> item
@options.callback results
else
@@ -141,8 +168,9 @@ class GitLabDropdown
searchFields = if @options.search then @options.search.fields else [];
if @options.data
- # If data is an array
- if _.isArray @options.data
+ # If we provided data
+ # data could be an array of objects or a group of arrays
+ if _.isObject(@options.data) and not _.isFunction(@options.data)
@fullData = @options.data
@parseData @options.data
else
@@ -230,19 +258,33 @@ class GitLabDropdown
parseData: (data) ->
@renderedData = data
- # Render each row
- html = $.map data, (obj) =>
- return @renderItem(obj)
-
if @options.filterable and data.length is 0
# render no matching results
html = [@noResults()]
+ else
+ # Handle array groups
+ if gl.utils.isObject data
+ html = []
+ for name, groupData of data
+ # Add header for each group
+ html.push(@renderItem(header: name, name))
+
+ @renderData(groupData, name)
+ .map (item) ->
+ html.push item
+ else
+ # Render each row
+ html = @renderData(data)
# Render the full menu
full_html = @renderMenu(html.join(""))
@appendMenu(full_html)
+ renderData: (data, group = false) ->
+ data.map (obj, index) =>
+ return @renderItem(obj, group, index)
+
shouldPropagate: (e) =>
if @options.multiSelect
$target = $(e.target)
@@ -299,11 +341,10 @@ class GitLabDropdown
selector = '.dropdown-content'
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content"
-
$(selector, @dropdown).html html
# Render the row
- renderItem: (data) ->
+ renderItem: (data, group = false, index = false) ->
html = ""
# Divider
@@ -346,8 +387,13 @@ class GitLabDropdown
if @highlight
text = @highlightTextMatches(text, @filterInput.val())
+ if group
+ groupAttrs = "data-group='#{group}' data-index='#{index}'"
+ else
+ groupAttrs = ''
+
html = "<li>
- <a href='#{url}' class='#{cssClass}'>
+ <a href='#{url}' #{groupAttrs} class='#{cssClass}'>
#{text}
</a>
</li>"
@@ -377,9 +423,15 @@ class GitLabDropdown
rowClicked: (el) ->
fieldName = @options.fieldName
- selectedIndex = el.parent().index()
if @renderedData
- selectedObject = @renderedData[selectedIndex]
+ groupName = el.data('group')
+ if groupName
+ selectedIndex = el.data('index')
+ selectedObject = @renderedData[groupName][selectedIndex]
+ else
+ selectedIndex = el.closest('li').index()
+ selectedObject = @renderedData[selectedIndex]
+
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
if el.hasClass(ACTIVE_CLASS)
@@ -460,7 +512,7 @@ class GitLabDropdown
return false
if currentKeyCode is 13
- @selectRowAtIndex currentIndex
+ @selectRowAtIndex if currentIndex < 0 then 0 else currentIndex
removeArrayKeyEvent: ->
$('body').off 'keydown'
diff --git a/app/assets/javascripts/issuable_form.js.coffee b/app/assets/javascripts/issuable_form.js.coffee
index 7a788f761b7..72ae3bde81e 100644
--- a/app/assets/javascripts/issuable_form.js.coffee
+++ b/app/assets/javascripts/issuable_form.js.coffee
@@ -20,6 +20,15 @@ class @IssuableForm
@initWip()
+ $issuableDueDate = $('#issuable-due-date')
+
+ if $issuableDueDate.length
+ $('.datepicker').datepicker(
+ dateFormat: 'yy-mm-dd',
+ onSelect: (dateText, inst) ->
+ $issuableDueDate.val dateText
+ ).datepicker 'setDate', $.datepicker.parseDate('yy-mm-dd', $issuableDueDate.val())
+
initAutosave: ->
new Autosave @titleField, [
document.location.pathname,
diff --git a/app/assets/javascripts/lib/type_utility.js.coffee b/app/assets/javascripts/lib/type_utility.js.coffee
new file mode 100644
index 00000000000..957f0d86b36
--- /dev/null
+++ b/app/assets/javascripts/lib/type_utility.js.coffee
@@ -0,0 +1,9 @@
+((w) ->
+
+ w.gl ?= {}
+ w.gl.utils ?= {}
+
+ w.gl.utils.isObject = (obj) ->
+ obj? and (obj.constructor is Object)
+
+) window
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index f58647988a2..b6d590f681c 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -113,7 +113,7 @@ class @MergeRequestWidget
switch state
when "failed", "canceled", "not_found"
@setMergeButtonClass('btn-danger')
- when "running", "pending"
+ when "running"
@setMergeButtonClass('btn-warning')
when "success"
@setMergeButtonClass('btn-create')
@@ -126,6 +126,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
- $('.accept_merge_request')
+ $('.js-merge-button')
.removeClass('btn-danger btn-warning btn-create')
.addClass(css_class)
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index efb3e8e2198..6d9d6528f45 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -285,6 +285,7 @@ class @Notes
form.addClass "js-main-target-form"
form.find("#note_line_code").remove()
+ form.find("#note_type").remove()
###
General note form setup.
@@ -472,6 +473,7 @@ class @Notes
setupDiscussionNoteForm: (dataHolder, form) =>
# setup note target
form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
+ form.find("#note_type").val dataHolder.data("noteType")
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")
diff --git a/app/assets/javascripts/user_tabs.js.coffee b/app/assets/javascripts/user_tabs.js.coffee
index c2aeffe2381..70614396a4e 100644
--- a/app/assets/javascripts/user_tabs.js.coffee
+++ b/app/assets/javascripts/user_tabs.js.coffee
@@ -26,6 +26,10 @@
# Personal projects
# </a>
# </li>
+# <li class="snippets-tab">
+# <a data-action="snippets" data-target="#snippets" data-toggle="tab" href="/u/username/snippets">
+# </a>
+# </li>
# </ul>
#
# <div class="tab-content">
@@ -41,6 +45,9 @@
# <div class="tab-pane" id="projects">
# Projects content
# </div>
+# <div class="tab-pane" id="snippets">
+# Snippets content
+# </div>
# </div>
#
# <div class="loading-status">
@@ -100,7 +107,7 @@ class @UserTabs
if action is 'activity'
@loadActivities(source)
- if action in ['groups', 'contributed', 'projects']
+ if action in ['groups', 'contributed', 'projects', 'snippets']
@loadTab(source, action)
loadTab: (source, action) ->