Upstream version 8.12.1+dfsg1
-----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJX7JXDAAoJEM4fnGdFEsIq9ZkP/3RumUYdMPcFkpQjSLQB2MEg cYlm3KyHbO7vjr4lZMcgPTKm7Qa5WCzu3vgLulrS/3F68pP6ZlWM3BzDXeKCWMV7 hH4W21cJPiN12jzYy9lxDZoygFXrV6qSJb808GZIvCg8SF8b7jxbo9ZCkU6MsEVm 8J29L32mmKISwW/HA2ZTkqzsXkjEtoyreS1ABFGvUvo7tVzn3e3VKvKwJLfCKFc0 LQlFndxg22GISRAlSsywG37Ojto5ZwWrLXHYySFhShZHN27xdRyotU7DlEyKY9TS 25H7QCZtDOOXKL3IaAr6Znm9x9a6loQ/Uy7wny38GhY2uDfgmZ4BAA0GuFNd099o zGfEJjeUqFk6FwyK7hJNkPNAF+5ePnCdehbRUDVeaqDX74oCszKCOqgHAVakrpDP SGBASO2E3WLMIt7DcPq5WJ3N+n/OCsXEh4OZ0NyKZl4u+uOWb2SnVvJTLL42COA/ Q8YmiqB7x9topdcw/JWPXdp8JlrZBca5KTRc1GtqvA+bxARJQTNv1ocKsMUBIHs5 qzflDJXbJG171OHVKL9D2qUCwz8jtS56dGowEJNHvk2tOfL6VNpkyOVxiQjJ01Ba iZOnepW4tFsIaWb5poQcpuOuvK9HBbX49HtHEe0irflB+rWEfMnI4Nyq8iDBkUg2 Vavm9AgSI7upscQKNIoN =4D1W -----END PGP SIGNATURE----- Merge tag 'upstream/8.12.1+dfsg1' Upstream version 8.12.1+dfsg1 # gpg: Signature made Thursday 29 September 2016 09:47:07 AM IST using RSA key ID CE1F9C674512C22A # gpg: Good signature from "Praveen Arimbrathodiyil (piratepin) <praveen@debian.org>" [ultimate] # gpg: aka "Pirate Praveen (pirates.org.in) <praveen@onenetbeyond.org>" [ultimate] # gpg: aka "Pirate Praveen (piratesin) <me@j4v4m4n.in>" [ultimate] # gpg: aka "Pirate Praveen (PP) <praveen@privacyrequired.com>" [ultimate] # gpg: aka "Praveen Arimbrathodiyil (j4v4m4n) <pravi.a@gmail.com>" [ultimate]
This commit is contained in:
commit
48a8cbd0b0
1096 changed files with 26288 additions and 9715 deletions
|
@ -1 +1,2 @@
|
||||||
*.erb
|
*.erb
|
||||||
|
lib/gitlab/sanitizers/svg/whitelist.rb
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -48,3 +48,4 @@
|
||||||
/vendor/bundle/*
|
/vendor/bundle/*
|
||||||
/builds/*
|
/builds/*
|
||||||
/shared/*
|
/shared/*
|
||||||
|
/.gitlab_workhorse_secret
|
||||||
|
|
|
@ -82,7 +82,7 @@ update-knapsack:
|
||||||
- export KNAPSACK_REPORT_PATH=knapsack/rspec_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
|
- export KNAPSACK_REPORT_PATH=knapsack/rspec_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
|
||||||
- export KNAPSACK_GENERATE_REPORT=true
|
- export KNAPSACK_GENERATE_REPORT=true
|
||||||
- cp knapsack/rspec_report.json ${KNAPSACK_REPORT_PATH}
|
- cp knapsack/rspec_report.json ${KNAPSACK_REPORT_PATH}
|
||||||
- knapsack rspec
|
- knapsack rspec "--color --format documentation"
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 31d
|
expire_in: 31d
|
||||||
paths:
|
paths:
|
||||||
|
@ -206,10 +206,15 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
|
||||||
- bundle exec $CI_BUILD_NAME
|
- bundle exec $CI_BUILD_NAME
|
||||||
|
|
||||||
rubocop: *exec
|
rubocop: *exec
|
||||||
|
rake haml_lint: *exec
|
||||||
rake scss_lint: *exec
|
rake scss_lint: *exec
|
||||||
rake brakeman: *exec
|
rake brakeman: *exec
|
||||||
rake flog: *exec
|
rake flog:
|
||||||
rake flay: *exec
|
<<: *exec
|
||||||
|
allow_failure: yes
|
||||||
|
rake flay:
|
||||||
|
<<: *exec
|
||||||
|
allow_failure: yes
|
||||||
license_finder: *exec
|
license_finder: *exec
|
||||||
rake downtime_check: *exec
|
rake downtime_check: *exec
|
||||||
|
|
||||||
|
@ -248,6 +253,21 @@ bundler:audit:
|
||||||
script:
|
script:
|
||||||
- "bundle exec bundle-audit check --update --ignore OSVDB-115941"
|
- "bundle exec bundle-audit check --update --ignore OSVDB-115941"
|
||||||
|
|
||||||
|
migration paths:
|
||||||
|
stage: test
|
||||||
|
<<: *use-db
|
||||||
|
only:
|
||||||
|
- master@gitlab-org/gitlab-ce
|
||||||
|
script:
|
||||||
|
- git checkout HEAD .
|
||||||
|
- git fetch --tags
|
||||||
|
- git checkout v8.5.9
|
||||||
|
- 'echo test: unix:/var/opt/gitlab/redis/redis.socket > config/resque.yml'
|
||||||
|
- bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}" --retry=3
|
||||||
|
- rake db:drop db:create db:schema:load db:seed_fu
|
||||||
|
- git checkout $CI_BUILD_REF
|
||||||
|
- rake db:migrate
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
stage: post-test
|
stage: post-test
|
||||||
services: []
|
services: []
|
||||||
|
@ -263,7 +283,6 @@ coverage:
|
||||||
- coverage/index.html
|
- coverage/index.html
|
||||||
- coverage/assets/
|
- coverage/assets/
|
||||||
|
|
||||||
|
|
||||||
# Notify slack in the end
|
# Notify slack in the end
|
||||||
|
|
||||||
notify:slack:
|
notify:slack:
|
||||||
|
|
44
.gitlab/issue_templates/Bug.md
Normal file
44
.gitlab/issue_templates/Bug.md
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
(Summarize the bug encountered concisely)
|
||||||
|
|
||||||
|
### Steps to reproduce
|
||||||
|
|
||||||
|
(How one can reproduce the issue - this is very important)
|
||||||
|
|
||||||
|
### Expected behavior
|
||||||
|
|
||||||
|
(What you should see instead)
|
||||||
|
|
||||||
|
### Actual behavior
|
||||||
|
|
||||||
|
(What actually happens)
|
||||||
|
|
||||||
|
### Relevant logs and/or screenshots
|
||||||
|
|
||||||
|
(Paste any relevant logs - please use code blocks (```) to format console output,
|
||||||
|
logs, and code as it's very hard to read otherwise.)
|
||||||
|
|
||||||
|
### Output of checks
|
||||||
|
|
||||||
|
#### Results of GitLab application Check
|
||||||
|
|
||||||
|
(For installations with omnibus-gitlab package run and paste the output of:
|
||||||
|
`sudo gitlab-rake gitlab:check SANITIZE=true`)
|
||||||
|
|
||||||
|
(For installations from source run and paste the output of:
|
||||||
|
`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`)
|
||||||
|
|
||||||
|
(we will only investigate if the tests are passing)
|
||||||
|
|
||||||
|
#### Results of GitLab environment info
|
||||||
|
|
||||||
|
(For installations with omnibus-gitlab package run and paste the output of:
|
||||||
|
`sudo gitlab-rake gitlab:env:info`)
|
||||||
|
|
||||||
|
(For installations from source run and paste the output of:
|
||||||
|
`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
|
||||||
|
|
||||||
|
### Possible fixes
|
||||||
|
|
||||||
|
(If you can, link to the line of code that might be responsible for the problem)
|
7
.gitlab/issue_templates/Feature Proposal.md
Normal file
7
.gitlab/issue_templates/Feature Proposal.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
### Description
|
||||||
|
|
||||||
|
(Include problem, use cases, benefits, and/or goals)
|
||||||
|
|
||||||
|
### Proposal
|
||||||
|
|
||||||
|
### Links / references
|
14
.gitlab/merge_request_templates/Documentation.md
Normal file
14
.gitlab/merge_request_templates/Documentation.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
See the general Documentation guidelines http://docs.gitlab.com/ce/development/doc_styleguide.html.
|
||||||
|
|
||||||
|
## What does this MR do?
|
||||||
|
|
||||||
|
(briefly describe what this MR is about)
|
||||||
|
|
||||||
|
## Moving docs to a new location?
|
||||||
|
|
||||||
|
See the guidelines: http://docs.gitlab.com/ce/development/doc_styleguide.html#changing-document-location
|
||||||
|
|
||||||
|
- [ ] Make sure the old link is not removed and has its contents replaced with a link to the new location.
|
||||||
|
- [ ] Make sure internal links pointing to the document in question are not broken.
|
||||||
|
- [ ] Search and replace any links referring to old docs in GitLab Rails app, specifically under the `app/views/` directory.
|
||||||
|
- [ ] If working on CE, submit an MR to EE with the changes as well.
|
103
.haml-lint.yml
Normal file
103
.haml-lint.yml
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
# Whether to ignore frontmatter at the beginning of HAML documents for
|
||||||
|
# frameworks such as Jekyll/Middleman
|
||||||
|
skip_frontmatter: false
|
||||||
|
exclude:
|
||||||
|
- 'vendor/**/*'
|
||||||
|
- 'spec/**/*'
|
||||||
|
|
||||||
|
linters:
|
||||||
|
AltText:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ClassAttributeWithStaticValue:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ClassesBeforeIds:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ConsecutiveComments:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ConsecutiveSilentScripts:
|
||||||
|
enabled: false
|
||||||
|
max_consecutive: 2
|
||||||
|
|
||||||
|
EmptyObjectReference:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
EmptyScript:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
FinalNewline:
|
||||||
|
enabled: false
|
||||||
|
present: true
|
||||||
|
|
||||||
|
HtmlAttributes:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ImplicitDiv:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
LeadingCommentSpace:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
LineLength:
|
||||||
|
enabled: false
|
||||||
|
max: 80
|
||||||
|
|
||||||
|
MultilinePipe:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
MultilineScript:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ObjectReferenceAttributes:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
RuboCop:
|
||||||
|
enabled: false
|
||||||
|
# These cops are incredibly noisy when it comes to HAML templates, so we
|
||||||
|
# ignore them.
|
||||||
|
ignored_cops:
|
||||||
|
- Lint/BlockAlignment
|
||||||
|
- Lint/EndAlignment
|
||||||
|
- Lint/Void
|
||||||
|
- Metrics/LineLength
|
||||||
|
- Style/AlignParameters
|
||||||
|
- Style/BlockNesting
|
||||||
|
- Style/ElseAlignment
|
||||||
|
- Style/FileName
|
||||||
|
- Style/FinalNewline
|
||||||
|
- Style/FrozenStringLiteralComment
|
||||||
|
- Style/IfUnlessModifier
|
||||||
|
- Style/IndentationWidth
|
||||||
|
- Style/Next
|
||||||
|
- Style/TrailingBlankLines
|
||||||
|
- Style/TrailingWhitespace
|
||||||
|
- Style/WhileUntilModifier
|
||||||
|
|
||||||
|
RubyComments:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
SpaceBeforeScript:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
SpaceInsideHashAttributes:
|
||||||
|
enabled: false
|
||||||
|
style: space
|
||||||
|
|
||||||
|
Indentation:
|
||||||
|
enabled: true
|
||||||
|
character: space # or tab
|
||||||
|
|
||||||
|
TagName:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
TrailingWhitespace:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
UnnecessaryInterpolation:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
UnnecessaryStringOutput:
|
||||||
|
enabled: false
|
12
.pkgr.yml
12
.pkgr.yml
|
@ -3,6 +3,8 @@ group: git
|
||||||
services:
|
services:
|
||||||
- postgres
|
- postgres
|
||||||
before_precompile: ./bin/pkgr_before_precompile.sh
|
before_precompile: ./bin/pkgr_before_precompile.sh
|
||||||
|
env:
|
||||||
|
- SKIP_STORAGE_VALIDATION=true
|
||||||
targets:
|
targets:
|
||||||
debian-7: &wheezy
|
debian-7: &wheezy
|
||||||
build_dependencies:
|
build_dependencies:
|
||||||
|
@ -25,6 +27,16 @@ targets:
|
||||||
- libicu52
|
- libicu52
|
||||||
- libpcre3
|
- libpcre3
|
||||||
- git
|
- git
|
||||||
|
ubuntu-16.04:
|
||||||
|
build_dependencies:
|
||||||
|
- libkrb5-dev
|
||||||
|
- libicu-dev
|
||||||
|
- cmake
|
||||||
|
- pkg-config
|
||||||
|
dependencies:
|
||||||
|
- libicu55
|
||||||
|
- libpcre3
|
||||||
|
- git
|
||||||
centos-6:
|
centos-6:
|
||||||
build_dependencies:
|
build_dependencies:
|
||||||
- krb5-devel
|
- krb5-devel
|
||||||
|
|
|
@ -5,8 +5,8 @@ require:
|
||||||
inherit_from: .rubocop_todo.yml
|
inherit_from: .rubocop_todo.yml
|
||||||
|
|
||||||
AllCops:
|
AllCops:
|
||||||
TargetRubyVersion: 2.1
|
TargetRubyVersion: 2.3
|
||||||
# Cop names are not displayed in offense messages by default. Change behavior
|
# Cop names are not d§splayed in offense messages by default. Change behavior
|
||||||
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names
|
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names
|
||||||
# option.
|
# option.
|
||||||
DisplayCopNames: true
|
DisplayCopNames: true
|
||||||
|
@ -192,6 +192,9 @@ Style/FlipFlop:
|
||||||
Style/For:
|
Style/For:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
|
# Checks if there is a magic comment to enforce string literals
|
||||||
|
Style/FrozenStringLiteralComment:
|
||||||
|
Enabled: false
|
||||||
# Do not introduce global variables.
|
# Do not introduce global variables.
|
||||||
Style/GlobalVars:
|
Style/GlobalVars:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
# This configuration was generated by
|
# This configuration was generated by
|
||||||
# `rubocop --auto-gen-config --exclude-limit 0`
|
# `rubocop --auto-gen-config --exclude-limit 0`
|
||||||
# on 2016-07-13 12:36:08 -0600 using RuboCop version 0.41.2.
|
# on 2016-09-14 15:44:53 -0400 using RuboCop version 0.42.0.
|
||||||
# The point is for the user to remove these configuration records
|
# The point is for the user to remove these configuration records
|
||||||
# one by one as the offenses are removed from the code base.
|
# one by one as the offenses are removed from the code base.
|
||||||
# Note that changes in the inspected code, or installation of new
|
# Note that changes in the inspected code, or installation of new
|
||||||
# versions of RuboCop, may require this file to be generated again.
|
# versions of RuboCop, may require this file to be generated again.
|
||||||
|
|
||||||
# Offense count: 154
|
# Offense count: 158
|
||||||
Lint/AmbiguousRegexpLiteral:
|
Lint/AmbiguousRegexpLiteral:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 43
|
# Offense count: 41
|
||||||
# Configuration parameters: AllowSafeAssignment.
|
# Configuration parameters: AllowSafeAssignment.
|
||||||
Lint/AssignmentInCondition:
|
Lint/AssignmentInCondition:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 14
|
# Offense count: 16
|
||||||
Lint/HandleExceptions:
|
Lint/HandleExceptions:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
@ -23,28 +23,28 @@ Lint/HandleExceptions:
|
||||||
Lint/Loop:
|
Lint/Loop:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 15
|
# Offense count: 16
|
||||||
Lint/ShadowingOuterLocalVariable:
|
Lint/ShadowingOuterLocalVariable:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 3
|
# Offense count: 6
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Lint/StringConversionInInterpolation:
|
Lint/StringConversionInInterpolation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 44
|
# Offense count: 49
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
|
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
|
||||||
Lint/UnusedBlockArgument:
|
Lint/UnusedBlockArgument:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 129
|
# Offense count: 144
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
|
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
|
||||||
Lint/UnusedMethodArgument:
|
Lint/UnusedMethodArgument:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 12
|
# Offense count: 9
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Performance/PushSplat:
|
Performance/PushSplat:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
@ -59,51 +59,51 @@ Performance/RedundantBlockCall:
|
||||||
Performance/RedundantMatch:
|
Performance/RedundantMatch:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 24
|
# Offense count: 27
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: MaxKeyValuePairs.
|
# Configuration parameters: MaxKeyValuePairs.
|
||||||
Performance/RedundantMerge:
|
Performance/RedundantMerge:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 60
|
# Offense count: 61
|
||||||
Rails/OutputSafety:
|
Rails/OutputSafety:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 128
|
# Offense count: 129
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
# SupportedStyles: strict, flexible
|
# SupportedStyles: strict, flexible
|
||||||
Rails/TimeZone:
|
Rails/TimeZone:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 12
|
# Offense count: 15
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: Include.
|
# Configuration parameters: Include.
|
||||||
# Include: app/models/**/*.rb
|
# Include: app/models/**/*.rb
|
||||||
Rails/Validation:
|
Rails/Validation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 217
|
# Offense count: 273
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||||
# SupportedStyles: with_first_parameter, with_fixed_indentation
|
# SupportedStyles: with_first_parameter, with_fixed_indentation
|
||||||
Style/AlignParameters:
|
Style/AlignParameters:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 32
|
# Offense count: 30
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
# SupportedStyles: always, conditionals
|
# SupportedStyles: always, conditionals
|
||||||
Style/AndOr:
|
Style/AndOr:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 47
|
# Offense count: 50
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
# SupportedStyles: percent_q, bare_percent
|
# SupportedStyles: percent_q, bare_percent
|
||||||
Style/BarePercentLiterals:
|
Style/BarePercentLiterals:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 258
|
# Offense count: 289
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
# SupportedStyles: braces, no_braces, context_dependent
|
# SupportedStyles: braces, no_braces, context_dependent
|
||||||
|
@ -126,14 +126,14 @@ Style/ColonMethodCall:
|
||||||
Style/CommentAnnotation:
|
Style/CommentAnnotation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 34
|
# Offense count: 33
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly.
|
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly.
|
||||||
# SupportedStyles: assign_to_condition, assign_inside_condition
|
# SupportedStyles: assign_to_condition, assign_inside_condition
|
||||||
Style/ConditionalAssignment:
|
Style/ConditionalAssignment:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 789
|
# Offense count: 881
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
# SupportedStyles: leading, trailing
|
# SupportedStyles: leading, trailing
|
||||||
|
@ -144,11 +144,12 @@ Style/DotPosition:
|
||||||
Style/DoubleNegation:
|
Style/DoubleNegation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 3
|
# Offense count: 4
|
||||||
|
# Cop supports --auto-correct.
|
||||||
Style/EachWithObject:
|
Style/EachWithObject:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 30
|
# Offense count: 25
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
# SupportedStyles: empty, nil, both
|
# SupportedStyles: empty, nil, both
|
||||||
|
@ -160,7 +161,7 @@ Style/EmptyElse:
|
||||||
Style/EmptyLiteral:
|
Style/EmptyLiteral:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 123
|
# Offense count: 135
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
|
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
|
||||||
Style/ExtraSpacing:
|
Style/ExtraSpacing:
|
||||||
|
@ -172,16 +173,16 @@ Style/ExtraSpacing:
|
||||||
Style/FormatString:
|
Style/FormatString:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 48
|
# Offense count: 51
|
||||||
# Configuration parameters: MinBodyLength.
|
# Configuration parameters: MinBodyLength.
|
||||||
Style/GuardClause:
|
Style/GuardClause:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 11
|
# Offense count: 9
|
||||||
Style/IfInsideElse:
|
Style/IfInsideElse:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 177
|
# Offense count: 174
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: MaxLineLength.
|
# Configuration parameters: MaxLineLength.
|
||||||
Style/IfUnlessModifier:
|
Style/IfUnlessModifier:
|
||||||
|
@ -194,7 +195,7 @@ Style/IfUnlessModifier:
|
||||||
Style/IndentArray:
|
Style/IndentArray:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 89
|
# Offense count: 97
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||||
# SupportedStyles: special_inside_parentheses, consistent, align_braces
|
# SupportedStyles: special_inside_parentheses, consistent, align_braces
|
||||||
|
@ -208,7 +209,7 @@ Style/IndentHash:
|
||||||
Style/Lambda:
|
Style/Lambda:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 6
|
# Offense count: 5
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/LineEndConcatenation:
|
Style/LineEndConcatenation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
@ -218,17 +219,21 @@ Style/LineEndConcatenation:
|
||||||
Style/MethodCallParentheses:
|
Style/MethodCallParentheses:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 62
|
# Offense count: 8
|
||||||
|
Style/MethodMissing:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# Offense count: 85
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/MutableConstant:
|
Style/MutableConstant:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 10
|
# Offense count: 8
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/NestedParenthesizedCalls:
|
Style/NestedParenthesizedCalls:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 12
|
# Offense count: 13
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
||||||
# SupportedStyles: skip_modifier_ifs, always
|
# SupportedStyles: skip_modifier_ifs, always
|
||||||
|
@ -242,12 +247,19 @@ Style/Next:
|
||||||
Style/NumericLiteralPrefix:
|
Style/NumericLiteralPrefix:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
# Offense count: 64
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
|
# SupportedStyles: predicate, comparison
|
||||||
|
Style/NumericPredicate:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 29
|
# Offense count: 29
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/ParallelAssignment:
|
Style/ParallelAssignment:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 208
|
# Offense count: 264
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: PreferredDelimiters.
|
# Configuration parameters: PreferredDelimiters.
|
||||||
Style/PercentLiteralDelimiters:
|
Style/PercentLiteralDelimiters:
|
||||||
|
@ -265,7 +277,7 @@ Style/PercentQLiterals:
|
||||||
Style/PerlBackrefs:
|
Style/PerlBackrefs:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 32
|
# Offense count: 35
|
||||||
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
|
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
|
||||||
# NamePrefix: is_, has_, have_
|
# NamePrefix: is_, has_, have_
|
||||||
# NamePrefixBlacklist: is_, has_, have_
|
# NamePrefixBlacklist: is_, has_, have_
|
||||||
|
@ -273,7 +285,7 @@ Style/PerlBackrefs:
|
||||||
Style/PredicateName:
|
Style/PredicateName:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 28
|
# Offense count: 27
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/PreferredHashMethods:
|
Style/PreferredHashMethods:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
@ -283,14 +295,14 @@ Style/PreferredHashMethods:
|
||||||
Style/Proc:
|
Style/Proc:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 20
|
# Offense count: 22
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
# SupportedStyles: compact, exploded
|
# SupportedStyles: compact, exploded
|
||||||
Style/RaiseArgs:
|
Style/RaiseArgs:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 3
|
# Offense count: 4
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/RedundantBegin:
|
Style/RedundantBegin:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
@ -300,29 +312,29 @@ Style/RedundantBegin:
|
||||||
Style/RedundantException:
|
Style/RedundantException:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 23
|
# Offense count: 24
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/RedundantFreeze:
|
Style/RedundantFreeze:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 377
|
# Offense count: 408
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/RedundantSelf:
|
Style/RedundantSelf:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 94
|
# Offense count: 93
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
|
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
|
||||||
# SupportedStyles: slashes, percent_r, mixed
|
# SupportedStyles: slashes, percent_r, mixed
|
||||||
Style/RegexpLiteral:
|
Style/RegexpLiteral:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 17
|
# Offense count: 18
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/RescueModifier:
|
Style/RescueModifier:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 2
|
# Offense count: 5
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/SelfAssignment:
|
Style/SelfAssignment:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
@ -339,42 +351,42 @@ Style/SingleLineBlockParams:
|
||||||
Style/SingleLineMethods:
|
Style/SingleLineMethods:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 119
|
# Offense count: 124
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||||
# SupportedStyles: space, no_space
|
# SupportedStyles: space, no_space
|
||||||
Style/SpaceBeforeBlockBraces:
|
Style/SpaceBeforeBlockBraces:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 11
|
# Offense count: 10
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: AllowForAlignment.
|
# Configuration parameters: AllowForAlignment.
|
||||||
Style/SpaceBeforeFirstArg:
|
Style/SpaceBeforeFirstArg:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 130
|
# Offense count: 141
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
|
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
|
||||||
# SupportedStyles: space, no_space
|
# SupportedStyles: space, no_space
|
||||||
Style/SpaceInsideBlockBraces:
|
Style/SpaceInsideBlockBraces:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 98
|
# Offense count: 96
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/SpaceInsideBrackets:
|
Style/SpaceInsideBrackets:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 60
|
# Offense count: 62
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/SpaceInsideParens:
|
Style/SpaceInsideParens:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 5
|
# Offense count: 7
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/SpaceInsidePercentLiteralDelimiters:
|
Style/SpaceInsidePercentLiteralDelimiters:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 36
|
# Offense count: 40
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: SupportedStyles.
|
# Configuration parameters: SupportedStyles.
|
||||||
# SupportedStyles: use_perl_names, use_english_names
|
# SupportedStyles: use_perl_names, use_english_names
|
||||||
|
@ -388,21 +400,28 @@ Style/SpecialGlobalVars:
|
||||||
Style/StringLiteralsInInterpolation:
|
Style/StringLiteralsInInterpolation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 24
|
# Offense count: 32
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: IgnoredMethods.
|
# Configuration parameters: IgnoredMethods.
|
||||||
# IgnoredMethods: respond_to, define_method
|
# IgnoredMethods: respond_to, define_method
|
||||||
Style/SymbolProc:
|
Style/SymbolProc:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 23
|
# Offense count: 5
|
||||||
|
# Cop supports --auto-correct.
|
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
|
||||||
|
# SupportedStyles: require_parentheses, require_no_parentheses
|
||||||
|
Style/TernaryParentheses:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# Offense count: 24
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
|
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
|
||||||
# SupportedStyles: comma, consistent_comma, no_comma
|
# SupportedStyles: comma, consistent_comma, no_comma
|
||||||
Style/TrailingCommaInArguments:
|
Style/TrailingCommaInArguments:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 113
|
# Offense count: 102
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
|
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
|
||||||
# SupportedStyles: comma, consistent_comma, no_comma
|
# SupportedStyles: comma, consistent_comma, no_comma
|
||||||
|
@ -415,7 +434,7 @@ Style/TrailingCommaInLiteral:
|
||||||
Style/TrailingUnderscoreVariable:
|
Style/TrailingUnderscoreVariable:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 90
|
# Offense count: 76
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/TrailingWhitespace:
|
Style/TrailingWhitespace:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
@ -427,12 +446,12 @@ Style/TrailingWhitespace:
|
||||||
Style/TrivialAccessors:
|
Style/TrivialAccessors:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 3
|
# Offense count: 2
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/UnlessElse:
|
Style/UnlessElse:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 13
|
# Offense count: 14
|
||||||
# Cop supports --auto-correct.
|
# Cop supports --auto-correct.
|
||||||
Style/UnneededInterpolation:
|
Style/UnneededInterpolation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
|
@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
|
||||||
|
|
||||||
## Implement design & UI elements
|
## Implement design & UI elements
|
||||||
|
|
||||||
### Design reference
|
Please see the [UI Guide for building GitLab].
|
||||||
|
|
||||||
The GitLab design reference can be found in the [gitlab-design] project.
|
|
||||||
The designs are made using Antetype (`.atype` files). You can use the
|
|
||||||
[free Antetype viewer (Mac OSX only)] or grab an exported PNG from the design
|
|
||||||
(the PNG is 1:1).
|
|
||||||
|
|
||||||
The current designs can be found in the [`gitlab8.atype` file].
|
|
||||||
|
|
||||||
### UI development kit
|
|
||||||
|
|
||||||
Implemented UI elements can also be found at https://gitlab.com/help/ui. Please
|
|
||||||
note that this page isn't comprehensive at this time.
|
|
||||||
|
|
||||||
## Issue tracker
|
## Issue tracker
|
||||||
|
|
||||||
|
@ -129,7 +117,7 @@ request that potentially fixes it.
|
||||||
|
|
||||||
### Feature proposals
|
### Feature proposals
|
||||||
|
|
||||||
To create a feature proposal for CE and CI, open an issue on the
|
To create a feature proposal for CE, open an issue on the
|
||||||
[issue tracker of CE][ce-tracker].
|
[issue tracker of CE][ce-tracker].
|
||||||
|
|
||||||
For feature proposals for EE, open an issue on the
|
For feature proposals for EE, open an issue on the
|
||||||
|
@ -144,16 +132,7 @@ code snippet right after your description in a new line: `~"feature proposal"`.
|
||||||
Please keep feature proposals as small and simple as possible, complex ones
|
Please keep feature proposals as small and simple as possible, complex ones
|
||||||
might be edited to make them small and simple.
|
might be edited to make them small and simple.
|
||||||
|
|
||||||
You are encouraged to use the template below for feature proposals.
|
Please submit Feature Proposals using the ['Feature Proposal' issue template](.gitlab/issue_templates/Feature Proposal.md) provided on the issue tracker.
|
||||||
|
|
||||||
```
|
|
||||||
## Description
|
|
||||||
Include problem, use cases, benefits, and/or goals
|
|
||||||
|
|
||||||
## Proposal
|
|
||||||
|
|
||||||
## Links / references
|
|
||||||
```
|
|
||||||
|
|
||||||
For changes in the interface, it can be helpful to create a mockup first.
|
For changes in the interface, it can be helpful to create a mockup first.
|
||||||
If you want to create something yourself, consider opening an issue first to
|
If you want to create something yourself, consider opening an issue first to
|
||||||
|
@ -166,55 +145,11 @@ submitting your own, there's a good chance somebody else had the same issue or
|
||||||
feature proposal. Show your support with an award emoji and/or join the
|
feature proposal. Show your support with an award emoji and/or join the
|
||||||
discussion.
|
discussion.
|
||||||
|
|
||||||
Please submit bugs using the following template in the issue description area.
|
Please submit bugs using the ['Bug' issue template](.gitlab/issue_templates/Bug.md) provided on the issue tracker.
|
||||||
The text in the parenthesis is there to help you with what to include. Omit it
|
The text in the parenthesis is there to help you with what to include. Omit it
|
||||||
when submitting the actual issue. You can copy-paste it and then edit as you
|
when submitting the actual issue. You can copy-paste it and then edit as you
|
||||||
see fit.
|
see fit.
|
||||||
|
|
||||||
```
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
(Summarize your issue in one sentence - what goes wrong, what did you expect to happen)
|
|
||||||
|
|
||||||
## Steps to reproduce
|
|
||||||
|
|
||||||
(How one can reproduce the issue - this is very important)
|
|
||||||
|
|
||||||
## Expected behavior
|
|
||||||
|
|
||||||
(What you should see instead)
|
|
||||||
|
|
||||||
## Relevant logs and/or screenshots
|
|
||||||
|
|
||||||
(Paste any relevant logs - please use code blocks (```) to format console output,
|
|
||||||
logs, and code as it's very hard to read otherwise.)
|
|
||||||
|
|
||||||
## Output of checks
|
|
||||||
|
|
||||||
### Results of GitLab Application Check
|
|
||||||
|
|
||||||
(For installations with omnibus-gitlab package run and paste the output of:
|
|
||||||
sudo gitlab-rake gitlab:check SANITIZE=true)
|
|
||||||
|
|
||||||
(For installations from source run and paste the output of:
|
|
||||||
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true)
|
|
||||||
|
|
||||||
(we will only investigate if the tests are passing)
|
|
||||||
|
|
||||||
### Results of GitLab Environment Info
|
|
||||||
|
|
||||||
(For installations with omnibus-gitlab package run and paste the output of:
|
|
||||||
sudo gitlab-rake gitlab:env:info)
|
|
||||||
|
|
||||||
(For installations from source run and paste the output of:
|
|
||||||
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production)
|
|
||||||
|
|
||||||
## Possible fixes
|
|
||||||
|
|
||||||
(If you can, link to the line of code that might be responsible for the problem)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issue weight
|
### Issue weight
|
||||||
|
|
||||||
Issue weight allows us to get an idea of the amount of work required to solve
|
Issue weight allows us to get an idea of the amount of work required to solve
|
||||||
|
@ -340,6 +275,10 @@ request is as follows:
|
||||||
migrations on a fresh database before the MR is reviewed. If the review leads
|
migrations on a fresh database before the MR is reviewed. If the review leads
|
||||||
to large changes in the MR, do this again once the review is complete.
|
to large changes in the MR, do this again once the review is complete.
|
||||||
1. For more complex migrations, write tests.
|
1. For more complex migrations, write tests.
|
||||||
|
1. Merge requests **must** adhere to the [merge request performance
|
||||||
|
guidelines](doc/development/merge_request_performance_guidelines.md).
|
||||||
|
1. For tests that use Capybara or PhantomJS, see this [article on how
|
||||||
|
to write reliable asynchronous tests](https://robots.thoughtbot.com/write-reliable-asynchronous-integration-tests-with-capybara).
|
||||||
|
|
||||||
The **official merge window** is in the beginning of the month from the 1st to
|
The **official merge window** is in the beginning of the month from the 1st to
|
||||||
the 7th day of the month. This is the best time to submit an MR and get
|
the 7th day of the month. This is the best time to submit an MR and get
|
||||||
|
@ -387,7 +326,8 @@ description area. Copy-paste it to retain the markdown format.
|
||||||
|
|
||||||
1. The change is as small as possible
|
1. The change is as small as possible
|
||||||
1. Include proper tests and make all tests pass (unless it contains a test
|
1. Include proper tests and make all tests pass (unless it contains a test
|
||||||
exposing a bug in existing code)
|
exposing a bug in existing code). Every new class should have corresponding
|
||||||
|
unit tests, even if the class is exercised at a higher level, such as a feature test.
|
||||||
1. If you suspect a failing CI build is unrelated to your contribution, you may
|
1. If you suspect a failing CI build is unrelated to your contribution, you may
|
||||||
try and restart the failing CI job or ask a developer to fix the
|
try and restart the failing CI job or ask a developer to fix the
|
||||||
aforementioned failing test
|
aforementioned failing test
|
||||||
|
@ -539,7 +479,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
|
||||||
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
|
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
|
||||||
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
|
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
|
||||||
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
|
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
|
||||||
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
|
[UI Guide for building GitLab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/ui_guide.md
|
||||||
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
|
|
||||||
[`gitlab8.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/current/
|
|
||||||
[license-finder-doc]: doc/development/licensing.md
|
[license-finder-doc]: doc/development/licensing.md
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
3.4.0
|
3.6.0
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.7.11
|
0.8.2
|
||||||
|
|
14
Gemfile
14
Gemfile
|
@ -26,7 +26,7 @@ gem 'omniauth-auth0', '~> 1.4.1'
|
||||||
gem 'omniauth-azure-oauth2', '~> 0.0.6'
|
gem 'omniauth-azure-oauth2', '~> 0.0.6'
|
||||||
gem 'omniauth-bitbucket', '~> 0.0.2'
|
gem 'omniauth-bitbucket', '~> 0.0.2'
|
||||||
gem 'omniauth-cas3', '~> 1.1.2'
|
gem 'omniauth-cas3', '~> 1.1.2'
|
||||||
gem 'omniauth-facebook', '~> 3.0.0'
|
gem 'omniauth-facebook', '~> 4.0.0'
|
||||||
gem 'omniauth-github', '~> 1.1.1'
|
gem 'omniauth-github', '~> 1.1.1'
|
||||||
gem 'omniauth-gitlab', '~> 1.0.0'
|
gem 'omniauth-gitlab', '~> 1.0.0'
|
||||||
gem 'omniauth-google-oauth2', '~> 0.4.1'
|
gem 'omniauth-google-oauth2', '~> 0.4.1'
|
||||||
|
@ -53,7 +53,7 @@ gem 'browser', '~> 2.2'
|
||||||
|
|
||||||
# Extracting information from a git repository
|
# Extracting information from a git repository
|
||||||
# Provide access to Gitlab::Git library
|
# Provide access to Gitlab::Git library
|
||||||
gem 'gitlab_git', '~> 10.4.7'
|
gem 'gitlab_git', '~> 10.6.6'
|
||||||
|
|
||||||
# LDAP Auth
|
# LDAP Auth
|
||||||
# GitLab fork with several improvements to original library. For full list of changes
|
# GitLab fork with several improvements to original library. For full list of changes
|
||||||
|
@ -97,9 +97,6 @@ gem 'fog-rackspace', '~> 0.1.1'
|
||||||
# for aws storage
|
# for aws storage
|
||||||
gem 'unf', '~> 0.1.4'
|
gem 'unf', '~> 0.1.4'
|
||||||
|
|
||||||
# Authorization
|
|
||||||
gem 'six', '~> 0.2.0'
|
|
||||||
|
|
||||||
# Seed data
|
# Seed data
|
||||||
gem 'seed-fu', '~> 2.3.5'
|
gem 'seed-fu', '~> 2.3.5'
|
||||||
|
|
||||||
|
@ -209,6 +206,9 @@ gem 'mousetrap-rails', '~> 1.4.6'
|
||||||
# Detect and convert string character encoding
|
# Detect and convert string character encoding
|
||||||
gem 'charlock_holmes', '~> 0.7.3'
|
gem 'charlock_holmes', '~> 0.7.3'
|
||||||
|
|
||||||
|
# Faster JSON
|
||||||
|
gem 'oj', '~> 2.17.4'
|
||||||
|
|
||||||
# Parse time & duration
|
# Parse time & duration
|
||||||
gem 'chronic', '~> 0.10.2'
|
gem 'chronic', '~> 0.10.2'
|
||||||
gem 'chronic_duration', '~> 0.10.6'
|
gem 'chronic_duration', '~> 0.10.6'
|
||||||
|
@ -298,9 +298,10 @@ group :development, :test do
|
||||||
gem 'spring-commands-spinach', '~> 1.1.0'
|
gem 'spring-commands-spinach', '~> 1.1.0'
|
||||||
gem 'spring-commands-teaspoon', '~> 0.0.2'
|
gem 'spring-commands-teaspoon', '~> 0.0.2'
|
||||||
|
|
||||||
gem 'rubocop', '~> 0.41.2', require: false
|
gem 'rubocop', '~> 0.42.0', require: false
|
||||||
gem 'rubocop-rspec', '~> 1.5.0', require: false
|
gem 'rubocop-rspec', '~> 1.5.0', require: false
|
||||||
gem 'scss_lint', '~> 0.47.0', require: false
|
gem 'scss_lint', '~> 0.47.0', require: false
|
||||||
|
gem 'haml_lint', '~> 0.18.2', require: false
|
||||||
gem 'simplecov', '0.12.0', require: false
|
gem 'simplecov', '0.12.0', require: false
|
||||||
gem 'flog', '~> 4.3.2', require: false
|
gem 'flog', '~> 4.3.2', require: false
|
||||||
gem 'flay', '~> 2.6.1', require: false
|
gem 'flay', '~> 2.6.1', require: false
|
||||||
|
@ -319,6 +320,7 @@ group :test do
|
||||||
gem 'webmock', '~> 1.21.0'
|
gem 'webmock', '~> 1.21.0'
|
||||||
gem 'test_after_commit', '~> 0.4.2'
|
gem 'test_after_commit', '~> 0.4.2'
|
||||||
gem 'sham_rack', '~> 1.3.6'
|
gem 'sham_rack', '~> 1.3.6'
|
||||||
|
gem 'timecop', '~> 0.8.0'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :production do
|
group :production do
|
||||||
|
|
42
Gemfile.lock
42
Gemfile.lock
|
@ -189,7 +189,7 @@ GEM
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
escape_utils (1.1.1)
|
escape_utils (1.1.1)
|
||||||
eventmachine (1.0.8)
|
eventmachine (1.0.8)
|
||||||
excon (0.49.0)
|
excon (0.52.0)
|
||||||
execjs (2.6.0)
|
execjs (2.6.0)
|
||||||
expression_parser (0.9.0)
|
expression_parser (0.9.0)
|
||||||
factory_girl (4.5.0)
|
factory_girl (4.5.0)
|
||||||
|
@ -215,8 +215,8 @@ GEM
|
||||||
flowdock (0.7.1)
|
flowdock (0.7.1)
|
||||||
httparty (~> 0.7)
|
httparty (~> 0.7)
|
||||||
multi_json
|
multi_json
|
||||||
fog-aws (0.9.2)
|
fog-aws (0.11.0)
|
||||||
fog-core (~> 1.27)
|
fog-core (~> 1.38)
|
||||||
fog-json (~> 1.0)
|
fog-json (~> 1.0)
|
||||||
fog-xml (~> 0.1)
|
fog-xml (~> 0.1)
|
||||||
ipaddress (~> 0.8)
|
ipaddress (~> 0.8)
|
||||||
|
@ -225,7 +225,7 @@ GEM
|
||||||
fog-core (~> 1.27)
|
fog-core (~> 1.27)
|
||||||
fog-json (~> 1.0)
|
fog-json (~> 1.0)
|
||||||
fog-xml (~> 0.1)
|
fog-xml (~> 0.1)
|
||||||
fog-core (1.40.0)
|
fog-core (1.42.0)
|
||||||
builder
|
builder
|
||||||
excon (~> 0.49)
|
excon (~> 0.49)
|
||||||
formatador (~> 0.2)
|
formatador (~> 0.2)
|
||||||
|
@ -279,7 +279,7 @@ GEM
|
||||||
diff-lcs (~> 1.1)
|
diff-lcs (~> 1.1)
|
||||||
mime-types (>= 1.16, < 3)
|
mime-types (>= 1.16, < 3)
|
||||||
posix-spawn (~> 0.3)
|
posix-spawn (~> 0.3)
|
||||||
gitlab_git (10.4.7)
|
gitlab_git (10.6.6)
|
||||||
activesupport (~> 4.0)
|
activesupport (~> 4.0)
|
||||||
charlock_holmes (~> 0.7.3)
|
charlock_holmes (~> 0.7.3)
|
||||||
github-linguist (~> 4.7.0)
|
github-linguist (~> 4.7.0)
|
||||||
|
@ -322,11 +322,18 @@ GEM
|
||||||
grape-entity (0.4.8)
|
grape-entity (0.4.8)
|
||||||
activesupport
|
activesupport
|
||||||
multi_json (>= 1.3.2)
|
multi_json (>= 1.3.2)
|
||||||
|
haml (4.0.7)
|
||||||
|
tilt
|
||||||
|
haml_lint (0.18.2)
|
||||||
|
haml (~> 4.0)
|
||||||
|
rake (>= 10, < 12)
|
||||||
|
rubocop (>= 0.36.0)
|
||||||
|
sysexits (~> 1.1)
|
||||||
hamlit (2.6.1)
|
hamlit (2.6.1)
|
||||||
temple (~> 0.7.6)
|
temple (~> 0.7.6)
|
||||||
thor
|
thor
|
||||||
tilt
|
tilt
|
||||||
hashie (3.4.3)
|
hashie (3.4.4)
|
||||||
health_check (2.1.0)
|
health_check (2.1.0)
|
||||||
rails (>= 4.0)
|
rails (>= 4.0)
|
||||||
hipchat (1.5.2)
|
hipchat (1.5.2)
|
||||||
|
@ -394,7 +401,7 @@ GEM
|
||||||
mime-types (>= 1.16, < 4)
|
mime-types (>= 1.16, < 4)
|
||||||
mail_room (0.8.0)
|
mail_room (0.8.0)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (2.99.2)
|
mime-types (2.99.3)
|
||||||
mimemagic (0.3.0)
|
mimemagic (0.3.0)
|
||||||
mini_portile2 (2.1.0)
|
mini_portile2 (2.1.0)
|
||||||
minitest (5.7.0)
|
minitest (5.7.0)
|
||||||
|
@ -420,6 +427,7 @@ GEM
|
||||||
rack (>= 1.2, < 3)
|
rack (>= 1.2, < 3)
|
||||||
octokit (4.3.0)
|
octokit (4.3.0)
|
||||||
sawyer (~> 0.7.0, >= 0.5.3)
|
sawyer (~> 0.7.0, >= 0.5.3)
|
||||||
|
oj (2.17.4)
|
||||||
omniauth (1.3.1)
|
omniauth (1.3.1)
|
||||||
hashie (>= 1.2, < 4)
|
hashie (>= 1.2, < 4)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
|
@ -437,7 +445,7 @@ GEM
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.3)
|
||||||
nokogiri (~> 1.6.6)
|
nokogiri (~> 1.6.6)
|
||||||
omniauth (~> 1.2)
|
omniauth (~> 1.2)
|
||||||
omniauth-facebook (3.0.0)
|
omniauth-facebook (4.0.0)
|
||||||
omniauth-oauth2 (~> 1.2)
|
omniauth-oauth2 (~> 1.2)
|
||||||
omniauth-github (1.1.2)
|
omniauth-github (1.1.2)
|
||||||
omniauth (~> 1.0)
|
omniauth (~> 1.0)
|
||||||
|
@ -584,7 +592,7 @@ GEM
|
||||||
railties (>= 4.2.0, < 5.1)
|
railties (>= 4.2.0, < 5.1)
|
||||||
rinku (2.0.0)
|
rinku (2.0.0)
|
||||||
rotp (2.1.2)
|
rotp (2.1.2)
|
||||||
rouge (2.0.5)
|
rouge (2.0.6)
|
||||||
rqrcode (0.7.0)
|
rqrcode (0.7.0)
|
||||||
chunky_png
|
chunky_png
|
||||||
rqrcode-rails3 (0.1.7)
|
rqrcode-rails3 (0.1.7)
|
||||||
|
@ -612,7 +620,7 @@ GEM
|
||||||
rspec-retry (0.4.5)
|
rspec-retry (0.4.5)
|
||||||
rspec-core
|
rspec-core
|
||||||
rspec-support (3.5.0)
|
rspec-support (3.5.0)
|
||||||
rubocop (0.41.2)
|
rubocop (0.42.0)
|
||||||
parser (>= 2.3.1.1, < 3.0)
|
parser (>= 2.3.1.1, < 3.0)
|
||||||
powerpack (~> 0.1)
|
powerpack (~> 0.1)
|
||||||
rainbow (>= 1.99.1, < 3.0)
|
rainbow (>= 1.99.1, < 3.0)
|
||||||
|
@ -683,7 +691,6 @@ GEM
|
||||||
rack (~> 1.5)
|
rack (~> 1.5)
|
||||||
rack-protection (~> 1.4)
|
rack-protection (~> 1.4)
|
||||||
tilt (>= 1.3, < 3)
|
tilt (>= 1.3, < 3)
|
||||||
six (0.2.0)
|
|
||||||
slack-notifier (1.2.1)
|
slack-notifier (1.2.1)
|
||||||
slop (3.6.0)
|
slop (3.6.0)
|
||||||
spinach (0.8.10)
|
spinach (0.8.10)
|
||||||
|
@ -724,6 +731,7 @@ GEM
|
||||||
stringex (2.5.2)
|
stringex (2.5.2)
|
||||||
sys-filesystem (1.1.6)
|
sys-filesystem (1.1.6)
|
||||||
ffi
|
ffi
|
||||||
|
sysexits (1.2.0)
|
||||||
systemu (2.6.5)
|
systemu (2.6.5)
|
||||||
task_list (1.0.2)
|
task_list (1.0.2)
|
||||||
html-pipeline
|
html-pipeline
|
||||||
|
@ -755,7 +763,7 @@ GEM
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.2)
|
unf_ext (0.0.7.2)
|
||||||
unicode-display_width (1.1.0)
|
unicode-display_width (1.1.1)
|
||||||
unicorn (4.9.0)
|
unicorn (4.9.0)
|
||||||
kgio (~> 2.6)
|
kgio (~> 2.6)
|
||||||
rack
|
rack
|
||||||
|
@ -859,7 +867,7 @@ DEPENDENCIES
|
||||||
github-linguist (~> 4.7.0)
|
github-linguist (~> 4.7.0)
|
||||||
github-markup (~> 1.4)
|
github-markup (~> 1.4)
|
||||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||||
gitlab_git (~> 10.4.7)
|
gitlab_git (~> 10.6.6)
|
||||||
gitlab_meta (= 7.0)
|
gitlab_meta (= 7.0)
|
||||||
gitlab_omniauth-ldap (~> 1.2.1)
|
gitlab_omniauth-ldap (~> 1.2.1)
|
||||||
gollum-lib (~> 4.2)
|
gollum-lib (~> 4.2)
|
||||||
|
@ -867,6 +875,7 @@ DEPENDENCIES
|
||||||
gon (~> 6.1.0)
|
gon (~> 6.1.0)
|
||||||
grape (~> 0.15.0)
|
grape (~> 0.15.0)
|
||||||
grape-entity (~> 0.4.2)
|
grape-entity (~> 0.4.2)
|
||||||
|
haml_lint (~> 0.18.2)
|
||||||
hamlit (~> 2.6.1)
|
hamlit (~> 2.6.1)
|
||||||
health_check (~> 2.1.0)
|
health_check (~> 2.1.0)
|
||||||
hipchat (~> 1.5.0)
|
hipchat (~> 1.5.0)
|
||||||
|
@ -896,12 +905,13 @@ DEPENDENCIES
|
||||||
nokogiri (~> 1.6.7, >= 1.6.7.2)
|
nokogiri (~> 1.6.7, >= 1.6.7.2)
|
||||||
oauth2 (~> 1.2.0)
|
oauth2 (~> 1.2.0)
|
||||||
octokit (~> 4.3.0)
|
octokit (~> 4.3.0)
|
||||||
|
oj (~> 2.17.4)
|
||||||
omniauth (~> 1.3.1)
|
omniauth (~> 1.3.1)
|
||||||
omniauth-auth0 (~> 1.4.1)
|
omniauth-auth0 (~> 1.4.1)
|
||||||
omniauth-azure-oauth2 (~> 0.0.6)
|
omniauth-azure-oauth2 (~> 0.0.6)
|
||||||
omniauth-bitbucket (~> 0.0.2)
|
omniauth-bitbucket (~> 0.0.2)
|
||||||
omniauth-cas3 (~> 1.1.2)
|
omniauth-cas3 (~> 1.1.2)
|
||||||
omniauth-facebook (~> 3.0.0)
|
omniauth-facebook (~> 4.0.0)
|
||||||
omniauth-github (~> 1.1.1)
|
omniauth-github (~> 1.1.1)
|
||||||
omniauth-gitlab (~> 1.0.0)
|
omniauth-gitlab (~> 1.0.0)
|
||||||
omniauth-google-oauth2 (~> 0.4.1)
|
omniauth-google-oauth2 (~> 0.4.1)
|
||||||
|
@ -936,7 +946,7 @@ DEPENDENCIES
|
||||||
rqrcode-rails3 (~> 0.1.7)
|
rqrcode-rails3 (~> 0.1.7)
|
||||||
rspec-rails (~> 3.5.0)
|
rspec-rails (~> 3.5.0)
|
||||||
rspec-retry (~> 0.4.5)
|
rspec-retry (~> 0.4.5)
|
||||||
rubocop (~> 0.41.2)
|
rubocop (~> 0.42.0)
|
||||||
rubocop-rspec (~> 1.5.0)
|
rubocop-rspec (~> 1.5.0)
|
||||||
ruby-fogbugz (~> 0.2.1)
|
ruby-fogbugz (~> 0.2.1)
|
||||||
ruby-prof (~> 0.15.9)
|
ruby-prof (~> 0.15.9)
|
||||||
|
@ -954,7 +964,6 @@ DEPENDENCIES
|
||||||
sidekiq-cron (~> 0.4.0)
|
sidekiq-cron (~> 0.4.0)
|
||||||
simplecov (= 0.12.0)
|
simplecov (= 0.12.0)
|
||||||
sinatra (~> 1.4.4)
|
sinatra (~> 1.4.4)
|
||||||
six (~> 0.2.0)
|
|
||||||
slack-notifier (~> 1.2.0)
|
slack-notifier (~> 1.2.0)
|
||||||
spinach-rails (~> 0.2.1)
|
spinach-rails (~> 0.2.1)
|
||||||
spinach-rerun-reporter (~> 0.0.2)
|
spinach-rerun-reporter (~> 0.0.2)
|
||||||
|
@ -971,6 +980,7 @@ DEPENDENCIES
|
||||||
teaspoon-jasmine (~> 2.2.0)
|
teaspoon-jasmine (~> 2.2.0)
|
||||||
test_after_commit (~> 0.4.2)
|
test_after_commit (~> 0.4.2)
|
||||||
thin (~> 1.7.0)
|
thin (~> 1.7.0)
|
||||||
|
timecop (~> 0.8.0)
|
||||||
turbolinks (~> 2.5.0)
|
turbolinks (~> 2.5.0)
|
||||||
u2f (~> 0.2.1)
|
u2f (~> 0.2.1)
|
||||||
uglifier (~> 2.7.2)
|
uglifier (~> 2.7.2)
|
||||||
|
|
|
@ -50,7 +50,7 @@ etc.).
|
||||||
|
|
||||||
The most important thing is making sure valid issues receive feedback from the
|
The most important thing is making sure valid issues receive feedback from the
|
||||||
development team. Therefore the priority is mentioning developers that can help
|
development team. Therefore the priority is mentioning developers that can help
|
||||||
on those issue. Please select someone with relevant experience from
|
on those issues. Please select someone with relevant experience from
|
||||||
[GitLab core team][core-team]. If there is nobody mentioned with that expertise
|
[GitLab core team][core-team]. If there is nobody mentioned with that expertise
|
||||||
look in the commit history for the affected files to find someone. Avoid
|
look in the commit history for the affected files to find someone. Avoid
|
||||||
mentioning the lead developer, this is the person that is least likely to give a
|
mentioning the lead developer, this is the person that is least likely to give a
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# GitLab
|
# GitLab
|
||||||
|
|
||||||
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
|
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
|
||||||
|
[![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
|
||||||
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
|
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
|
||||||
|
|
||||||
## Canonical source
|
## Canonical source
|
||||||
|
@ -69,7 +70,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the
|
||||||
GitLab is a Ruby on Rails application that runs on the following software:
|
GitLab is a Ruby on Rails application that runs on the following software:
|
||||||
|
|
||||||
- Ubuntu/Debian/CentOS/RHEL
|
- Ubuntu/Debian/CentOS/RHEL
|
||||||
- Ruby (MRI) 2.1
|
- Ruby (MRI) 2.3
|
||||||
- Git 2.7.4+
|
- Git 2.7.4+
|
||||||
- Redis 2.8+
|
- Redis 2.8+
|
||||||
- MySQL or PostgreSQL
|
- MySQL or PostgreSQL
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
8.11.3
|
8.12.1
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 729 B |
1
app/assets/images/icon_anchor.svg
Normal file
1
app/assets/images/icon_anchor.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="#333" fill-rule="evenodd" d="M9.683 6.676l-.047-.048C8.27 5.26 6.07 5.243 4.726 6.588l-2.29 2.29c-1.344 1.344-1.328 3.544.04 4.91 1.366 1.368 3.564 1.385 4.908.04l1.753-1.752c-.695.074-1.457-.078-2.176-.444L5.934 12.66c-.634.634-1.67.625-2.312-.017-.642-.643-.65-1.677-.017-2.312L6.035 7.9c.634-.634 1.67-.625 2.312.017.024.024.048.05.07.075l.003-.002c.36.36.943.366 1.3.01.355-.356.35-.938-.01-1.3l-.027-.024zM6.58 9.586l.048.05c1.367 1.366 3.565 1.384 4.91.04l2.29-2.292c1.344-1.343 1.328-3.542-.04-4.91-1.366-1.366-3.564-1.384-4.908-.04L7.127 4.187c.695-.074 1.457.078 2.176.444l1.028-1.027c.635-.634 1.67-.624 2.313.017.643.644.652 1.678.018 2.312l-2.43 2.432c-.635.634-1.67.624-2.313-.018-.024-.024-.048-.05-.07-.075l-.003.004c-.36-.362-.943-.367-1.3-.01-.355.355-.35.937.01 1.3.01.007.018.015.027.023z"/></svg>
|
After Width: | Height: | Size: 911 B |
|
@ -3,6 +3,7 @@
|
||||||
LabelManager.prototype.errorMessage = 'Unable to update label prioritization at this time';
|
LabelManager.prototype.errorMessage = 'Unable to update label prioritization at this time';
|
||||||
|
|
||||||
function LabelManager(opts) {
|
function LabelManager(opts) {
|
||||||
|
// Defaults
|
||||||
var ref, ref1, ref2;
|
var ref, ref1, ref2;
|
||||||
if (opts == null) {
|
if (opts == null) {
|
||||||
opts = {};
|
opts = {};
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
$btn = $(e.currentTarget);
|
$btn = $(e.currentTarget);
|
||||||
$label = $("#" + ($btn.data('domId')));
|
$label = $("#" + ($btn.data('domId')));
|
||||||
action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add';
|
action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add';
|
||||||
|
// Make sure tooltip will hide
|
||||||
$tooltip = $("#" + ($btn.find('.has-tooltip:visible').attr('aria-describedby')));
|
$tooltip = $("#" + ($btn.find('.has-tooltip:visible').attr('aria-describedby')));
|
||||||
$tooltip.tooltip('destroy');
|
$tooltip.tooltip('destroy');
|
||||||
return _this.toggleLabelPriority($label, action);
|
return _this.toggleLabelPriority($label, action);
|
||||||
|
@ -42,6 +44,7 @@
|
||||||
url = $label.find('.js-toggle-priority').data('url');
|
url = $label.find('.js-toggle-priority').data('url');
|
||||||
$target = this.prioritizedLabels;
|
$target = this.prioritizedLabels;
|
||||||
$from = this.otherLabels;
|
$from = this.otherLabels;
|
||||||
|
// Optimistic update
|
||||||
if (action === 'remove') {
|
if (action === 'remove') {
|
||||||
$target = this.otherLabels;
|
$target = this.otherLabels;
|
||||||
$from = this.prioritizedLabels;
|
$from = this.prioritizedLabels;
|
||||||
|
@ -53,6 +56,7 @@
|
||||||
$target.find('.empty-message').addClass('hidden');
|
$target.find('.empty-message').addClass('hidden');
|
||||||
}
|
}
|
||||||
$label.detach().appendTo($target);
|
$label.detach().appendTo($target);
|
||||||
|
// Return if we are not persisting state
|
||||||
if (!persistState) {
|
if (!persistState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +65,7 @@
|
||||||
url: url,
|
url: url,
|
||||||
type: 'DELETE'
|
type: 'DELETE'
|
||||||
});
|
});
|
||||||
|
// Restore empty message
|
||||||
if (!$from.find('li').length) {
|
if (!$from.find('li').length) {
|
||||||
$from.find('.empty-message').removeClass('hidden');
|
$from.find('.empty-message').removeClass('hidden');
|
||||||
}
|
}
|
||||||
|
|
38
app/assets/javascripts/abuse_reports.js.es6
Normal file
38
app/assets/javascripts/abuse_reports.js.es6
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
((global) => {
|
||||||
|
const MAX_MESSAGE_LENGTH = 500;
|
||||||
|
const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
|
||||||
|
|
||||||
|
class AbuseReports {
|
||||||
|
constructor() {
|
||||||
|
$(MESSAGE_CELL_SELECTOR).each(this.truncateLongMessage);
|
||||||
|
$(document)
|
||||||
|
.off('click', MESSAGE_CELL_SELECTOR)
|
||||||
|
.on('click', MESSAGE_CELL_SELECTOR, this.toggleMessageTruncation);
|
||||||
|
}
|
||||||
|
|
||||||
|
truncateLongMessage() {
|
||||||
|
const $messageCellElement = $(this);
|
||||||
|
const reportMessage = $messageCellElement.text();
|
||||||
|
if (reportMessage.length > MAX_MESSAGE_LENGTH) {
|
||||||
|
$messageCellElement.data('original-message', reportMessage);
|
||||||
|
$messageCellElement.data('message-truncated', 'true');
|
||||||
|
$messageCellElement.text(global.text.truncate(reportMessage, MAX_MESSAGE_LENGTH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleMessageTruncation() {
|
||||||
|
const $messageCellElement = $(this);
|
||||||
|
const originalMessage = $messageCellElement.data('original-message');
|
||||||
|
if (!originalMessage) return;
|
||||||
|
if ($messageCellElement.data('message-truncated') === 'true') {
|
||||||
|
$messageCellElement.data('message-truncated', 'false');
|
||||||
|
$messageCellElement.text(originalMessage);
|
||||||
|
} else {
|
||||||
|
$messageCellElement.data('message-truncated', 'true');
|
||||||
|
$messageCellElement.text(`${originalMessage.substr(0, (MAX_MESSAGE_LENGTH - 3))}...`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global.AbuseReports = AbuseReports;
|
||||||
|
})(window.gl || (window.gl = {}));
|
|
@ -12,7 +12,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
Activities.prototype.updateTooltips = function() {
|
Activities.prototype.updateTooltips = function() {
|
||||||
return gl.utils.localTimeAgo($('.js-timeago', '#activity'));
|
return gl.utils.localTimeAgo($('.js-timeago', '.content_list'));
|
||||||
};
|
};
|
||||||
|
|
||||||
Activities.prototype.reloadActivities = function() {
|
Activities.prototype.reloadActivities = function() {
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
event_filters = $.cookie("event_filter");
|
event_filters = $.cookie("event_filter");
|
||||||
filter = sender.attr("id").split("_")[0];
|
filter = sender.attr("id").split("_")[0];
|
||||||
$.cookie("event_filter", (event_filters !== filter ? filter : ""), {
|
$.cookie("event_filter", (event_filters !== filter ? filter : ""), {
|
||||||
path: '/'
|
path: gon.relative_url_root || '/'
|
||||||
});
|
});
|
||||||
if (event_filters !== filter) {
|
if (event_filters !== filter) {
|
||||||
return sender.closest('li').toggleClass("active");
|
return sender.closest('li').toggleClass("active");
|
||||||
|
|
|
@ -16,20 +16,18 @@
|
||||||
.replace(':id', group_id);
|
.replace(':id', group_id);
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
data: {
|
|
||||||
private_token: gon.api_token
|
|
||||||
},
|
|
||||||
dataType: "json"
|
dataType: "json"
|
||||||
}).done(function(group) {
|
}).done(function(group) {
|
||||||
return callback(group);
|
return callback(group);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// Return groups list. Filtered by query
|
||||||
|
// Only active groups retrieved
|
||||||
groups: function(query, skip_ldap, callback) {
|
groups: function(query, skip_ldap, callback) {
|
||||||
var url = Api.buildUrl(Api.groupsPath);
|
var url = Api.buildUrl(Api.groupsPath);
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
data: {
|
data: {
|
||||||
private_token: gon.api_token,
|
|
||||||
search: query,
|
search: query,
|
||||||
per_page: 20
|
per_page: 20
|
||||||
},
|
},
|
||||||
|
@ -38,12 +36,12 @@
|
||||||
return callback(groups);
|
return callback(groups);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// Return namespaces list. Filtered by query
|
||||||
namespaces: function(query, callback) {
|
namespaces: function(query, callback) {
|
||||||
var url = Api.buildUrl(Api.namespacesPath);
|
var url = Api.buildUrl(Api.namespacesPath);
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
data: {
|
data: {
|
||||||
private_token: gon.api_token,
|
|
||||||
search: query,
|
search: query,
|
||||||
per_page: 20
|
per_page: 20
|
||||||
},
|
},
|
||||||
|
@ -52,12 +50,12 @@
|
||||||
return callback(namespaces);
|
return callback(namespaces);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// Return projects list. Filtered by query
|
||||||
projects: function(query, order, callback) {
|
projects: function(query, order, callback) {
|
||||||
var url = Api.buildUrl(Api.projectsPath);
|
var url = Api.buildUrl(Api.projectsPath);
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
data: {
|
data: {
|
||||||
private_token: gon.api_token,
|
|
||||||
search: query,
|
search: query,
|
||||||
order_by: order,
|
order_by: order,
|
||||||
per_page: 20
|
per_page: 20
|
||||||
|
@ -70,7 +68,6 @@
|
||||||
newLabel: function(project_id, data, callback) {
|
newLabel: function(project_id, data, callback) {
|
||||||
var url = Api.buildUrl(Api.labelsPath)
|
var url = Api.buildUrl(Api.labelsPath)
|
||||||
.replace(':id', project_id);
|
.replace(':id', project_id);
|
||||||
data.private_token = gon.api_token;
|
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
@ -82,13 +79,13 @@
|
||||||
return callback(message.responseJSON);
|
return callback(message.responseJSON);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// Return group projects list. Filtered by query
|
||||||
groupProjects: function(group_id, query, callback) {
|
groupProjects: function(group_id, query, callback) {
|
||||||
var url = Api.buildUrl(Api.groupProjectsPath)
|
var url = Api.buildUrl(Api.groupProjectsPath)
|
||||||
.replace(':id', group_id);
|
.replace(':id', group_id);
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
data: {
|
data: {
|
||||||
private_token: gon.api_token,
|
|
||||||
search: query,
|
search: query,
|
||||||
per_page: 20
|
per_page: 20
|
||||||
},
|
},
|
||||||
|
@ -97,6 +94,7 @@
|
||||||
return callback(projects);
|
return callback(projects);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// Return text for a specific license
|
||||||
licenseText: function(key, data, callback) {
|
licenseText: function(key, data, callback) {
|
||||||
var url = Api.buildUrl(Api.licensePath)
|
var url = Api.buildUrl(Api.licensePath)
|
||||||
.replace(':key', key);
|
.replace(':key', key);
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
// This is a manifest file that'll be compiled into including all the files listed below.
|
||||||
|
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
|
||||||
|
// be included in the compiled file accessible from http://example.com/assets/application.js
|
||||||
|
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||||
|
// the compiled file.
|
||||||
|
//
|
||||||
/*= require jquery2 */
|
/*= require jquery2 */
|
||||||
/*= require jquery-ui/autocomplete */
|
/*= require jquery-ui/autocomplete */
|
||||||
/*= require jquery-ui/datepicker */
|
/*= require jquery-ui/datepicker */
|
||||||
|
@ -76,6 +82,7 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Disable button if text field is empty
|
||||||
window.disableButtonIfEmptyField = function(field_selector, button_selector) {
|
window.disableButtonIfEmptyField = function(field_selector, button_selector) {
|
||||||
var closest_submit, field;
|
var closest_submit, field;
|
||||||
field = $(field_selector);
|
field = $(field_selector);
|
||||||
|
@ -92,6 +99,7 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Disable button if any input field with given selector is empty
|
||||||
window.disableButtonIfAnyEmptyField = function(form, form_selector, button_selector) {
|
window.disableButtonIfAnyEmptyField = function(form, form_selector, button_selector) {
|
||||||
var closest_submit, updateButtons;
|
var closest_submit, updateButtons;
|
||||||
closest_submit = form.find(button_selector);
|
closest_submit = form.find(button_selector);
|
||||||
|
@ -128,6 +136,8 @@
|
||||||
window.addEventListener("hashchange", shiftWindow);
|
window.addEventListener("hashchange", shiftWindow);
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
// Scroll the window to avoid the topnav bar
|
||||||
|
// https://github.com/twitter/bootstrap/issues/1768
|
||||||
if (location.hash) {
|
if (location.hash) {
|
||||||
return setTimeout(shiftWindow, 100);
|
return setTimeout(shiftWindow, 100);
|
||||||
}
|
}
|
||||||
|
@ -149,9 +159,13 @@
|
||||||
return $(this).select().one('mouseup', function(e) {
|
return $(this).select().one('mouseup', function(e) {
|
||||||
return e.preventDefault();
|
return e.preventDefault();
|
||||||
});
|
});
|
||||||
|
// Click a .js-select-on-focus field, select the contents
|
||||||
|
// Prevent a mouseup event from deselecting the input
|
||||||
});
|
});
|
||||||
$('.remove-row').bind('ajax:success', function() {
|
$('.remove-row').bind('ajax:success', function() {
|
||||||
return $(this).closest('li').fadeOut();
|
$(this).tooltip('destroy')
|
||||||
|
.closest('li')
|
||||||
|
.fadeOut();
|
||||||
});
|
});
|
||||||
$('.js-remove-tr').bind('ajax:before', function() {
|
$('.js-remove-tr').bind('ajax:before', function() {
|
||||||
return $(this).hide();
|
return $(this).hide();
|
||||||
|
@ -161,6 +175,7 @@
|
||||||
});
|
});
|
||||||
$('select.select2').select2({
|
$('select.select2').select2({
|
||||||
width: 'resolve',
|
width: 'resolve',
|
||||||
|
// Initialize select2 selects
|
||||||
dropdownAutoWidth: true
|
dropdownAutoWidth: true
|
||||||
});
|
});
|
||||||
$('.js-select2').bind('select2-close', function() {
|
$('.js-select2').bind('select2-close', function() {
|
||||||
|
@ -168,25 +183,28 @@
|
||||||
$('.select2-container-active').removeClass('select2-container-active');
|
$('.select2-container-active').removeClass('select2-container-active');
|
||||||
return $(':focus').blur();
|
return $(':focus').blur();
|
||||||
}), 1);
|
}), 1);
|
||||||
|
// Close select2 on escape
|
||||||
});
|
});
|
||||||
|
// Initialize tooltips
|
||||||
$body.tooltip({
|
$body.tooltip({
|
||||||
selector: '.has-tooltip, [data-toggle="tooltip"]',
|
selector: '.has-tooltip, [data-toggle="tooltip"]',
|
||||||
placement: function(_, el) {
|
placement: function(_, el) {
|
||||||
var $el;
|
return $(el).data('placement') || 'bottom';
|
||||||
$el = $(el);
|
|
||||||
return $el.data('placement') || 'bottom';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$('.trigger-submit').on('change', function() {
|
$('.trigger-submit').on('change', function() {
|
||||||
return $(this).parents('form').submit();
|
return $(this).parents('form').submit();
|
||||||
|
// Form submitter
|
||||||
});
|
});
|
||||||
gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true);
|
gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true);
|
||||||
|
// Flash
|
||||||
if ((flash = $(".flash-container")).length > 0) {
|
if ((flash = $(".flash-container")).length > 0) {
|
||||||
flash.click(function() {
|
flash.click(function() {
|
||||||
return $(this).fadeOut();
|
return $(this).fadeOut();
|
||||||
});
|
});
|
||||||
flash.show();
|
flash.show();
|
||||||
}
|
}
|
||||||
|
// Disable form buttons while a form is submitting
|
||||||
$body.on('ajax:complete, ajax:beforeSend, submit', 'form', function(e) {
|
$body.on('ajax:complete, ajax:beforeSend, submit', 'form', function(e) {
|
||||||
var buttons;
|
var buttons;
|
||||||
buttons = $('[type="submit"]', this);
|
buttons = $('[type="submit"]', this);
|
||||||
|
@ -207,6 +225,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$('.account-box').hover(function() {
|
$('.account-box').hover(function() {
|
||||||
|
// Show/Hide the profile menu when hovering the account box
|
||||||
return $(this).toggleClass('hover');
|
return $(this).toggleClass('hover');
|
||||||
});
|
});
|
||||||
$document.on('click', '.diff-content .js-show-suppressed-diff', function() {
|
$document.on('click', '.diff-content .js-show-suppressed-diff', function() {
|
||||||
|
@ -214,6 +233,7 @@
|
||||||
$container = $(this).parent();
|
$container = $(this).parent();
|
||||||
$container.next('table').show();
|
$container.next('table').show();
|
||||||
return $container.remove();
|
return $container.remove();
|
||||||
|
// Commit show suppressed diff
|
||||||
});
|
});
|
||||||
$('.navbar-toggle').on('click', function() {
|
$('.navbar-toggle').on('click', function() {
|
||||||
$('.header-content .title').toggle();
|
$('.header-content .title').toggle();
|
||||||
|
@ -221,6 +241,7 @@
|
||||||
$('.header-content .navbar-collapse').toggle();
|
$('.header-content .navbar-collapse').toggle();
|
||||||
return $('.navbar-toggle').toggleClass('active');
|
return $('.navbar-toggle').toggleClass('active');
|
||||||
});
|
});
|
||||||
|
// Show/hide comments on diff
|
||||||
$body.on("click", ".js-toggle-diff-comments", function(e) {
|
$body.on("click", ".js-toggle-diff-comments", function(e) {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
$this.toggleClass('active');
|
$this.toggleClass('active');
|
||||||
|
@ -230,6 +251,7 @@
|
||||||
} else {
|
} else {
|
||||||
notesHolders.hide();
|
notesHolders.hide();
|
||||||
}
|
}
|
||||||
|
$this.trigger('blur');
|
||||||
return e.preventDefault();
|
return e.preventDefault();
|
||||||
});
|
});
|
||||||
$document.off("click", '.js-confirm-danger');
|
$document.off("click", '.js-confirm-danger');
|
||||||
|
@ -284,42 +306,9 @@
|
||||||
gl.awardsHandler = new AwardsHandler();
|
gl.awardsHandler = new AwardsHandler();
|
||||||
checkInitialSidebarSize();
|
checkInitialSidebarSize();
|
||||||
new Aside();
|
new Aside();
|
||||||
if ($window.width() < 1024 && $.cookie('pin_nav') === 'true') {
|
|
||||||
$.cookie('pin_nav', 'false', {
|
// bind sidebar events
|
||||||
path: '/',
|
new gl.Sidebar();
|
||||||
expires: 365 * 10
|
|
||||||
});
|
|
||||||
$('.page-with-sidebar').toggleClass('page-sidebar-collapsed page-sidebar-expanded').removeClass('page-sidebar-pinned');
|
|
||||||
$('.navbar-fixed-top').removeClass('header-pinned-nav');
|
|
||||||
}
|
|
||||||
$document.off('click', '.js-nav-pin').on('click', '.js-nav-pin', function(e) {
|
|
||||||
var $page, $pinBtn, $tooltip, $topNav, doPinNav, tooltipText;
|
|
||||||
e.preventDefault();
|
|
||||||
$pinBtn = $(e.currentTarget);
|
|
||||||
$page = $('.page-with-sidebar');
|
|
||||||
$topNav = $('.navbar-fixed-top');
|
|
||||||
$tooltip = $("#" + ($pinBtn.attr('aria-describedby')));
|
|
||||||
doPinNav = !$page.is('.page-sidebar-pinned');
|
|
||||||
tooltipText = 'Pin navigation';
|
|
||||||
$(this).toggleClass('is-active');
|
|
||||||
if (doPinNav) {
|
|
||||||
$page.addClass('page-sidebar-pinned');
|
|
||||||
$topNav.addClass('header-pinned-nav');
|
|
||||||
} else {
|
|
||||||
$tooltip.remove();
|
|
||||||
$page.removeClass('page-sidebar-pinned').toggleClass('page-sidebar-collapsed page-sidebar-expanded');
|
|
||||||
$topNav.removeClass('header-pinned-nav').toggleClass('header-collapsed header-expanded');
|
|
||||||
}
|
|
||||||
$.cookie('pin_nav', doPinNav, {
|
|
||||||
path: '/',
|
|
||||||
expires: 365 * 10
|
|
||||||
});
|
|
||||||
if ($.cookie('pin_nav') === 'true' || doPinNav) {
|
|
||||||
tooltipText = 'Unpin navigation';
|
|
||||||
}
|
|
||||||
$tooltip.find('.tooltip-inner').text(tooltipText);
|
|
||||||
return $pinBtn.attr('title', tooltipText).tooltip('fixTitle');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Custom time ago
|
// Custom time ago
|
||||||
gl.utils.shortTimeAgo($('.js-short-timeago'));
|
gl.utils.shortTimeAgo($('.js-short-timeago'));
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
Autosave.prototype.restore = function() {
|
Autosave.prototype.restore = function() {
|
||||||
var e, error, text;
|
var e, text;
|
||||||
if (window.localStorage == null) {
|
if (window.localStorage == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
if ((text != null ? text.length : void 0) > 0) {
|
if ((text != null ? text.length : void 0) > 0) {
|
||||||
try {
|
try {
|
||||||
return window.localStorage.setItem(this.key, text);
|
return window.localStorage.setItem(this.key, text);
|
||||||
} catch (undefined) {}
|
} catch (error) {}
|
||||||
} else {
|
} else {
|
||||||
return this.reset();
|
return this.reset();
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return window.localStorage.removeItem(this.key);
|
return window.localStorage.removeItem(this.key);
|
||||||
} catch (undefined) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Autosave;
|
return Autosave;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
(function() {
|
(function() {
|
||||||
this.AwardsHandler = (function() {
|
this.AwardsHandler = (function() {
|
||||||
|
const FROM_SENTENCE_REGEX = /(?:, and | and |, )/; //For separating lists produced by ruby's Array#toSentence
|
||||||
function AwardsHandler() {
|
function AwardsHandler() {
|
||||||
this.aliases = gl.emojiAliases();
|
this.aliases = gl.emojiAliases();
|
||||||
$(document).off('click', '.js-add-award').on('click', '.js-add-award', (function(_this) {
|
$(document).off('click', '.js-add-award').on('click', '.js-add-award', (function(_this) {
|
||||||
|
@ -85,6 +86,8 @@
|
||||||
AwardsHandler.prototype.positionMenu = function($menu, $addBtn) {
|
AwardsHandler.prototype.positionMenu = function($menu, $addBtn) {
|
||||||
var css, position;
|
var css, position;
|
||||||
position = $addBtn.data('position');
|
position = $addBtn.data('position');
|
||||||
|
// The menu could potentially be off-screen or in a hidden overflow element
|
||||||
|
// So we position the element absolute in the body
|
||||||
css = {
|
css = {
|
||||||
top: ($addBtn.offset().top + $addBtn.outerHeight()) + "px"
|
top: ($addBtn.offset().top + $addBtn.outerHeight()) + "px"
|
||||||
};
|
};
|
||||||
|
@ -130,7 +133,7 @@
|
||||||
counter = $emojiButton.find('.js-counter');
|
counter = $emojiButton.find('.js-counter');
|
||||||
counter.text(parseInt(counter.text()) + 1);
|
counter.text(parseInt(counter.text()) + 1);
|
||||||
$emojiButton.addClass('active');
|
$emojiButton.addClass('active');
|
||||||
this.addMeToUserList(votesBlock, emoji);
|
this.addYouToUserList(votesBlock, emoji);
|
||||||
return this.animateEmoji($emojiButton);
|
return this.animateEmoji($emojiButton);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -176,11 +179,11 @@
|
||||||
counterNumber = parseInt(counter.text(), 10);
|
counterNumber = parseInt(counter.text(), 10);
|
||||||
if (counterNumber > 1) {
|
if (counterNumber > 1) {
|
||||||
counter.text(counterNumber - 1);
|
counter.text(counterNumber - 1);
|
||||||
this.removeMeFromUserList($emojiButton, emoji);
|
this.removeYouFromUserList($emojiButton, emoji);
|
||||||
} else if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
} else if (emoji === 'thumbsup' || emoji === 'thumbsdown') {
|
||||||
$emojiButton.tooltip('destroy');
|
$emojiButton.tooltip('destroy');
|
||||||
counter.text('0');
|
counter.text('0');
|
||||||
this.removeMeFromUserList($emojiButton, emoji);
|
this.removeYouFromUserList($emojiButton, emoji);
|
||||||
if ($emojiButton.parents('.note').length) {
|
if ($emojiButton.parents('.note').length) {
|
||||||
this.removeEmoji($emojiButton);
|
this.removeEmoji($emojiButton);
|
||||||
}
|
}
|
||||||
|
@ -204,43 +207,48 @@
|
||||||
return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || '';
|
return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
AwardsHandler.prototype.removeMeFromUserList = function($emojiButton, emoji) {
|
AwardsHandler.prototype.toSentence = function(list) {
|
||||||
|
if(list.length <= 2){
|
||||||
|
return list.join(' and ');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return list.slice(0, -1).join(', ') + ', and ' + list[list.length - 1];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AwardsHandler.prototype.removeYouFromUserList = function($emojiButton, emoji) {
|
||||||
var authors, awardBlock, newAuthors, originalTitle;
|
var authors, awardBlock, newAuthors, originalTitle;
|
||||||
awardBlock = $emojiButton;
|
awardBlock = $emojiButton;
|
||||||
originalTitle = this.getAwardTooltip(awardBlock);
|
originalTitle = this.getAwardTooltip(awardBlock);
|
||||||
authors = originalTitle.split(', ');
|
authors = originalTitle.split(FROM_SENTENCE_REGEX);
|
||||||
authors.splice(authors.indexOf('me'), 1);
|
authors.splice(authors.indexOf('You'), 1);
|
||||||
newAuthors = authors.join(', ');
|
return awardBlock
|
||||||
awardBlock.closest('.js-emoji-btn').removeData('original-title').attr('data-original-title', newAuthors);
|
.closest('.js-emoji-btn')
|
||||||
return this.resetTooltip(awardBlock);
|
.removeData('title')
|
||||||
|
.removeAttr('data-title')
|
||||||
|
.removeAttr('data-original-title')
|
||||||
|
.attr('title', this.toSentence(authors))
|
||||||
|
.tooltip('fixTitle');
|
||||||
};
|
};
|
||||||
|
|
||||||
AwardsHandler.prototype.addMeToUserList = function(votesBlock, emoji) {
|
AwardsHandler.prototype.addYouToUserList = function(votesBlock, emoji) {
|
||||||
var awardBlock, origTitle, users;
|
var awardBlock, origTitle, users;
|
||||||
awardBlock = this.findEmojiIcon(votesBlock, emoji).parent();
|
awardBlock = this.findEmojiIcon(votesBlock, emoji).parent();
|
||||||
origTitle = this.getAwardTooltip(awardBlock);
|
origTitle = this.getAwardTooltip(awardBlock);
|
||||||
users = [];
|
users = [];
|
||||||
if (origTitle) {
|
if (origTitle) {
|
||||||
users = origTitle.trim().split(', ');
|
users = origTitle.trim().split(FROM_SENTENCE_REGEX);
|
||||||
}
|
}
|
||||||
users.push('me');
|
users.unshift('You');
|
||||||
awardBlock.attr('title', users.join(', '));
|
return awardBlock
|
||||||
return this.resetTooltip(awardBlock);
|
.attr('title', this.toSentence(users))
|
||||||
};
|
.tooltip('fixTitle');
|
||||||
|
|
||||||
AwardsHandler.prototype.resetTooltip = function(award) {
|
|
||||||
var cb;
|
|
||||||
award.tooltip('destroy');
|
|
||||||
cb = function() {
|
|
||||||
return award.tooltip();
|
|
||||||
};
|
|
||||||
return setTimeout(cb, 200);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AwardsHandler.prototype.createEmoji_ = function(votesBlock, emoji) {
|
AwardsHandler.prototype.createEmoji_ = function(votesBlock, emoji) {
|
||||||
var $emojiButton, buttonHtml, emojiCssClass;
|
var $emojiButton, buttonHtml, emojiCssClass;
|
||||||
emojiCssClass = this.resolveNameToCssClass(emoji);
|
emojiCssClass = this.resolveNameToCssClass(emoji);
|
||||||
buttonHtml = "<button class='btn award-control js-emoji-btn has-tooltip active' title='me' data-placement='bottom'> <div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div> <span class='award-control-text js-counter'>1</span> </button>";
|
buttonHtml = "<button class='btn award-control js-emoji-btn has-tooltip active' title='You' data-placement='bottom'> <div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div> <span class='award-control-text js-counter'>1</span> </button>";
|
||||||
$emojiButton = $(buttonHtml);
|
$emojiButton = $(buttonHtml);
|
||||||
$emojiButton.insertBefore(votesBlock.find('.js-award-holder')).find('.emoji-icon').data('emoji', emoji);
|
$emojiButton.insertBefore(votesBlock.find('.js-award-holder')).find('.emoji-icon').data('emoji', emoji);
|
||||||
this.animateEmoji($emojiButton);
|
this.animateEmoji($emojiButton);
|
||||||
|
@ -249,12 +257,12 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
AwardsHandler.prototype.animateEmoji = function($emoji) {
|
AwardsHandler.prototype.animateEmoji = function($emoji) {
|
||||||
var className;
|
var className = 'pulse animated once short';
|
||||||
className = 'pulse animated';
|
|
||||||
$emoji.addClass(className);
|
$emoji.addClass(className);
|
||||||
return setTimeout((function() {
|
|
||||||
return $emoji.removeClass(className);
|
$emoji.on('webkitAnimationEnd animationEnd', function() {
|
||||||
}), 321);
|
$(this).removeClass(className);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
AwardsHandler.prototype.createEmoji = function(votesBlock, emoji) {
|
AwardsHandler.prototype.createEmoji = function(votesBlock, emoji) {
|
||||||
|
@ -278,6 +286,7 @@
|
||||||
if (emojiIcon.length > 0) {
|
if (emojiIcon.length > 0) {
|
||||||
unicodeName = emojiIcon.data('unicode-name');
|
unicodeName = emojiIcon.data('unicode-name');
|
||||||
} else {
|
} else {
|
||||||
|
// Find by alias
|
||||||
unicodeName = $(".emoji-menu-content [data-aliases*=':" + emoji + ":']").data('unicode-name');
|
unicodeName = $(".emoji-menu-content [data-aliases*=':" + emoji + ":']").data('unicode-name');
|
||||||
}
|
}
|
||||||
return "emoji-" + unicodeName;
|
return "emoji-" + unicodeName;
|
||||||
|
@ -314,6 +323,7 @@
|
||||||
frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
|
frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
|
||||||
frequentlyUsedEmojis.push(emoji);
|
frequentlyUsedEmojis.push(emoji);
|
||||||
return $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), {
|
return $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), {
|
||||||
|
path: gon.relative_url_root || '/',
|
||||||
expires: 365
|
expires: 365
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -343,8 +353,10 @@
|
||||||
return function(ev) {
|
return function(ev) {
|
||||||
var found_emojis, h5, term, ul;
|
var found_emojis, h5, term, ul;
|
||||||
term = $(ev.target).val();
|
term = $(ev.target).val();
|
||||||
|
// Clean previous search results
|
||||||
$('ul.emoji-menu-search, h5.emoji-search').remove();
|
$('ul.emoji-menu-search, h5.emoji-search').remove();
|
||||||
if (term) {
|
if (term) {
|
||||||
|
// Generate a search result block
|
||||||
h5 = $('<h5>').text('Search results');
|
h5 = $('<h5>').text('Search results');
|
||||||
found_emojis = _this.searchEmojis(term).show();
|
found_emojis = _this.searchEmojis(term).show();
|
||||||
ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(found_emojis);
|
ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(found_emojis);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
/*= require jquery.ba-resize */
|
/*= require jquery.ba-resize */
|
||||||
|
|
||||||
|
|
||||||
/*= require autosize */
|
/*= require autosize */
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
container = $(this).closest(".js-details-container");
|
container = $(this).closest(".js-details-container");
|
||||||
return container.toggleClass("open");
|
return container.toggleClass("open");
|
||||||
});
|
});
|
||||||
|
// Show details content. Hides link after click.
|
||||||
|
//
|
||||||
|
// %div
|
||||||
|
// %a.js-details-expand
|
||||||
|
// %div.js-details-content
|
||||||
|
//
|
||||||
return $("body").on("click", ".js-details-expand", function(e) {
|
return $("body").on("click", ".js-details-expand", function(e) {
|
||||||
$(this).next('.js-details-content').removeClass("hide");
|
$(this).next('.js-details-content').removeClass("hide");
|
||||||
$(this).hide();
|
$(this).hide();
|
||||||
|
|
|
@ -1,6 +1,20 @@
|
||||||
|
// Quick Submit behavior
|
||||||
|
//
|
||||||
|
// When a child field of a form with a `js-quick-submit` class receives a
|
||||||
|
// "Meta+Enter" (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, the form
|
||||||
|
// is submitted.
|
||||||
|
//
|
||||||
/*= require extensions/jquery */
|
/*= require extensions/jquery */
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### Example Markup
|
||||||
|
//
|
||||||
|
// <form action="/foo" class="js-quick-submit">
|
||||||
|
// <input type="text" />
|
||||||
|
// <textarea></textarea>
|
||||||
|
// <input type="submit" value="Submit" />
|
||||||
|
// </form>
|
||||||
|
//
|
||||||
(function() {
|
(function() {
|
||||||
var isMac, keyCodeIs;
|
var isMac, keyCodeIs;
|
||||||
|
|
||||||
|
@ -17,6 +31,7 @@
|
||||||
|
|
||||||
$(document).on('keydown.quick_submit', '.js-quick-submit', function(e) {
|
$(document).on('keydown.quick_submit', '.js-quick-submit', function(e) {
|
||||||
var $form, $submit_button;
|
var $form, $submit_button;
|
||||||
|
// Enter
|
||||||
if (!keyCodeIs(e, 13)) {
|
if (!keyCodeIs(e, 13)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -33,8 +48,11 @@
|
||||||
return $form.submit();
|
return $form.submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If the user tabs to a submit button on a `js-quick-submit` form, display a
|
||||||
|
// tooltip to let them know they could've used the hotkey
|
||||||
$(document).on('keyup.quick_submit', '.js-quick-submit input[type=submit], .js-quick-submit button[type=submit]', function(e) {
|
$(document).on('keyup.quick_submit', '.js-quick-submit input[type=submit], .js-quick-submit button[type=submit]', function(e) {
|
||||||
var $this, title;
|
var $this, title;
|
||||||
|
// Tab
|
||||||
if (!keyCodeIs(e, 9)) {
|
if (!keyCodeIs(e, 9)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
|
// Requires Input behavior
|
||||||
|
//
|
||||||
|
// When called on a form with input fields with the `required` attribute, the
|
||||||
|
// form's submit button will be disabled until all required fields have values.
|
||||||
|
//
|
||||||
/*= require extensions/jquery */
|
/*= require extensions/jquery */
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### Example Markup
|
||||||
|
//
|
||||||
|
// <form class="js-requires-input">
|
||||||
|
// <input type="text" required="required">
|
||||||
|
// <input type="submit" value="Submit">
|
||||||
|
// </form>
|
||||||
|
//
|
||||||
(function() {
|
(function() {
|
||||||
$.fn.requiresInput = function() {
|
$.fn.requiresInput = function() {
|
||||||
var $button, $form, fieldSelector, requireInput, required;
|
var $button, $form, fieldSelector, requireInput, required;
|
||||||
|
@ -11,14 +23,17 @@
|
||||||
requireInput = function() {
|
requireInput = function() {
|
||||||
var values;
|
var values;
|
||||||
values = _.map($(fieldSelector, $form), function(field) {
|
values = _.map($(fieldSelector, $form), function(field) {
|
||||||
|
// Collect the input values of *all* required fields
|
||||||
return field.value;
|
return field.value;
|
||||||
});
|
});
|
||||||
|
// Disable the button if any required fields are empty
|
||||||
if (values.length && _.any(values, _.isEmpty)) {
|
if (values.length && _.any(values, _.isEmpty)) {
|
||||||
return $button.disable();
|
return $button.disable();
|
||||||
} else {
|
} else {
|
||||||
return $button.enable();
|
return $button.enable();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Set initial button state
|
||||||
requireInput();
|
requireInput();
|
||||||
return $form.on('change input', fieldSelector, requireInput);
|
return $form.on('change input', fieldSelector, requireInput);
|
||||||
};
|
};
|
||||||
|
@ -27,6 +42,8 @@
|
||||||
var $form, hideOrShowHelpBlock;
|
var $form, hideOrShowHelpBlock;
|
||||||
$form = $('form.js-requires-input');
|
$form = $('form.js-requires-input');
|
||||||
$form.requiresInput();
|
$form.requiresInput();
|
||||||
|
// Hide or Show the help block when creating a new project
|
||||||
|
// based on the option selected
|
||||||
hideOrShowHelpBlock = function(form) {
|
hideOrShowHelpBlock = function(form) {
|
||||||
var selected;
|
var selected;
|
||||||
selected = $('.js-select-namespace option:selected');
|
selected = $('.js-select-namespace option:selected');
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
(function(w) {
|
(function(w) {
|
||||||
$(function() {
|
$(function() {
|
||||||
$('.js-toggle-button').on('click', function(e) {
|
// Toggle button. Show/hide content inside parent container.
|
||||||
|
// Button does not change visibility. If button has icon - it changes chevron style.
|
||||||
|
//
|
||||||
|
// %div.js-toggle-container
|
||||||
|
// %a.js-toggle-button
|
||||||
|
// %div.js-toggle-content
|
||||||
|
//
|
||||||
|
$('body').on('click', '.js-toggle-button', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$(this)
|
$(this)
|
||||||
.find('.fa')
|
.find('.fa')
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
autoDiscover: false,
|
autoDiscover: false,
|
||||||
autoProcessQueue: false,
|
autoProcessQueue: false,
|
||||||
url: form.attr('action'),
|
url: form.attr('action'),
|
||||||
|
// Rails uses a hidden input field for PUT
|
||||||
|
// http://stackoverflow.com/questions/21056482/how-to-set-method-put-in-form-tag-in-rails
|
||||||
method: method,
|
method: method,
|
||||||
clickable: true,
|
clickable: true,
|
||||||
uploadMultiple: false,
|
uploadMultiple: false,
|
||||||
|
@ -36,6 +38,7 @@
|
||||||
formData.append('commit_message', form.find('.js-commit-message').val());
|
formData.append('commit_message', form.find('.js-commit-message').val());
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// Override behavior of adding error underneath preview
|
||||||
error: function(file, errorMessage) {
|
error: function(file, errorMessage) {
|
||||||
var stripped;
|
var stripped;
|
||||||
stripped = $("<div/>").html(errorMessage).text();
|
stripped = $("<div/>").html(errorMessage).text();
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
this.buildDropdown();
|
this.buildDropdown();
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
this.onFilenameUpdate();
|
this.onFilenameUpdate();
|
||||||
|
|
||||||
|
this.autosizeUpdateEvent = document.createEvent('Event');
|
||||||
|
this.autosizeUpdateEvent.initEvent('autosize:update', true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateSelector.prototype.buildDropdown = function() {
|
TemplateSelector.prototype.buildDropdown = function() {
|
||||||
|
@ -66,9 +69,16 @@
|
||||||
// be added by all subclasses.
|
// be added by all subclasses.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// To be implemented on the extending class
|
||||||
|
// e.g.
|
||||||
|
// Api.gitignoreText item.name, @requestFileSuccess.bind(@)
|
||||||
TemplateSelector.prototype.requestFileSuccess = function(file, skipFocus) {
|
TemplateSelector.prototype.requestFileSuccess = function(file, skipFocus) {
|
||||||
this.editor.setValue(file.content, 1);
|
this.editor.setValue(file.content, 1);
|
||||||
if (!skipFocus) this.editor.focus();
|
if (!skipFocus) this.editor.focus();
|
||||||
|
|
||||||
|
if (this.editor instanceof jQuery) {
|
||||||
|
this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TemplateSelector.prototype.startLoadingSpinner = function() {
|
TemplateSelector.prototype.startLoadingSpinner = function() {
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
return function() {
|
return function() {
|
||||||
return $("#file-content").val(_this.editor.getValue());
|
return $("#file-content").val(_this.editor.getValue());
|
||||||
};
|
};
|
||||||
|
// Before a form submission, move the content from the Ace editor into the
|
||||||
|
// submitted textarea
|
||||||
})(this));
|
})(this));
|
||||||
this.initModePanesAndLinks();
|
this.initModePanesAndLinks();
|
||||||
new BlobLicenseSelectors({
|
new BlobLicenseSelectors({
|
||||||
|
|
|
@ -54,4 +54,11 @@ $(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gl.IssueBoardsSearch = new Vue({
|
||||||
|
el: '#js-boards-seach',
|
||||||
|
data: {
|
||||||
|
filters: Store.state.filters
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,15 +21,10 @@
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
query: '',
|
|
||||||
filters: Store.state.filters
|
filters: Store.state.filters
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
query () {
|
|
||||||
this.list.filters = this.getFilterData();
|
|
||||||
this.list.getIssues(true);
|
|
||||||
},
|
|
||||||
filters: {
|
filters: {
|
||||||
handler () {
|
handler () {
|
||||||
this.list.page = 1;
|
this.list.page = 1;
|
||||||
|
@ -38,16 +33,6 @@
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
|
||||||
getFilterData () {
|
|
||||||
const filters = this.filters;
|
|
||||||
let queryData = { search: this.query };
|
|
||||||
|
|
||||||
Object.keys(filters).forEach((key) => { queryData[key] = filters[key]; });
|
|
||||||
|
|
||||||
return queryData;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ready () {
|
ready () {
|
||||||
const options = gl.issueBoards.getBoardSortableDefaultOptions({
|
const options = gl.issueBoards.getBoardSortableDefaultOptions({
|
||||||
disabled: this.disabled,
|
disabled: this.disabled,
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
scrollOffset: 250,
|
scrollOffset: 250,
|
||||||
filters: Store.state.filters
|
filters: Store.state.filters,
|
||||||
|
showCount: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -30,6 +31,20 @@
|
||||||
this.$els.list.scrollTop = 0;
|
this.$els.list.scrollTop = 0;
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
|
},
|
||||||
|
issues () {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.scrollHeight() <= this.listHeight() && this.list.issuesSize > this.list.issues.length) {
|
||||||
|
this.list.page++;
|
||||||
|
this.list.getIssues(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.scrollHeight() > this.listHeight()) {
|
||||||
|
this.showCount = true;
|
||||||
|
} else {
|
||||||
|
this.showCount = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -58,6 +73,7 @@
|
||||||
group: 'issues',
|
group: 'issues',
|
||||||
sort: false,
|
sort: false,
|
||||||
disabled: this.disabled,
|
disabled: this.disabled,
|
||||||
|
filter: '.board-list-count',
|
||||||
onStart: (e) => {
|
onStart: (e) => {
|
||||||
const card = this.$refs.issue[e.oldIndex];
|
const card = this.$refs.issue[e.oldIndex];
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ class List {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.loadingMore = false;
|
this.loadingMore = false;
|
||||||
this.issues = [];
|
this.issues = [];
|
||||||
|
this.issuesSize = 0;
|
||||||
|
|
||||||
if (obj.label) {
|
if (obj.label) {
|
||||||
this.label = new ListLabel(obj.label);
|
this.label = new ListLabel(obj.label);
|
||||||
|
@ -51,17 +52,13 @@ class List {
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPage () {
|
nextPage () {
|
||||||
if (Math.floor(this.issues.length / 20) === this.page) {
|
if (this.issuesSize > this.issues.length) {
|
||||||
this.page++;
|
this.page++;
|
||||||
|
|
||||||
return this.getIssues(false);
|
return this.getIssues(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
canSearch () {
|
|
||||||
return this.type === 'backlog';
|
|
||||||
}
|
|
||||||
|
|
||||||
getIssues (emptyIssues = true) {
|
getIssues (emptyIssues = true) {
|
||||||
const filters = this.filters;
|
const filters = this.filters;
|
||||||
let data = { page: this.page };
|
let data = { page: this.page };
|
||||||
|
@ -80,12 +77,13 @@ class List {
|
||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
const data = resp.json();
|
const data = resp.json();
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
this.issuesSize = data.size;
|
||||||
|
|
||||||
if (emptyIssues) {
|
if (emptyIssues) {
|
||||||
this.issues = [];
|
this.issues = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createIssues(data);
|
this.createIssues(data.issues);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,14 +94,20 @@ class List {
|
||||||
}
|
}
|
||||||
|
|
||||||
addIssue (issue, listFrom) {
|
addIssue (issue, listFrom) {
|
||||||
this.issues.push(issue);
|
if (!this.findIssue(issue.id)) {
|
||||||
|
this.issues.push(issue);
|
||||||
|
|
||||||
if (this.label) {
|
if (this.label) {
|
||||||
issue.addLabel(this.label);
|
issue.addLabel(this.label);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listFrom) {
|
if (listFrom) {
|
||||||
gl.boardService.moveIssue(issue.id, listFrom.id, this.id);
|
this.issuesSize++;
|
||||||
|
gl.boardService.moveIssue(issue.id, listFrom.id, this.id)
|
||||||
|
.then(() => {
|
||||||
|
listFrom.getIssues(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +120,7 @@ class List {
|
||||||
const matchesRemove = removeIssue.id === issue.id;
|
const matchesRemove = removeIssue.id === issue.id;
|
||||||
|
|
||||||
if (matchesRemove) {
|
if (matchesRemove) {
|
||||||
|
this.issuesSize--;
|
||||||
issue.removeLabel(this.label);
|
issue.removeLabel(this.label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
author_id: gl.utils.getParameterValues('author_id')[0],
|
author_id: gl.utils.getParameterValues('author_id')[0],
|
||||||
assignee_id: gl.utils.getParameterValues('assignee_id')[0],
|
assignee_id: gl.utils.getParameterValues('assignee_id')[0],
|
||||||
milestone_title: gl.utils.getParameterValues('milestone_title')[0],
|
milestone_title: gl.utils.getParameterValues('milestone_title')[0],
|
||||||
label_name: gl.utils.getParameterValues('label_name[]')
|
label_name: gl.utils.getParameterValues('label_name[]'),
|
||||||
|
search: ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
addList (listObj) {
|
addList (listObj) {
|
||||||
|
|
0
app/assets/javascripts/boards/test_utils/simulate_drag.js
Executable file → Normal file
0
app/assets/javascripts/boards/test_utils/simulate_drag.js
Executable file → Normal file
|
@ -1,10 +1,7 @@
|
||||||
Vue.http.interceptors.push((request, next) => {
|
Vue.http.interceptors.push((request, next) => {
|
||||||
Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1;
|
Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1;
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
next(function (response) {
|
||||||
setTimeout(() => {
|
Vue.activeResources--;
|
||||||
Vue.activeResources--;
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
next();
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
if ($(allDeviceSelector.join(",")).length) {
|
if ($(allDeviceSelector.join(",")).length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Create all the elements
|
||||||
els = $.map(BREAKPOINTS, function(breakpoint) {
|
els = $.map(BREAKPOINTS, function(breakpoint) {
|
||||||
return "<div class='device-" + breakpoint + " visible-" + breakpoint + "'></div>";
|
return "<div class='device-" + breakpoint + " visible-" + breakpoint + "'></div>";
|
||||||
});
|
});
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
BreakpointInstance.prototype.getBreakpointSize = function() {
|
BreakpointInstance.prototype.getBreakpointSize = function() {
|
||||||
var $visibleDevice;
|
var $visibleDevice;
|
||||||
$visibleDevice = this.visibleDevice;
|
$visibleDevice = this.visibleDevice;
|
||||||
|
// the page refreshed via turbolinks
|
||||||
if (!$visibleDevice().length) {
|
if (!$visibleDevice().length) {
|
||||||
this.setup();
|
this.setup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
this.toggleSidebar = bind(this.toggleSidebar, this);
|
this.toggleSidebar = bind(this.toggleSidebar, this);
|
||||||
this.updateDropdown = bind(this.updateDropdown, this);
|
this.updateDropdown = bind(this.updateDropdown, this);
|
||||||
clearInterval(Build.interval);
|
clearInterval(Build.interval);
|
||||||
|
// Init breakpoint checker
|
||||||
this.bp = Breakpoints.get();
|
this.bp = Breakpoints.get();
|
||||||
$('.js-build-sidebar').niceScroll();
|
$('.js-build-sidebar').niceScroll();
|
||||||
|
|
||||||
|
@ -26,10 +27,11 @@
|
||||||
$(document).off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
|
$(document).off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
|
||||||
$(window).off('resize.build').on('resize.build', this.hideSidebar);
|
$(window).off('resize.build').on('resize.build', this.hideSidebar);
|
||||||
$(document).off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
|
$(document).off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
|
||||||
|
$('#js-build-scroll > a').off('click').on('click', this.stepTrace);
|
||||||
this.updateArtifactRemoveDate();
|
this.updateArtifactRemoveDate();
|
||||||
if ($('#build-trace').length) {
|
if ($('#build-trace').length) {
|
||||||
this.getInitialBuildTrace();
|
this.getInitialBuildTrace();
|
||||||
this.initScrollButtonAffix();
|
this.initScrollButtons();
|
||||||
}
|
}
|
||||||
if (this.build_status === "running" || this.build_status === "pending") {
|
if (this.build_status === "running" || this.build_status === "pending") {
|
||||||
$('#autoscroll-button').on('click', function() {
|
$('#autoscroll-button').on('click', function() {
|
||||||
|
@ -42,6 +44,9 @@
|
||||||
$(this).data("state", "enabled");
|
$(this).data("state", "enabled");
|
||||||
return $(this).text("disable autoscroll");
|
return $(this).text("disable autoscroll");
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// Bind autoscroll button to follow build output
|
||||||
|
//
|
||||||
});
|
});
|
||||||
Build.interval = setInterval((function(_this) {
|
Build.interval = setInterval((function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
|
@ -49,17 +54,23 @@
|
||||||
return _this.getBuildTrace();
|
return _this.getBuildTrace();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
//
|
||||||
|
// Check for new build output if user still watching build page
|
||||||
|
// Only valid for runnig build when output changes during time
|
||||||
|
//
|
||||||
})(this), 4000);
|
})(this), 4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Build.prototype.getInitialBuildTrace = function() {
|
Build.prototype.getInitialBuildTrace = function() {
|
||||||
|
var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped']
|
||||||
|
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: this.build_url,
|
url: this.build_url,
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(build_data) {
|
success: function(build_data) {
|
||||||
$('.js-build-output').html(build_data.trace_html);
|
$('.js-build-output').html(build_data.trace_html);
|
||||||
if (build_data.status === 'success' || build_data.status === 'failed') {
|
if (removeRefreshStatuses.indexOf(build_data.status) >= 0) {
|
||||||
return $('.js-build-refresh').remove();
|
return $('.js-build-refresh').remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +107,7 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.initScrollButtonAffix = function() {
|
Build.prototype.initScrollButtons = function() {
|
||||||
var $body, $buildScroll, $buildTrace;
|
var $body, $buildScroll, $buildTrace;
|
||||||
$buildScroll = $('#js-build-scroll');
|
$buildScroll = $('#js-build-scroll');
|
||||||
$body = $('body');
|
$body = $('body');
|
||||||
|
@ -155,6 +166,14 @@
|
||||||
this.populateJobs(stage);
|
this.populateJobs(stage);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Build.prototype.stepTrace = function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$currentTarget = $(e.currentTarget);
|
||||||
|
$.scrollTo($currentTarget.attr('href'), {
|
||||||
|
offset: -($('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight())
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return Build;
|
return Build;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
6
app/assets/javascripts/build_variables.js.es6
Normal file
6
app/assets/javascripts/build_variables.js.es6
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
$(function(){
|
||||||
|
$('.reveal-variables').off('click').on('click',function(){
|
||||||
|
$('.js-build').toggle().niceScroll();
|
||||||
|
$(this).hide();
|
||||||
|
});
|
||||||
|
});
|
|
@ -2,6 +2,7 @@
|
||||||
this.ImageFile = (function() {
|
this.ImageFile = (function() {
|
||||||
var prepareFrames;
|
var prepareFrames;
|
||||||
|
|
||||||
|
// Width where images must fits in, for 2-up this gets divided by 2
|
||||||
ImageFile.availWidth = 900;
|
ImageFile.availWidth = 900;
|
||||||
|
|
||||||
ImageFile.viewModes = ['two-up', 'swipe'];
|
ImageFile.viewModes = ['two-up', 'swipe'];
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
function ImageFile(file) {
|
function ImageFile(file) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) {
|
this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) {
|
||||||
|
// Determine if old and new file has same dimensions, if not show 'two-up' view
|
||||||
return function(deletedWidth, deletedHeight) {
|
return function(deletedWidth, deletedHeight) {
|
||||||
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) {
|
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) {
|
||||||
if (width === deletedWidth && height === deletedHeight) {
|
if (width === deletedWidth && height === deletedHeight) {
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
CommitsList.content.html(data.html);
|
CommitsList.content.html(data.html);
|
||||||
return history.replaceState({
|
return history.replaceState({
|
||||||
page: commitsUrl
|
page: commitsUrl
|
||||||
|
// Change url so if user reload a page - search results are saved
|
||||||
}, document.title, commitsUrl);
|
}, document.title, commitsUrl);
|
||||||
},
|
},
|
||||||
dataType: "json"
|
dataType: "json"
|
||||||
|
|
|
@ -6,14 +6,19 @@
|
||||||
|
|
||||||
genericSuccess = function(e) {
|
genericSuccess = function(e) {
|
||||||
showTooltip(e.trigger, 'Copied!');
|
showTooltip(e.trigger, 'Copied!');
|
||||||
|
// Clear the selection and blur the trigger so it loses its border
|
||||||
e.clearSelection();
|
e.clearSelection();
|
||||||
return $(e.trigger).blur();
|
return $(e.trigger).blur();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Safari doesn't support `execCommand`, so instead we inform the user to
|
||||||
|
// copy manually.
|
||||||
|
//
|
||||||
|
// See http://clipboardjs.com/#browser-support
|
||||||
genericError = function(e) {
|
genericError = function(e) {
|
||||||
var key;
|
var key;
|
||||||
if (/Mac/i.test(navigator.userAgent)) {
|
if (/Mac/i.test(navigator.userAgent)) {
|
||||||
key = '⌘';
|
key = '⌘'; // Command
|
||||||
} else {
|
} else {
|
||||||
key = 'Ctrl';
|
key = 'Ctrl';
|
||||||
}
|
}
|
||||||
|
|
93
app/assets/javascripts/cycle-analytics.js.es6
Normal file
93
app/assets/javascripts/cycle-analytics.js.es6
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
((global) => {
|
||||||
|
|
||||||
|
const COOKIE_NAME = 'cycle_analytics_help_dismissed';
|
||||||
|
const store = gl.cycleAnalyticsStore = {
|
||||||
|
isLoading: true,
|
||||||
|
hasError: false,
|
||||||
|
isHelpDismissed: $.cookie(COOKIE_NAME),
|
||||||
|
analytics: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
gl.CycleAnalytics = class CycleAnalytics {
|
||||||
|
constructor() {
|
||||||
|
const that = this;
|
||||||
|
|
||||||
|
this.vue = new Vue({
|
||||||
|
el: '#cycle-analytics',
|
||||||
|
name: 'CycleAnalytics',
|
||||||
|
created: this.fetchData(),
|
||||||
|
data: store,
|
||||||
|
methods: {
|
||||||
|
dismissLanding() {
|
||||||
|
that.dismissLanding();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData(options) {
|
||||||
|
store.isLoading = true;
|
||||||
|
options = options || { startDate: 30 };
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: $('#cycle-analytics').data('request-path'),
|
||||||
|
method: 'GET',
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: { start_date: options.startDate }
|
||||||
|
}).done((data) => {
|
||||||
|
this.decorateData(data);
|
||||||
|
this.initDropdown();
|
||||||
|
})
|
||||||
|
.error((data) => {
|
||||||
|
this.handleError(data);
|
||||||
|
})
|
||||||
|
.always(() => {
|
||||||
|
store.isLoading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
decorateData(data) {
|
||||||
|
data.summary = data.summary || [];
|
||||||
|
data.stats = data.stats || [];
|
||||||
|
|
||||||
|
data.summary.forEach((item) => {
|
||||||
|
item.value = item.value || '-';
|
||||||
|
});
|
||||||
|
|
||||||
|
data.stats.forEach((item) => {
|
||||||
|
item.value = item.value || '- - -';
|
||||||
|
});
|
||||||
|
|
||||||
|
store.analytics = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(data) {
|
||||||
|
store.hasError = true;
|
||||||
|
new Flash('There was an error while fetching cycle analytics data.', 'alert');
|
||||||
|
}
|
||||||
|
|
||||||
|
dismissLanding() {
|
||||||
|
store.isHelpDismissed = true;
|
||||||
|
$.cookie(COOKIE_NAME, true, {
|
||||||
|
path: gon.relative_url_root || '/'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initDropdown() {
|
||||||
|
const $dropdown = $('.js-ca-dropdown');
|
||||||
|
const $label = $dropdown.find('.dropdown-label');
|
||||||
|
|
||||||
|
$dropdown.find('li a').off('click').on('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const $target = $(e.currentTarget);
|
||||||
|
const value = $target.data('value');
|
||||||
|
|
||||||
|
$label.text($target.text().trim());
|
||||||
|
this.fetchData({ startDate: value });
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})(window.gl || (window.gl = {}));
|
|
@ -39,6 +39,9 @@
|
||||||
bottom: unfoldBottom,
|
bottom: unfoldBottom,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
unfold: unfold,
|
unfold: unfold,
|
||||||
|
// indent is used to compensate for single space indent to fit
|
||||||
|
// '+' and '-' prepended to diff lines,
|
||||||
|
// see https://gitlab.com/gitlab-org/gitlab-ce/issues/707
|
||||||
indent: 1,
|
indent: 1,
|
||||||
view: file.data('view')
|
view: file.data('view')
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
case 'projects:boards:show':
|
case 'projects:boards:show':
|
||||||
shortcut_handler = new ShortcutsNavigation();
|
shortcut_handler = new ShortcutsNavigation();
|
||||||
break;
|
break;
|
||||||
|
case 'projects:merge_requests:index':
|
||||||
case 'projects:issues:index':
|
case 'projects:issues:index':
|
||||||
Issuable.init();
|
Issuable.init();
|
||||||
new IssuableBulkActions();
|
new IssuableBulkActions();
|
||||||
|
@ -93,6 +94,7 @@
|
||||||
break;
|
break;
|
||||||
case "projects:merge_requests:conflicts":
|
case "projects:merge_requests:conflicts":
|
||||||
window.mcui = new MergeConflictResolver()
|
window.mcui = new MergeConflictResolver()
|
||||||
|
break;
|
||||||
case 'projects:merge_requests:index':
|
case 'projects:merge_requests:index':
|
||||||
shortcut_handler = new ShortcutsNavigation();
|
shortcut_handler = new ShortcutsNavigation();
|
||||||
Issuable.init();
|
Issuable.init();
|
||||||
|
@ -167,6 +169,8 @@
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'projects:network:show':
|
case 'projects:network:show':
|
||||||
|
// Ensure we don't create a particular shortcut handler here. This is
|
||||||
|
// already created, where the network graph is created.
|
||||||
shortcut_handler = true;
|
shortcut_handler = true;
|
||||||
break;
|
break;
|
||||||
case 'projects:forks:new':
|
case 'projects:forks:new':
|
||||||
|
@ -186,6 +190,9 @@
|
||||||
new gl.ProtectedBranchCreate();
|
new gl.ProtectedBranchCreate();
|
||||||
new gl.ProtectedBranchEditList();
|
new gl.ProtectedBranchEditList();
|
||||||
break;
|
break;
|
||||||
|
case 'projects:cycle_analytics:show':
|
||||||
|
new gl.CycleAnalytics();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
switch (path.first()) {
|
switch (path.first()) {
|
||||||
case 'admin':
|
case 'admin':
|
||||||
|
@ -199,9 +206,13 @@
|
||||||
break;
|
break;
|
||||||
case 'labels':
|
case 'labels':
|
||||||
switch (path[2]) {
|
switch (path[2]) {
|
||||||
|
case 'new':
|
||||||
case 'edit':
|
case 'edit':
|
||||||
new Labels();
|
new Labels();
|
||||||
}
|
}
|
||||||
|
case 'abuse_reports':
|
||||||
|
new gl.AbuseReports();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'dashboard':
|
case 'dashboard':
|
||||||
|
@ -259,12 +270,14 @@
|
||||||
shortcut_handler = new ShortcutsNavigation();
|
shortcut_handler = new ShortcutsNavigation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If we haven't installed a custom shortcut handler, install the default one
|
||||||
if (!shortcut_handler) {
|
if (!shortcut_handler) {
|
||||||
return new Shortcuts();
|
return new Shortcuts();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Dispatcher.prototype.initSearch = function() {
|
Dispatcher.prototype.initSearch = function() {
|
||||||
|
// Only when search form is present
|
||||||
if ($('.search').length) {
|
if ($('.search').length) {
|
||||||
return new SearchAutocomplete();
|
return new SearchAutocomplete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
this.DueDateSelect = (function() {
|
this.DueDateSelect = (function() {
|
||||||
function DueDateSelect() {
|
function DueDateSelect() {
|
||||||
var $datePicker, $dueDate, $loading;
|
var $datePicker, $dueDate, $loading;
|
||||||
|
// Milestone edit/new form
|
||||||
$datePicker = $('.datepicker');
|
$datePicker = $('.datepicker');
|
||||||
if ($datePicker.length) {
|
if ($datePicker.length) {
|
||||||
$dueDate = $('#milestone_due_date');
|
$dueDate = $('#milestone_due_date');
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return $.datepicker._clearDate($datePicker);
|
return $.datepicker._clearDate($datePicker);
|
||||||
});
|
});
|
||||||
|
// Issuable sidebar
|
||||||
$loading = $('.js-issuable-update .due_date').find('.block-loading').hide();
|
$loading = $('.js-issuable-update .due_date').find('.block-loading').hide();
|
||||||
$('.js-due-date-select').each(function(i, dropdown) {
|
$('.js-due-date-select').each(function(i, dropdown) {
|
||||||
var $block, $dropdown, $dropdownParent, $selectbox, $sidebarValue, $value, $valueContent, abilityName, addDueDate, fieldName, issueUpdateURL;
|
var $block, $dropdown, $dropdownParent, $selectbox, $sidebarValue, $value, $valueContent, abilityName, addDueDate, fieldName, issueUpdateURL;
|
||||||
|
@ -38,6 +40,7 @@
|
||||||
});
|
});
|
||||||
addDueDate = function(isDropdown) {
|
addDueDate = function(isDropdown) {
|
||||||
var data, date, mediumDate, value;
|
var data, date, mediumDate, value;
|
||||||
|
// Create the post date
|
||||||
value = $("input[name='" + fieldName + "']").val();
|
value = $("input[name='" + fieldName + "']").val();
|
||||||
if (value !== '') {
|
if (value !== '') {
|
||||||
date = new Date(value.replace(new RegExp('-', 'g'), ','));
|
date = new Date(value.replace(new RegExp('-', 'g'), ','));
|
||||||
|
|
2
app/assets/javascripts/extensions/jquery.js
vendored
2
app/assets/javascripts/extensions/jquery.js
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
// Disable an element and add the 'disabled' Bootstrap class
|
||||||
(function() {
|
(function() {
|
||||||
$.fn.extend({
|
$.fn.extend({
|
||||||
disable: function() {
|
disable: function() {
|
||||||
|
@ -5,6 +6,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Enable an element and remove the 'disabled' Bootstrap class
|
||||||
$.fn.extend({
|
$.fn.extend({
|
||||||
enable: function() {
|
enable: function() {
|
||||||
return $(this).removeAttr('disabled').removeClass('disabled');
|
return $(this).removeAttr('disabled').removeClass('disabled');
|
||||||
|
|
|
@ -39,12 +39,13 @@
|
||||||
FilesCommentButton.prototype.render = function(e) {
|
FilesCommentButton.prototype.render = function(e) {
|
||||||
var $currentTarget, buttonParentElement, lineContentElement, textFileElement;
|
var $currentTarget, buttonParentElement, lineContentElement, textFileElement;
|
||||||
$currentTarget = $(e.currentTarget);
|
$currentTarget = $(e.currentTarget);
|
||||||
|
|
||||||
buttonParentElement = this.getButtonParent($currentTarget);
|
buttonParentElement = this.getButtonParent($currentTarget);
|
||||||
if (!this.shouldRender(e, buttonParentElement)) {
|
if (!this.validateButtonParent(buttonParentElement)) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
textFileElement = this.getTextFileElement($currentTarget);
|
|
||||||
lineContentElement = this.getLineContent($currentTarget);
|
lineContentElement = this.getLineContent($currentTarget);
|
||||||
|
if (!this.validateLineContent(lineContentElement)) return;
|
||||||
|
|
||||||
|
textFileElement = this.getTextFileElement($currentTarget);
|
||||||
buttonParentElement.append(this.buildButton({
|
buttonParentElement.append(this.buildButton({
|
||||||
noteableType: textFileElement.attr('data-noteable-type'),
|
noteableType: textFileElement.attr('data-noteable-type'),
|
||||||
noteableID: textFileElement.attr('data-noteable-id'),
|
noteableID: textFileElement.attr('data-noteable-id'),
|
||||||
|
@ -119,10 +120,14 @@
|
||||||
return newButtonParent.is(this.getButtonParent($(e.currentTarget)));
|
return newButtonParent.is(this.getButtonParent($(e.currentTarget)));
|
||||||
};
|
};
|
||||||
|
|
||||||
FilesCommentButton.prototype.shouldRender = function(e, buttonParentElement) {
|
FilesCommentButton.prototype.validateButtonParent = function(buttonParentElement) {
|
||||||
return !buttonParentElement.hasClass(EMPTY_CELL_CLASS) && !buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS) && $(COMMENT_BUTTON_CLASS, buttonParentElement).length === 0;
|
return !buttonParentElement.hasClass(EMPTY_CELL_CLASS) && !buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS) && $(COMMENT_BUTTON_CLASS, buttonParentElement).length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FilesCommentButton.prototype.validateLineContent = function(lineContentElement) {
|
||||||
|
return lineContentElement.attr('data-discussion-id') && lineContentElement.attr('data-discussion-id') !== '';
|
||||||
|
};
|
||||||
|
|
||||||
return FilesCommentButton;
|
return FilesCommentButton;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Creates the variables for setting up GFM auto-completion
|
||||||
(function() {
|
(function() {
|
||||||
if (window.GitLab == null) {
|
if (window.GitLab == null) {
|
||||||
window.GitLab = {};
|
window.GitLab = {};
|
||||||
|
@ -8,18 +9,22 @@
|
||||||
dataLoaded: false,
|
dataLoaded: false,
|
||||||
cachedData: {},
|
cachedData: {},
|
||||||
dataSource: '',
|
dataSource: '',
|
||||||
|
// Emoji
|
||||||
Emoji: {
|
Emoji: {
|
||||||
template: '<li>${name} <img alt="${name}" height="20" src="${path}" width="20" /></li>'
|
template: '<li>${name} <img alt="${name}" height="20" src="${path}" width="20" /></li>'
|
||||||
},
|
},
|
||||||
|
// Team Members
|
||||||
Members: {
|
Members: {
|
||||||
template: '<li>${username} <small>${title}</small></li>'
|
template: '<li>${username} <small>${title}</small></li>'
|
||||||
},
|
},
|
||||||
Labels: {
|
Labels: {
|
||||||
template: '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>'
|
template: '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>'
|
||||||
},
|
},
|
||||||
|
// Issues and MergeRequests
|
||||||
Issues: {
|
Issues: {
|
||||||
template: '<li><small>${id}</small> ${title}</li>'
|
template: '<li><small>${id}</small> ${title}</li>'
|
||||||
},
|
},
|
||||||
|
// Milestones
|
||||||
Milestones: {
|
Milestones: {
|
||||||
template: '<li>${title}</li>'
|
template: '<li>${title}</li>'
|
||||||
},
|
},
|
||||||
|
@ -48,8 +53,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup: function(input) {
|
setup: function(input) {
|
||||||
|
// Add GFM auto-completion to all input fields, that accept GFM input.
|
||||||
this.input = input || $('.js-gfm-input');
|
this.input = input || $('.js-gfm-input');
|
||||||
|
// destroy previous instances
|
||||||
this.destroyAtWho();
|
this.destroyAtWho();
|
||||||
|
// set up instances
|
||||||
this.setupAtWho();
|
this.setupAtWho();
|
||||||
if (this.dataSource) {
|
if (this.dataSource) {
|
||||||
if (!this.dataLoading && !this.cachedData) {
|
if (!this.dataLoading && !this.cachedData) {
|
||||||
|
@ -63,6 +71,11 @@
|
||||||
return _this.loadData(data);
|
return _this.loadData(data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// We should wait until initializations are done
|
||||||
|
// and only trigger the last .setup since
|
||||||
|
// The previous .dataSource belongs to the previous issuable
|
||||||
|
// and the last one will have the **proper** .dataSource property
|
||||||
|
// TODO: Make this a singleton and turn off events when moving to another page
|
||||||
})(this), 1000);
|
})(this), 1000);
|
||||||
}
|
}
|
||||||
if (this.cachedData != null) {
|
if (this.cachedData != null) {
|
||||||
|
@ -71,6 +84,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setupAtWho: function() {
|
setupAtWho: function() {
|
||||||
|
// Emoji
|
||||||
this.input.atwho({
|
this.input.atwho({
|
||||||
at: ':',
|
at: ':',
|
||||||
displayTpl: (function(_this) {
|
displayTpl: (function(_this) {
|
||||||
|
@ -90,6 +104,7 @@
|
||||||
beforeInsert: this.DefaultOptions.beforeInsert
|
beforeInsert: this.DefaultOptions.beforeInsert
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Team Members
|
||||||
this.input.atwho({
|
this.input.atwho({
|
||||||
at: '@',
|
at: '@',
|
||||||
displayTpl: (function(_this) {
|
displayTpl: (function(_this) {
|
||||||
|
@ -321,13 +336,22 @@
|
||||||
loadData: function(data) {
|
loadData: function(data) {
|
||||||
this.cachedData = data;
|
this.cachedData = data;
|
||||||
this.dataLoaded = true;
|
this.dataLoaded = true;
|
||||||
|
// load members
|
||||||
this.input.atwho('load', '@', data.members);
|
this.input.atwho('load', '@', data.members);
|
||||||
|
// load issues
|
||||||
this.input.atwho('load', 'issues', data.issues);
|
this.input.atwho('load', 'issues', data.issues);
|
||||||
|
// load milestones
|
||||||
this.input.atwho('load', 'milestones', data.milestones);
|
this.input.atwho('load', 'milestones', data.milestones);
|
||||||
|
// load merge requests
|
||||||
this.input.atwho('load', 'mergerequests', data.mergerequests);
|
this.input.atwho('load', 'mergerequests', data.mergerequests);
|
||||||
|
// load emojis
|
||||||
this.input.atwho('load', ':', data.emojis);
|
this.input.atwho('load', ':', data.emojis);
|
||||||
|
// load labels
|
||||||
this.input.atwho('load', '~', data.labels);
|
this.input.atwho('load', '~', data.labels);
|
||||||
|
// load commands
|
||||||
this.input.atwho('load', '/', data.commands);
|
this.input.atwho('load', '/', data.commands);
|
||||||
|
// This trigger at.js again
|
||||||
|
// otherwise we would be stuck with loading until the user types
|
||||||
return $(':focus').trigger('keyup');
|
return $(':focus').trigger('keyup');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,12 +21,14 @@
|
||||||
$clearButton = $inputContainer.find('.js-dropdown-input-clear');
|
$clearButton = $inputContainer.find('.js-dropdown-input-clear');
|
||||||
this.indeterminateIds = [];
|
this.indeterminateIds = [];
|
||||||
$clearButton.on('click', (function(_this) {
|
$clearButton.on('click', (function(_this) {
|
||||||
|
// Clear click
|
||||||
return function(e) {
|
return function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
return _this.input.val('').trigger('keyup').focus();
|
return _this.input.val('').trigger('keyup').focus();
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
|
// Key events
|
||||||
timeout = "";
|
timeout = "";
|
||||||
this.input
|
this.input
|
||||||
.on('keydown', function (e) {
|
.on('keydown', function (e) {
|
||||||
|
@ -49,6 +51,7 @@
|
||||||
if (keyCode === 13 && !options.elIsInput) {
|
if (keyCode === 13 && !options.elIsInput) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Only filter asynchronously only if option remote is set
|
||||||
if (this.options.remote) {
|
if (this.options.remote) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
return timeout = setTimeout(function() {
|
return timeout = setTimeout(function() {
|
||||||
|
@ -79,11 +82,27 @@
|
||||||
if ((data != null) && !this.options.filterByText) {
|
if ((data != null) && !this.options.filterByText) {
|
||||||
results = data;
|
results = data;
|
||||||
if (search_text !== '') {
|
if (search_text !== '') {
|
||||||
|
// When data is an array of objects therefore [object Array] e.g.
|
||||||
|
// [
|
||||||
|
// { prop: 'foo' },
|
||||||
|
// { prop: 'baz' }
|
||||||
|
// ]
|
||||||
if (_.isArray(data)) {
|
if (_.isArray(data)) {
|
||||||
results = fuzzaldrinPlus.filter(data, search_text, {
|
results = fuzzaldrinPlus.filter(data, search_text, {
|
||||||
key: this.options.keys
|
key: this.options.keys
|
||||||
});
|
});
|
||||||
} else {
|
} 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)) {
|
if (gl.utils.isObject(data)) {
|
||||||
results = {};
|
results = {};
|
||||||
for (key in data) {
|
for (key in data) {
|
||||||
|
@ -117,7 +136,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return elements.show();
|
return elements.show().removeClass('option-hidden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -140,6 +159,7 @@
|
||||||
this.options.beforeSend();
|
this.options.beforeSend();
|
||||||
}
|
}
|
||||||
return this.dataEndpoint("", (function(_this) {
|
return this.dataEndpoint("", (function(_this) {
|
||||||
|
// Fetch the data by calling the data funcfion
|
||||||
return function(data) {
|
return function(data) {
|
||||||
if (_this.options.success) {
|
if (_this.options.success) {
|
||||||
_this.options.success(data);
|
_this.options.success(data);
|
||||||
|
@ -171,6 +191,7 @@
|
||||||
};
|
};
|
||||||
})(this)
|
})(this)
|
||||||
});
|
});
|
||||||
|
// Fetch the data through ajax if the data is a string
|
||||||
};
|
};
|
||||||
|
|
||||||
return GitLabDropdownRemote;
|
return GitLabDropdownRemote;
|
||||||
|
@ -190,9 +211,9 @@
|
||||||
|
|
||||||
currentIndex = -1;
|
currentIndex = -1;
|
||||||
|
|
||||||
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link, .option-hidden';
|
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link';
|
||||||
|
|
||||||
SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ")";
|
SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ", .option-hidden)";
|
||||||
|
|
||||||
CURSOR_SELECT_SCROLL_PADDING = 5
|
CURSOR_SELECT_SCROLL_PADDING = 5
|
||||||
|
|
||||||
|
@ -209,13 +230,18 @@
|
||||||
self = this;
|
self = this;
|
||||||
selector = $(this.el).data("target");
|
selector = $(this.el).data("target");
|
||||||
this.dropdown = selector != null ? $(selector) : $(this.el).parent();
|
this.dropdown = selector != null ? $(selector) : $(this.el).parent();
|
||||||
|
// Set Defaults
|
||||||
ref = this.options, this.filterInput = (ref1 = ref.filterInput) != null ? ref1 : this.getElement(FILTER_INPUT), this.highlight = (ref2 = ref.highlight) != null ? ref2 : false, this.filterInputBlur = (ref3 = ref.filterInputBlur) != null ? ref3 : true;
|
ref = this.options, this.filterInput = (ref1 = ref.filterInput) != null ? ref1 : this.getElement(FILTER_INPUT), this.highlight = (ref2 = ref.highlight) != null ? ref2 : false, this.filterInputBlur = (ref3 = ref.filterInputBlur) != null ? ref3 : true;
|
||||||
|
// If no input is passed create a default one
|
||||||
self = this;
|
self = this;
|
||||||
|
// If selector was passed
|
||||||
if (_.isString(this.filterInput)) {
|
if (_.isString(this.filterInput)) {
|
||||||
this.filterInput = this.getElement(this.filterInput);
|
this.filterInput = this.getElement(this.filterInput);
|
||||||
}
|
}
|
||||||
searchFields = this.options.search ? this.options.search.fields : [];
|
searchFields = this.options.search ? this.options.search.fields : [];
|
||||||
if (this.options.data) {
|
if (this.options.data) {
|
||||||
|
// If we provided data
|
||||||
|
// data could be an array of objects or a group of arrays
|
||||||
if (_.isObject(this.options.data) && !_.isFunction(this.options.data)) {
|
if (_.isObject(this.options.data) && !_.isFunction(this.options.data)) {
|
||||||
this.fullData = this.options.data;
|
this.fullData = this.options.data;
|
||||||
currentIndex = -1;
|
currentIndex = -1;
|
||||||
|
@ -232,10 +258,12 @@
|
||||||
return _this.filter.input.trigger('keyup');
|
return _this.filter.input.trigger('keyup');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Remote data
|
||||||
})(this)
|
})(this)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Init filterable
|
||||||
if (this.options.filterable) {
|
if (this.options.filterable) {
|
||||||
this.filter = new GitLabDropdownFilter(this.filterInput, {
|
this.filter = new GitLabDropdownFilter(this.filterInput, {
|
||||||
elIsInput: $(this.el).is('input'),
|
elIsInput: $(this.el).is('input'),
|
||||||
|
@ -278,12 +306,14 @@
|
||||||
})(this)
|
})(this)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Event listeners
|
||||||
this.dropdown.on("shown.bs.dropdown", this.opened);
|
this.dropdown.on("shown.bs.dropdown", this.opened);
|
||||||
this.dropdown.on("hidden.bs.dropdown", this.hidden);
|
this.dropdown.on("hidden.bs.dropdown", this.hidden);
|
||||||
$(this.el).on("update.label", this.updateLabel);
|
$(this.el).on("update.label", this.updateLabel);
|
||||||
this.dropdown.on("click", ".dropdown-menu, .dropdown-menu-close", this.shouldPropagate);
|
this.dropdown.on("click", ".dropdown-menu, .dropdown-menu-close", this.shouldPropagate);
|
||||||
this.dropdown.on('keyup', (function(_this) {
|
this.dropdown.on('keyup', (function(_this) {
|
||||||
return function(e) {
|
return function(e) {
|
||||||
|
// Escape key
|
||||||
if (e.which === 27) {
|
if (e.which === 27) {
|
||||||
return $('.dropdown-menu-close', _this.dropdown).trigger('click');
|
return $('.dropdown-menu-close', _this.dropdown).trigger('click');
|
||||||
}
|
}
|
||||||
|
@ -322,11 +352,18 @@
|
||||||
if (self.options.clicked) {
|
if (self.options.clicked) {
|
||||||
self.options.clicked(selected, $el, e);
|
self.options.clicked(selected, $el, e);
|
||||||
}
|
}
|
||||||
return $el.trigger('blur');
|
|
||||||
|
// Update label right after all modifications in dropdown has been done
|
||||||
|
if (self.options.toggleLabel) {
|
||||||
|
self.updateLabel(selected, $el, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
$el.trigger('blur');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finds an element inside wrapper element
|
||||||
GitLabDropdown.prototype.getElement = function(selector) {
|
GitLabDropdown.prototype.getElement = function(selector) {
|
||||||
return this.dropdown.find(selector);
|
return this.dropdown.find(selector);
|
||||||
};
|
};
|
||||||
|
@ -344,6 +381,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
menu.toggleClass(PAGE_TWO_CLASS);
|
menu.toggleClass(PAGE_TWO_CLASS);
|
||||||
|
// Focus first visible input on active page
|
||||||
return this.dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus();
|
return this.dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -351,23 +389,28 @@
|
||||||
var full_html, groupData, html, name;
|
var full_html, groupData, html, name;
|
||||||
this.renderedData = data;
|
this.renderedData = data;
|
||||||
if (this.options.filterable && data.length === 0) {
|
if (this.options.filterable && data.length === 0) {
|
||||||
|
// render no matching results
|
||||||
html = [this.noResults()];
|
html = [this.noResults()];
|
||||||
} else {
|
} else {
|
||||||
|
// Handle array groups
|
||||||
if (gl.utils.isObject(data)) {
|
if (gl.utils.isObject(data)) {
|
||||||
html = [];
|
html = [];
|
||||||
for (name in data) {
|
for (name in data) {
|
||||||
groupData = data[name];
|
groupData = data[name];
|
||||||
html.push(this.renderItem({
|
html.push(this.renderItem({
|
||||||
header: name
|
header: name
|
||||||
|
// Add header for each group
|
||||||
}, name));
|
}, name));
|
||||||
this.renderData(groupData, name).map(function(item) {
|
this.renderData(groupData, name).map(function(item) {
|
||||||
return html.push(item);
|
return html.push(item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Render each row
|
||||||
html = this.renderData(data);
|
html = this.renderData(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Render the full menu
|
||||||
full_html = this.renderMenu(html);
|
full_html = this.renderMenu(html);
|
||||||
return this.appendMenu(full_html);
|
return this.appendMenu(full_html);
|
||||||
};
|
};
|
||||||
|
@ -406,6 +449,7 @@
|
||||||
if (this.options.setActiveIds) {
|
if (this.options.setActiveIds) {
|
||||||
this.options.setActiveIds.call(this);
|
this.options.setActiveIds.call(this);
|
||||||
}
|
}
|
||||||
|
// Makes indeterminate items effective
|
||||||
if (this.fullData && this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) {
|
if (this.fullData && this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) {
|
||||||
this.parseData(this.fullData);
|
this.parseData(this.fullData);
|
||||||
}
|
}
|
||||||
|
@ -427,6 +471,8 @@
|
||||||
if (this.options.filterable) {
|
if (this.options.filterable) {
|
||||||
$input.blur().val("");
|
$input.blur().val("");
|
||||||
}
|
}
|
||||||
|
// Triggering 'keyup' will re-render the dropdown which is not always required
|
||||||
|
// specially if we want to keep the state of the dropdown needed for bulk-assignment
|
||||||
if (!this.options.persistWhenHide) {
|
if (!this.options.persistWhenHide) {
|
||||||
$input.trigger("keyup");
|
$input.trigger("keyup");
|
||||||
}
|
}
|
||||||
|
@ -439,6 +485,7 @@
|
||||||
return this.dropdown.trigger('hidden.gl.dropdown');
|
return this.dropdown.trigger('hidden.gl.dropdown');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Render the full menu
|
||||||
GitLabDropdown.prototype.renderMenu = function(html) {
|
GitLabDropdown.prototype.renderMenu = function(html) {
|
||||||
var menu_html;
|
var menu_html;
|
||||||
menu_html = "";
|
menu_html = "";
|
||||||
|
@ -450,6 +497,7 @@
|
||||||
return menu_html;
|
return menu_html;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Append the menu into the dropdown
|
||||||
GitLabDropdown.prototype.appendMenu = function(html) {
|
GitLabDropdown.prototype.appendMenu = function(html) {
|
||||||
var selector;
|
var selector;
|
||||||
selector = '.dropdown-content';
|
selector = '.dropdown-content';
|
||||||
|
@ -465,35 +513,42 @@
|
||||||
group = false;
|
group = false;
|
||||||
}
|
}
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
|
// Render the row
|
||||||
index = false;
|
index = false;
|
||||||
}
|
}
|
||||||
html = "";
|
html = "";
|
||||||
|
// Divider
|
||||||
if (data === "divider") {
|
if (data === "divider") {
|
||||||
return "<li class='divider'></li>";
|
return "<li class='divider'></li>";
|
||||||
}
|
}
|
||||||
|
// Separator is a full-width divider
|
||||||
if (data === "separator") {
|
if (data === "separator") {
|
||||||
return "<li class='separator'></li>";
|
return "<li class='separator'></li>";
|
||||||
}
|
}
|
||||||
|
// Header
|
||||||
if (data.header != null) {
|
if (data.header != null) {
|
||||||
return _.template('<li class="dropdown-header"><%- header %></li>')({ header: data.header });
|
return _.template('<li class="dropdown-header"><%- header %></li>')({ header: data.header });
|
||||||
}
|
}
|
||||||
if (this.options.renderRow) {
|
if (this.options.renderRow) {
|
||||||
|
// Call the render function
|
||||||
html = this.options.renderRow.call(this.options, data, this);
|
html = this.options.renderRow.call(this.options, data, this);
|
||||||
} else {
|
} else {
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
value = this.options.id ? this.options.id(data) : data.id;
|
value = this.options.id ? this.options.id(data) : data.id;
|
||||||
fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName() : this.options.fieldName;
|
fieldName = this.options.fieldName;
|
||||||
|
|
||||||
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']");
|
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']");
|
||||||
if (field.length) {
|
if (field.length) {
|
||||||
selected = true;
|
selected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Set URL
|
||||||
if (this.options.url != null) {
|
if (this.options.url != null) {
|
||||||
url = this.options.url(data);
|
url = this.options.url(data);
|
||||||
} else {
|
} else {
|
||||||
url = data.url != null ? data.url : '#';
|
url = data.url != null ? data.url : '#';
|
||||||
}
|
}
|
||||||
|
// Set Text
|
||||||
if (this.options.text != null) {
|
if (this.options.text != null) {
|
||||||
text = this.options.text(data);
|
text = this.options.text(data);
|
||||||
} else {
|
} else {
|
||||||
|
@ -540,6 +595,7 @@
|
||||||
|
|
||||||
GitLabDropdown.prototype.rowClicked = function(el) {
|
GitLabDropdown.prototype.rowClicked = function(el) {
|
||||||
var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value;
|
var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value;
|
||||||
|
fieldName = this.options.fieldName;
|
||||||
isInput = $(this.el).is('input');
|
isInput = $(this.el).is('input');
|
||||||
if (this.renderedData) {
|
if (this.renderedData) {
|
||||||
groupName = el.data('group');
|
groupName = el.data('group');
|
||||||
|
@ -551,34 +607,31 @@
|
||||||
selectedObject = this.renderedData[selectedIndex];
|
selectedObject = this.renderedData[selectedIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName(selectedObject) : this.options.fieldName;
|
field = [];
|
||||||
value = this.options.id ? this.options.id(selectedObject, el) : selectedObject.id;
|
value = this.options.id ? this.options.id(selectedObject, el) : selectedObject.id;
|
||||||
if (isInput) {
|
if (isInput) {
|
||||||
field = $(this.el);
|
field = $(this.el);
|
||||||
} else {
|
} else if(value) {
|
||||||
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']");
|
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, '\\\'') + "']");
|
||||||
}
|
}
|
||||||
if (el.hasClass(ACTIVE_CLASS)) {
|
if (el.hasClass(ACTIVE_CLASS)) {
|
||||||
el.removeClass(ACTIVE_CLASS);
|
el.removeClass(ACTIVE_CLASS);
|
||||||
if (isInput) {
|
if (field && field.length) {
|
||||||
field.val('');
|
if (isInput) {
|
||||||
} else {
|
field.val('');
|
||||||
field.remove();
|
} else {
|
||||||
|
field.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.options.toggleLabel) {
|
|
||||||
this.updateLabel(selectedObject, el, this);
|
|
||||||
}
|
|
||||||
return selectedObject;
|
|
||||||
} else if (el.hasClass(INDETERMINATE_CLASS)) {
|
} else if (el.hasClass(INDETERMINATE_CLASS)) {
|
||||||
el.addClass(ACTIVE_CLASS);
|
el.addClass(ACTIVE_CLASS);
|
||||||
el.removeClass(INDETERMINATE_CLASS);
|
el.removeClass(INDETERMINATE_CLASS);
|
||||||
if (value == null) {
|
if (field && field.length && value == null) {
|
||||||
field.remove();
|
field.remove();
|
||||||
}
|
}
|
||||||
if (!field.length && fieldName) {
|
if ((!field || !field.length) && fieldName) {
|
||||||
this.addInput(fieldName, value, selectedObject);
|
this.addInput(fieldName, value, selectedObject);
|
||||||
}
|
}
|
||||||
return selectedObject;
|
|
||||||
} else {
|
} else {
|
||||||
if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) {
|
if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) {
|
||||||
this.dropdown.find("." + ACTIVE_CLASS).removeClass(ACTIVE_CLASS);
|
this.dropdown.find("." + ACTIVE_CLASS).removeClass(ACTIVE_CLASS);
|
||||||
|
@ -586,33 +639,30 @@
|
||||||
this.dropdown.parent().find("input[name='" + fieldName + "']").remove();
|
this.dropdown.parent().find("input[name='" + fieldName + "']").remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (value == null) {
|
if (field && field.length && value == null) {
|
||||||
field.remove();
|
field.remove();
|
||||||
}
|
}
|
||||||
|
// Toggle active class for the tick mark
|
||||||
el.addClass(ACTIVE_CLASS);
|
el.addClass(ACTIVE_CLASS);
|
||||||
if (this.options.toggleLabel) {
|
|
||||||
this.updateLabel(selectedObject, el, this);
|
|
||||||
}
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (!field.length && fieldName) {
|
if ((!field || !field.length) && fieldName) {
|
||||||
this.addInput(fieldName, value, selectedObject);
|
this.addInput(fieldName, value, selectedObject);
|
||||||
} else {
|
} else if (field && field.length) {
|
||||||
field.val(value).trigger('change');
|
field.val(value).trigger('change');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return selectedObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return selectedObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
GitLabDropdown.prototype.addInput = function(fieldName, value, selectedObject) {
|
GitLabDropdown.prototype.addInput = function(fieldName, value, selectedObject) {
|
||||||
var $input;
|
var $input;
|
||||||
|
// Create hidden input for form
|
||||||
$input = $('<input>').attr('type', 'hidden').attr('name', fieldName).val(value);
|
$input = $('<input>').attr('type', 'hidden').attr('name', fieldName).val(value);
|
||||||
if (this.options.inputId != null) {
|
if (this.options.inputId != null) {
|
||||||
$input.attr('id', this.options.inputId);
|
$input.attr('id', this.options.inputId);
|
||||||
}
|
}
|
||||||
if (selectedObject && selectedObject.type) {
|
|
||||||
$input.attr('data-type', selectedObject.type);
|
|
||||||
}
|
|
||||||
return this.dropdown.before($input);
|
return this.dropdown.before($input);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -627,6 +677,7 @@
|
||||||
if (this.dropdown.find(".dropdown-toggle-page").length) {
|
if (this.dropdown.find(".dropdown-toggle-page").length) {
|
||||||
selector = ".dropdown-page-one " + selector;
|
selector = ".dropdown-page-one " + selector;
|
||||||
}
|
}
|
||||||
|
// simulate a click on the first link
|
||||||
$el = $(selector, this.dropdown);
|
$el = $(selector, this.dropdown);
|
||||||
if ($el.length) {
|
if ($el.length) {
|
||||||
var href = $el.attr('href');
|
var href = $el.attr('href');
|
||||||
|
@ -655,11 +706,15 @@
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
PREV_INDEX = currentIndex;
|
PREV_INDEX = currentIndex;
|
||||||
$listItems = $(selector, _this.dropdown);
|
$listItems = $(selector, _this.dropdown);
|
||||||
|
// if @options.filterable
|
||||||
|
// $input.blur()
|
||||||
if (currentKeyCode === 40) {
|
if (currentKeyCode === 40) {
|
||||||
|
// Move down
|
||||||
if (currentIndex < ($listItems.length - 1)) {
|
if (currentIndex < ($listItems.length - 1)) {
|
||||||
currentIndex += 1;
|
currentIndex += 1;
|
||||||
}
|
}
|
||||||
} else if (currentKeyCode === 38) {
|
} else if (currentKeyCode === 38) {
|
||||||
|
// Move up
|
||||||
if (currentIndex > 0) {
|
if (currentIndex > 0) {
|
||||||
currentIndex -= 1;
|
currentIndex -= 1;
|
||||||
}
|
}
|
||||||
|
@ -687,24 +742,32 @@
|
||||||
|
|
||||||
GitLabDropdown.prototype.highlightRowAtIndex = function($listItems, index) {
|
GitLabDropdown.prototype.highlightRowAtIndex = function($listItems, index) {
|
||||||
var $dropdownContent, $listItem, dropdownContentBottom, dropdownContentHeight, dropdownContentTop, dropdownScrollTop, listItemBottom, listItemHeight, listItemTop;
|
var $dropdownContent, $listItem, dropdownContentBottom, dropdownContentHeight, dropdownContentTop, dropdownScrollTop, listItemBottom, listItemHeight, listItemTop;
|
||||||
|
// Remove the class for the previously focused row
|
||||||
$('.is-focused', this.dropdown).removeClass('is-focused');
|
$('.is-focused', this.dropdown).removeClass('is-focused');
|
||||||
|
// Update the class for the row at the specific index
|
||||||
$listItem = $listItems.eq(index);
|
$listItem = $listItems.eq(index);
|
||||||
$listItem.find('a:first-child').addClass("is-focused");
|
$listItem.find('a:first-child').addClass("is-focused");
|
||||||
|
// Dropdown content scroll area
|
||||||
$dropdownContent = $listItem.closest('.dropdown-content');
|
$dropdownContent = $listItem.closest('.dropdown-content');
|
||||||
dropdownScrollTop = $dropdownContent.scrollTop();
|
dropdownScrollTop = $dropdownContent.scrollTop();
|
||||||
dropdownContentHeight = $dropdownContent.outerHeight();
|
dropdownContentHeight = $dropdownContent.outerHeight();
|
||||||
dropdownContentTop = $dropdownContent.prop('offsetTop');
|
dropdownContentTop = $dropdownContent.prop('offsetTop');
|
||||||
dropdownContentBottom = dropdownContentTop + dropdownContentHeight;
|
dropdownContentBottom = dropdownContentTop + dropdownContentHeight;
|
||||||
|
// Get the offset bottom of the list item
|
||||||
listItemHeight = $listItem.outerHeight();
|
listItemHeight = $listItem.outerHeight();
|
||||||
listItemTop = $listItem.prop('offsetTop');
|
listItemTop = $listItem.prop('offsetTop');
|
||||||
listItemBottom = listItemTop + listItemHeight;
|
listItemBottom = listItemTop + listItemHeight;
|
||||||
if (!index) {
|
if (!index) {
|
||||||
|
// Scroll the dropdown content to the top
|
||||||
$dropdownContent.scrollTop(0)
|
$dropdownContent.scrollTop(0)
|
||||||
} else if (index === ($listItems.length - 1)) {
|
} else if (index === ($listItems.length - 1)) {
|
||||||
|
// Scroll the dropdown content to the bottom
|
||||||
$dropdownContent.scrollTop($dropdownContent.prop('scrollHeight'));
|
$dropdownContent.scrollTop($dropdownContent.prop('scrollHeight'));
|
||||||
} else if (listItemBottom > (dropdownContentBottom + dropdownScrollTop)) {
|
} else if (listItemBottom > (dropdownContentBottom + dropdownScrollTop)) {
|
||||||
|
// Scroll the dropdown content down
|
||||||
$dropdownContent.scrollTop(listItemBottom - dropdownContentBottom + CURSOR_SELECT_SCROLL_PADDING);
|
$dropdownContent.scrollTop(listItemBottom - dropdownContentBottom + CURSOR_SELECT_SCROLL_PADDING);
|
||||||
} else if (listItemTop < (dropdownContentTop + dropdownScrollTop)) {
|
} else if (listItemTop < (dropdownContentTop + dropdownScrollTop)) {
|
||||||
|
// Scroll the dropdown content up
|
||||||
return $dropdownContent.scrollTop(listItemTop - dropdownContentTop - CURSOR_SELECT_SCROLL_PADDING);
|
return $dropdownContent.scrollTop(listItemTop - dropdownContentTop - CURSOR_SELECT_SCROLL_PADDING);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,12 +3,15 @@
|
||||||
function GLForm(form) {
|
function GLForm(form) {
|
||||||
this.form = form;
|
this.form = form;
|
||||||
this.textarea = this.form.find('textarea.js-gfm-input');
|
this.textarea = this.form.find('textarea.js-gfm-input');
|
||||||
|
// Before we start, we should clean up any previous data for this form
|
||||||
this.destroy();
|
this.destroy();
|
||||||
|
// Setup the form
|
||||||
this.setupForm();
|
this.setupForm();
|
||||||
this.form.data('gl-form', this);
|
this.form.data('gl-form', this);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLForm.prototype.destroy = function() {
|
GLForm.prototype.destroy = function() {
|
||||||
|
// Clean form listeners
|
||||||
this.clearEventListeners();
|
this.clearEventListeners();
|
||||||
return this.form.data('gl-form', null);
|
return this.form.data('gl-form', null);
|
||||||
};
|
};
|
||||||
|
@ -21,12 +24,15 @@
|
||||||
this.form.find('.div-dropzone').remove();
|
this.form.find('.div-dropzone').remove();
|
||||||
this.form.addClass('gfm-form');
|
this.form.addClass('gfm-form');
|
||||||
disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button'));
|
disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button'));
|
||||||
|
// remove notify commit author checkbox for non-commit notes
|
||||||
GitLab.GfmAutoComplete.setup(this.form.find('.js-gfm-input'));
|
GitLab.GfmAutoComplete.setup(this.form.find('.js-gfm-input'));
|
||||||
new DropzoneInput(this.form);
|
new DropzoneInput(this.form);
|
||||||
autosize(this.textarea);
|
autosize(this.textarea);
|
||||||
|
// form and textarea event listeners
|
||||||
this.addEventListeners();
|
this.addEventListeners();
|
||||||
gl.text.init(this.form);
|
gl.text.init(this.form);
|
||||||
}
|
}
|
||||||
|
// hide discard button
|
||||||
this.form.find('.js-note-discard').hide();
|
this.form.find('.js-note-discard').hide();
|
||||||
return this.form.show();
|
return this.form.show();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
// This is a manifest file that'll be compiled into including all the files listed below.
|
||||||
|
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
|
||||||
|
// be included in the compiled file accessible from http://example.com/assets/application.js
|
||||||
|
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||||
|
// the compiled file.
|
||||||
|
//
|
||||||
/*= require_tree . */
|
/*= require_tree . */
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -204,6 +204,7 @@
|
||||||
|
|
||||||
function ContributorsAuthorGraph(data1) {
|
function ContributorsAuthorGraph(data1) {
|
||||||
this.data = data1;
|
this.data = data1;
|
||||||
|
// Don't split graph size in half for mobile devices.
|
||||||
if ($(window).width() < 768) {
|
if ($(window).width() < 768) {
|
||||||
this.width = $('.content').width() - 80;
|
this.width = $('.content').width() - 80;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
return _this.formatSelection.apply(_this, args);
|
return _this.formatSelection.apply(_this, args);
|
||||||
},
|
},
|
||||||
dropdownCssClass: "ajax-groups-dropdown",
|
dropdownCssClass: "ajax-groups-dropdown",
|
||||||
|
// we do not want to escape markup since we are displaying html in results
|
||||||
escapeMarkup: function(m) {
|
escapeMarkup: function(m) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,21 +10,24 @@
|
||||||
ImporterStatus.prototype.initStatusPage = function() {
|
ImporterStatus.prototype.initStatusPage = function() {
|
||||||
$('.js-add-to-import').off('click').on('click', (function(_this) {
|
$('.js-add-to-import').off('click').on('click', (function(_this) {
|
||||||
return function(e) {
|
return function(e) {
|
||||||
var $btn, $namespace_input, $target_field, $tr, id, new_namespace;
|
var $btn, $namespace_input, $target_field, $tr, id, target_namespace, newName;
|
||||||
$btn = $(e.currentTarget);
|
$btn = $(e.currentTarget);
|
||||||
$tr = $btn.closest('tr');
|
$tr = $btn.closest('tr');
|
||||||
$target_field = $tr.find('.import-target');
|
$target_field = $tr.find('.import-target');
|
||||||
$namespace_input = $target_field.find('input');
|
$namespace_input = $target_field.find('.js-select-namespace option:selected');
|
||||||
id = $tr.attr('id').replace('repo_', '');
|
id = $tr.attr('id').replace('repo_', '');
|
||||||
new_namespace = null;
|
target_namespace = null;
|
||||||
|
newName = null;
|
||||||
if ($namespace_input.length > 0) {
|
if ($namespace_input.length > 0) {
|
||||||
new_namespace = $namespace_input.prop('value');
|
target_namespace = $namespace_input[0].innerHTML;
|
||||||
$target_field.empty().append(new_namespace + "/" + ($target_field.data('project_name')));
|
newName = $target_field.find('#path').prop('value');
|
||||||
|
$target_field.empty().append(target_namespace + "/" + newName);
|
||||||
}
|
}
|
||||||
$btn.disable().addClass('is-loading');
|
$btn.disable().addClass('is-loading');
|
||||||
return $.post(_this.import_url, {
|
return $.post(_this.import_url, {
|
||||||
repo_id: id,
|
repo_id: id,
|
||||||
new_namespace: new_namespace
|
target_namespace: target_namespace,
|
||||||
|
new_name: newName
|
||||||
}, {
|
}, {
|
||||||
dataType: 'script'
|
dataType: 'script'
|
||||||
});
|
});
|
||||||
|
@ -70,7 +73,7 @@
|
||||||
if ($('.js-importer-status').length) {
|
if ($('.js-importer-status').length) {
|
||||||
var jobsImportPath = $('.js-importer-status').data('jobs-import-path');
|
var jobsImportPath = $('.js-importer-status').data('jobs-import-path');
|
||||||
var importPath = $('.js-importer-status').data('import-path');
|
var importPath = $('.js-importer-status').data('import-path');
|
||||||
|
|
||||||
new ImporterStatus(jobsImportPath, importPath);
|
new ImporterStatus(jobsImportPath, importPath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,38 +8,48 @@
|
||||||
Issuable.initTemplates();
|
Issuable.initTemplates();
|
||||||
Issuable.initSearch();
|
Issuable.initSearch();
|
||||||
Issuable.initChecks();
|
Issuable.initChecks();
|
||||||
|
Issuable.initResetFilters();
|
||||||
return Issuable.initLabelFilterRemove();
|
return Issuable.initLabelFilterRemove();
|
||||||
},
|
},
|
||||||
initTemplates: function() {
|
initTemplates: function() {
|
||||||
return Issuable.labelRow = _.template('<% _.each(labels, function(label){ %> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body"> <%- label.title %> </a> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>"> <i class="fa fa-times"></i> </button> </span> <% }); %>');
|
return Issuable.labelRow = _.template('<% _.each(labels, function(label){ %> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body"> <%- label.title %> </a> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>"> <i class="fa fa-times"></i> </button> </span> <% }); %>');
|
||||||
},
|
},
|
||||||
initSearch: function() {
|
initSearch: function() {
|
||||||
this.timer = null;
|
// `immediate` param set to false debounces on the `trailing` edge, lets user finish typing
|
||||||
return $('#issue_search').off('keyup').on('keyup', function() {
|
const debouncedExecSearch = _.debounce(Issuable.executeSearch, 500, false);
|
||||||
clearTimeout(this.timer);
|
|
||||||
return this.timer = setTimeout(function() {
|
$('#issuable_search').off('keyup').on('keyup', debouncedExecSearch);
|
||||||
var $form, $input, $search;
|
|
||||||
$search = $('#issue_search');
|
// ensures existing filters are preserved when manually submitted
|
||||||
$form = $('.js-filter-form');
|
$('#issue_search_form').on('submit', (e) => {
|
||||||
$input = $("input[name='" + ($search.attr('name')) + "']", $form);
|
e.preventDefault();
|
||||||
if ($input.length === 0) {
|
debouncedExecSearch(e);
|
||||||
$form.append("<input type='hidden' name='" + ($search.attr('name')) + "' value='" + (_.escape($search.val())) + "'/>");
|
|
||||||
} else {
|
|
||||||
$input.val($search.val());
|
|
||||||
}
|
|
||||||
if ($search.val() !== '') {
|
|
||||||
return Issuable.filterResults($form);
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
executeSearch: function(e) {
|
||||||
|
const $search = $('#issuable_search');
|
||||||
|
const $searchName = $search.attr('name');
|
||||||
|
const $searchValue = $search.val();
|
||||||
|
const $filtersForm = $('.js-filter-form');
|
||||||
|
const $input = $(`input[name='${$searchName}']`, $filtersForm);
|
||||||
|
|
||||||
|
if (!$input.length) {
|
||||||
|
$filtersForm.append(`<input type='hidden' name='${$searchName}' value='${_.escape($searchValue)}'/>`);
|
||||||
|
} else {
|
||||||
|
$input.val($searchValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
Issuable.filterResults($filtersForm);
|
||||||
|
},
|
||||||
initLabelFilterRemove: function() {
|
initLabelFilterRemove: function() {
|
||||||
return $(document).off('click', '.js-label-filter-remove').on('click', '.js-label-filter-remove', function(e) {
|
return $(document).off('click', '.js-label-filter-remove').on('click', '.js-label-filter-remove', function(e) {
|
||||||
var $button;
|
var $button;
|
||||||
$button = $(this);
|
$button = $(this);
|
||||||
|
// Remove the label input box
|
||||||
$('input[name="label_name[]"]').filter(function() {
|
$('input[name="label_name[]"]').filter(function() {
|
||||||
return this.value === $button.data('label');
|
return this.value === $button.data('label');
|
||||||
}).remove();
|
}).remove();
|
||||||
|
// Submit the form to get new data
|
||||||
Issuable.filterResults($('.filter-form'));
|
Issuable.filterResults($('.filter-form'));
|
||||||
return $('.js-label-select').trigger('update.label');
|
return $('.js-label-select').trigger('update.label');
|
||||||
});
|
});
|
||||||
|
@ -55,6 +65,17 @@
|
||||||
return Turbolinks.visit(issuesUrl);
|
return Turbolinks.visit(issuesUrl);
|
||||||
};
|
};
|
||||||
})(this),
|
})(this),
|
||||||
|
initResetFilters: function() {
|
||||||
|
$('.reset-filters').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = e.target;
|
||||||
|
const $form = $(target).parents('.js-filter-form');
|
||||||
|
const baseIssuesUrl = target.href;
|
||||||
|
|
||||||
|
$form.attr('action', baseIssuesUrl);
|
||||||
|
Turbolinks.visit(baseIssuesUrl);
|
||||||
|
});
|
||||||
|
},
|
||||||
initChecks: function() {
|
initChecks: function() {
|
||||||
this.issuableBulkActions = $('.bulk-update').data('bulkActions');
|
this.issuableBulkActions = $('.bulk-update').data('bulkActions');
|
||||||
$('.check_all_issues').off('click').on('click', function() {
|
$('.check_all_issues').off('click').on('click', function() {
|
||||||
|
@ -64,19 +85,22 @@
|
||||||
return $('.selected_issue').off('change').on('change', Issuable.checkChanged.bind(this));
|
return $('.selected_issue').off('change').on('change', Issuable.checkChanged.bind(this));
|
||||||
},
|
},
|
||||||
checkChanged: function() {
|
checkChanged: function() {
|
||||||
var checked_issues, ids;
|
const $checkedIssues = $('.selected_issue:checked');
|
||||||
checked_issues = $('.selected_issue:checked');
|
const $updateIssuesIds = $('#update_issuable_ids');
|
||||||
if (checked_issues.length > 0) {
|
const $issuesOtherFilters = $('.issues-other-filters');
|
||||||
ids = $.map(checked_issues, function(value) {
|
const $issuesBulkUpdate = $('.issues_bulk_update');
|
||||||
|
|
||||||
|
if ($checkedIssues.length > 0) {
|
||||||
|
let ids = $.map($checkedIssues, function(value) {
|
||||||
return $(value).data('id');
|
return $(value).data('id');
|
||||||
});
|
});
|
||||||
$('#update_issues_ids').val(ids);
|
$updateIssuesIds.val(ids);
|
||||||
$('.issues-other-filters').hide();
|
$issuesOtherFilters.hide();
|
||||||
$('.issues_bulk_update').show();
|
$issuesBulkUpdate.show();
|
||||||
} else {
|
} else {
|
||||||
$('#update_issues_ids').val([]);
|
$updateIssuesIds.val([]);
|
||||||
$('.issues_bulk_update').hide();
|
$issuesBulkUpdate.hide();
|
||||||
$('.issues-other-filters').show();
|
$issuesOtherFilters.show();
|
||||||
this.issuableBulkActions.willUpdateLabels = false;
|
this.issuableBulkActions.willUpdateLabels = false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
|
@ -102,20 +102,34 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
IssuableForm.prototype.initMoveDropdown = function() {
|
IssuableForm.prototype.initMoveDropdown = function() {
|
||||||
var $moveDropdown;
|
var $moveDropdown, pageSize;
|
||||||
$moveDropdown = $('.js-move-dropdown');
|
$moveDropdown = $('.js-move-dropdown');
|
||||||
if ($moveDropdown.length) {
|
if ($moveDropdown.length) {
|
||||||
|
pageSize = $moveDropdown.data('page-size');
|
||||||
return $('.js-move-dropdown').select2({
|
return $('.js-move-dropdown').select2({
|
||||||
ajax: {
|
ajax: {
|
||||||
url: $moveDropdown.data('projects-url'),
|
url: $moveDropdown.data('projects-url'),
|
||||||
results: function(data) {
|
quietMillis: 125,
|
||||||
|
data: function(term, page, context) {
|
||||||
return {
|
return {
|
||||||
results: data
|
search: term,
|
||||||
|
offset_id: context
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data: function(query) {
|
results: function(data) {
|
||||||
|
var context,
|
||||||
|
more;
|
||||||
|
|
||||||
|
if (data.length >= pageSize)
|
||||||
|
more = true;
|
||||||
|
|
||||||
|
if (data[data.length - 1])
|
||||||
|
context = data[data.length - 1].id;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
search: query
|
results: data,
|
||||||
|
more: more,
|
||||||
|
context: context
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
|
|
||||||
/*= require flash */
|
/*= require flash */
|
||||||
|
|
||||||
|
|
||||||
/*= require jquery.waitforimages */
|
/*= require jquery.waitforimages */
|
||||||
|
|
||||||
|
|
||||||
/*= require task_list */
|
/*= require task_list */
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
@ -13,6 +9,7 @@
|
||||||
this.Issue = (function() {
|
this.Issue = (function() {
|
||||||
function Issue() {
|
function Issue() {
|
||||||
this.submitNoteForm = bind(this.submitNoteForm, this);
|
this.submitNoteForm = bind(this.submitNoteForm, this);
|
||||||
|
// Prevent duplicate event bindings
|
||||||
this.disableTaskList();
|
this.disableTaskList();
|
||||||
if ($('a.btn-close').length) {
|
if ($('a.btn-close').length) {
|
||||||
this.initTaskList();
|
this.initTaskList();
|
||||||
|
@ -99,6 +96,8 @@
|
||||||
url: $('form.js-issuable-update').attr('action'),
|
url: $('form.js-issuable-update').attr('action'),
|
||||||
data: patchData
|
data: patchData
|
||||||
});
|
});
|
||||||
|
// TODO (rspeicher): Make the issue description inline-editable like a note so
|
||||||
|
// that we can re-use its form here
|
||||||
};
|
};
|
||||||
|
|
||||||
Issue.prototype.initMergeRequests = function() {
|
Issue.prototype.initMergeRequests = function() {
|
||||||
|
@ -127,7 +126,9 @@
|
||||||
|
|
||||||
Issue.prototype.initCanCreateBranch = function() {
|
Issue.prototype.initCanCreateBranch = function() {
|
||||||
var $container;
|
var $container;
|
||||||
$container = $('div#new-branch');
|
$container = $('#new-branch');
|
||||||
|
// If the user doesn't have the required permissions the container isn't
|
||||||
|
// rendered at all.
|
||||||
if ($container.length === 0) {
|
if ($container.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -139,7 +140,6 @@
|
||||||
if (data.can_create_branch) {
|
if (data.can_create_branch) {
|
||||||
$container.find('.checking').hide();
|
$container.find('.checking').hide();
|
||||||
$container.find('.available').show();
|
$container.find('.available').show();
|
||||||
return $container.find('a').attr('disabled', false);
|
|
||||||
} else {
|
} else {
|
||||||
$container.find('.checking').hide();
|
$container.find('.checking').hide();
|
||||||
return $container.find('.unavailable').show();
|
return $container.find('.unavailable').show();
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
(function() {
|
(function() {
|
||||||
this.IssuableBulkActions = (function() {
|
this.IssuableBulkActions = (function() {
|
||||||
function IssuableBulkActions(opts) {
|
function IssuableBulkActions(opts) {
|
||||||
|
// Set defaults
|
||||||
var ref, ref1, ref2;
|
var ref, ref1, ref2;
|
||||||
if (opts == null) {
|
if (opts == null) {
|
||||||
opts = {};
|
opts = {};
|
||||||
}
|
}
|
||||||
this.container = (ref = opts.container) != null ? ref : $('.content'), this.form = (ref1 = opts.form) != null ? ref1 : this.getElement('.bulk-update'), this.issues = (ref2 = opts.issues) != null ? ref2 : this.getElement('.issues-list .issue');
|
this.container = (ref = opts.container) != null ? ref : $('.content'), this.form = (ref1 = opts.form) != null ? ref1 : this.getElement('.bulk-update'), this.issues = (ref2 = opts.issues) != null ? ref2 : this.getElement('.issuable-list > li');
|
||||||
|
// Save instance
|
||||||
this.form.data('bulkActions', this);
|
this.form.data('bulkActions', this);
|
||||||
this.willUpdateLabels = false;
|
this.willUpdateLabels = false;
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
|
// Fixes bulk-assign not working when navigating through pages
|
||||||
Issuable.initChecks();
|
Issuable.initChecks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +89,7 @@
|
||||||
ref1 = this.getLabelsFromSelection();
|
ref1 = this.getLabelsFromSelection();
|
||||||
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
||||||
id = ref1[j];
|
id = ref1[j];
|
||||||
|
// Only the ones that we are not going to keep
|
||||||
if (labelsToKeep.indexOf(id) === -1) {
|
if (labelsToKeep.indexOf(id) === -1) {
|
||||||
result.push(id);
|
result.push(id);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +110,7 @@
|
||||||
state_event: this.form.find('input[name="update[state_event]"]').val(),
|
state_event: this.form.find('input[name="update[state_event]"]').val(),
|
||||||
assignee_id: this.form.find('input[name="update[assignee_id]"]').val(),
|
assignee_id: this.form.find('input[name="update[assignee_id]"]').val(),
|
||||||
milestone_id: this.form.find('input[name="update[milestone_id]"]').val(),
|
milestone_id: this.form.find('input[name="update[milestone_id]"]').val(),
|
||||||
issues_ids: this.form.find('input[name="update[issues_ids]"]').val(),
|
issuable_ids: this.form.find('input[name="update[issuable_ids]"]').val(),
|
||||||
subscription_event: this.form.find('input[name="update[subscription_event]"]').val(),
|
subscription_event: this.form.find('input[name="update[subscription_event]"]').val(),
|
||||||
add_label_ids: [],
|
add_label_ids: [],
|
||||||
remove_label_ids: []
|
remove_label_ids: []
|
||||||
|
@ -147,6 +151,8 @@
|
||||||
indeterminatedLabels = this.getUnmarkedIndeterminedLabels();
|
indeterminatedLabels = this.getUnmarkedIndeterminedLabels();
|
||||||
labelsToApply = this.getLabelsToApply();
|
labelsToApply = this.getLabelsToApply();
|
||||||
indeterminatedLabels.map(function(id) {
|
indeterminatedLabels.map(function(id) {
|
||||||
|
// We need to exclude label IDs that will be applied
|
||||||
|
// By not doing this will cause issues from selection to not add labels at all
|
||||||
if (labelsToApply.indexOf(id) === -1) {
|
if (labelsToApply.indexOf(id) === -1) {
|
||||||
return result.push(id);
|
return result.push(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,16 @@
|
||||||
var previewColor;
|
var previewColor;
|
||||||
previewColor = $('input#label_color').val();
|
previewColor = $('input#label_color').val();
|
||||||
return $('div.label-color-preview').css('background-color', previewColor);
|
return $('div.label-color-preview').css('background-color', previewColor);
|
||||||
|
// Updates the the preview color with the hex-color input
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Updates the preview color with a click on a suggested color
|
||||||
Labels.prototype.setSuggestedColor = function(e) {
|
Labels.prototype.setSuggestedColor = function(e) {
|
||||||
var color;
|
var color;
|
||||||
color = $(e.currentTarget).data('color');
|
color = $(e.currentTarget).data('color');
|
||||||
$('input#label_color').val(color);
|
$('input#label_color').val(color);
|
||||||
this.updateColorPreview();
|
this.updateColorPreview();
|
||||||
|
// Notify the form, that color has changed
|
||||||
$('.label-form').trigger('keyup');
|
$('.label-form').trigger('keyup');
|
||||||
return e.preventDefault();
|
return e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
|
@ -156,15 +156,17 @@
|
||||||
selectedClass.push('is-indeterminate');
|
selectedClass.push('is-indeterminate');
|
||||||
}
|
}
|
||||||
if (active.indexOf(label.id) !== -1) {
|
if (active.indexOf(label.id) !== -1) {
|
||||||
|
// Remove is-indeterminate class if the item will be marked as active
|
||||||
i = selectedClass.indexOf('is-indeterminate');
|
i = selectedClass.indexOf('is-indeterminate');
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
selectedClass.splice(i, 1);
|
selectedClass.splice(i, 1);
|
||||||
}
|
}
|
||||||
selectedClass.push('is-active');
|
selectedClass.push('is-active');
|
||||||
|
// Add input manually
|
||||||
instance.addInput(this.fieldName, label.id);
|
instance.addInput(this.fieldName, label.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($form.find("input[type='hidden'][name='" + ($dropdown.data('fieldName')) + "'][value='" + (this.id(label)) + "']").length) {
|
if (this.id(label) && $form.find("input[type='hidden'][name='" + ($dropdown.data('fieldName')) + "'][value='" + this.id(label).toString().replace(/'/g, '\\\'') + "']").length) {
|
||||||
selectedClass.push('is-active');
|
selectedClass.push('is-active');
|
||||||
}
|
}
|
||||||
if ($dropdown.hasClass('js-multiselect') && removesAll) {
|
if ($dropdown.hasClass('js-multiselect') && removesAll) {
|
||||||
|
@ -172,6 +174,7 @@
|
||||||
}
|
}
|
||||||
if (label.duplicate) {
|
if (label.duplicate) {
|
||||||
spacing = 100 / label.color.length;
|
spacing = 100 / label.color.length;
|
||||||
|
// Reduce the colors to 4
|
||||||
label.color = label.color.filter(function(color, i) {
|
label.color = label.color.filter(function(color, i) {
|
||||||
return i < 4;
|
return i < 4;
|
||||||
});
|
});
|
||||||
|
@ -192,11 +195,13 @@
|
||||||
} else {
|
} else {
|
||||||
colorEl = '';
|
colorEl = '';
|
||||||
}
|
}
|
||||||
|
// We need to identify which items are actually labels
|
||||||
if (label.id) {
|
if (label.id) {
|
||||||
selectedClass.push('label-item');
|
selectedClass.push('label-item');
|
||||||
$a.attr('data-label-id', label.id);
|
$a.attr('data-label-id', label.id);
|
||||||
}
|
}
|
||||||
$a.addClass(selectedClass.join(' ')).html(colorEl + " " + label.title);
|
$a.addClass(selectedClass.join(' ')).html(colorEl + " " + label.title);
|
||||||
|
// Return generated html
|
||||||
return $li.html($a).prop('outerHTML');
|
return $li.html($a).prop('outerHTML');
|
||||||
},
|
},
|
||||||
persistWhenHide: $dropdown.data('persistWhenHide'),
|
persistWhenHide: $dropdown.data('persistWhenHide'),
|
||||||
|
@ -238,6 +243,7 @@
|
||||||
isIssueIndex = page === 'projects:issues:index';
|
isIssueIndex = page === 'projects:issues:index';
|
||||||
isMRIndex = page === 'projects:merge_requests:index';
|
isMRIndex = page === 'projects:merge_requests:index';
|
||||||
$selectbox.hide();
|
$selectbox.hide();
|
||||||
|
// display:block overrides the hide-collapse rule
|
||||||
$value.removeAttr('style');
|
$value.removeAttr('style');
|
||||||
if (page === 'projects:boards:show') {
|
if (page === 'projects:boards:show') {
|
||||||
return;
|
return;
|
||||||
|
@ -255,6 +261,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($dropdown.hasClass('js-filter-bulk-update')) {
|
if ($dropdown.hasClass('js-filter-bulk-update')) {
|
||||||
|
// If we are persisting state we need the classes
|
||||||
if (!this.options.persistWhenHide) {
|
if (!this.options.persistWhenHide) {
|
||||||
return $dropdown.parent().find('.is-active, .is-indeterminate').removeClass();
|
return $dropdown.parent().find('.is-active, .is-indeterminate').removeClass();
|
||||||
}
|
}
|
||||||
|
@ -324,7 +331,9 @@
|
||||||
if ($('.selected_issue:checked').length) {
|
if ($('.selected_issue:checked').length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Remove inputs
|
||||||
$('.issues_bulk_update .labels-filter input[type="hidden"]').remove();
|
$('.issues_bulk_update .labels-filter input[type="hidden"]').remove();
|
||||||
|
// Also restore button text
|
||||||
return $('.issues_bulk_update .labels-filter .dropdown-toggle-text').text('Label');
|
return $('.issues_bulk_update .labels-filter .dropdown-toggle-text').text('Label');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
hideEndFade($('.scrolling-tabs'));
|
var $scrollingTabs = $('.scrolling-tabs');
|
||||||
|
|
||||||
|
hideEndFade($scrollingTabs);
|
||||||
$(window).off('resize.nav').on('resize.nav', function() {
|
$(window).off('resize.nav').on('resize.nav', function() {
|
||||||
return hideEndFade($('.scrolling-tabs'));
|
return hideEndFade($scrollingTabs);
|
||||||
});
|
});
|
||||||
return $('.scrolling-tabs').on('scroll', function(event) {
|
$scrollingTabs.off('scroll').on('scroll', function(event) {
|
||||||
var $this, currentPosition, maxPosition;
|
var $this, currentPosition, maxPosition;
|
||||||
$this = $(this);
|
$this = $(this);
|
||||||
currentPosition = $this.scrollLeft();
|
currentPosition = $this.scrollLeft();
|
||||||
|
@ -22,6 +24,23 @@
|
||||||
$this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0);
|
$this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0);
|
||||||
return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1);
|
return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$scrollingTabs.each(function () {
|
||||||
|
var $this = $(this),
|
||||||
|
scrollingTabWidth = $this.width(),
|
||||||
|
$active = $this.find('.active'),
|
||||||
|
activeWidth = $active.width();
|
||||||
|
|
||||||
|
if ($active.length) {
|
||||||
|
var offset = $active.offset().left + activeWidth;
|
||||||
|
|
||||||
|
if (offset > scrollingTabWidth - 30) {
|
||||||
|
var scrollLeft = scrollingTabWidth / 2;
|
||||||
|
scrollLeft = (offset - scrollLeft) - (activeWidth / 2);
|
||||||
|
$this.scrollLeft(scrollLeft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -3,5 +3,4 @@
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -3,5 +3,4 @@
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
1
app/assets/javascripts/lib/d3.js
vendored
1
app/assets/javascripts/lib/d3.js
vendored
|
@ -3,5 +3,4 @@
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
|
|
||||||
/*= require raphael */
|
/*= require raphael */
|
||||||
|
|
||||||
|
|
||||||
/*= require g.raphael */
|
/*= require g.raphael */
|
||||||
|
|
||||||
|
|
||||||
/*= require g.bar */
|
/*= require g.bar */
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
if (setTimeago) {
|
if (setTimeago) {
|
||||||
$timeagoEls.timeago();
|
$timeagoEls.timeago();
|
||||||
$timeagoEls.tooltip('destroy');
|
$timeagoEls.tooltip('destroy');
|
||||||
|
// Recreate with custom template
|
||||||
return $timeagoEls.tooltip({
|
return $timeagoEls.tooltip({
|
||||||
template: '<div class="tooltip local-timeago" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
|
template: '<div class="tooltip local-timeago" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
|
||||||
});
|
});
|
||||||
|
@ -67,6 +68,14 @@
|
||||||
$.timeago.settings.strings = tmpLocale;
|
$.timeago.settings.strings = tmpLocale;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
w.gl.utils.getDayDifference = function(a, b) {
|
||||||
|
var millisecondsPerDay = 1000 * 60 * 60 * 24;
|
||||||
|
var date1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
|
||||||
|
var date2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
|
||||||
|
|
||||||
|
return Math.floor((date2 - date1) / millisecondsPerDay);
|
||||||
|
}
|
||||||
|
|
||||||
})(window);
|
})(window);
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
gl.emojiAliases = ->
|
|
||||||
JSON.parse('<%= Gitlab::AwardEmoji.aliases.to_json %>')
|
|
6
app/assets/javascripts/lib/utils/emoji_aliases.js.erb
Normal file
6
app/assets/javascripts/lib/utils/emoji_aliases.js.erb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
(function() {
|
||||||
|
gl.emojiAliases = function() {
|
||||||
|
return JSON.parse('<%= Gitlab::AwardEmoji.aliases.to_json %>');
|
||||||
|
};
|
||||||
|
|
||||||
|
}).call(this);
|
|
@ -6,6 +6,7 @@
|
||||||
notification = new Notification(message, opts);
|
notification = new Notification(message, opts);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
return notification.close();
|
return notification.close();
|
||||||
|
// Hide the notification after X amount of seconds
|
||||||
}, 8000);
|
}, 8000);
|
||||||
if (onclick) {
|
if (onclick) {
|
||||||
return notification.onclick = onclick;
|
return notification.onclick = onclick;
|
||||||
|
@ -22,12 +23,16 @@
|
||||||
body: body,
|
body: body,
|
||||||
icon: icon
|
icon: icon
|
||||||
};
|
};
|
||||||
|
// Let's check if the browser supports notifications
|
||||||
if (!('Notification' in window)) {
|
if (!('Notification' in window)) {
|
||||||
|
|
||||||
|
// do nothing
|
||||||
} else if (Notification.permission === 'granted') {
|
} else if (Notification.permission === 'granted') {
|
||||||
|
// If it's okay let's create a notification
|
||||||
return notificationGranted(message, opts, onclick);
|
return notificationGranted(message, opts, onclick);
|
||||||
} else if (Notification.permission !== 'denied') {
|
} else if (Notification.permission !== 'denied') {
|
||||||
return Notification.requestPermission(function(permission) {
|
return Notification.requestPermission(function(permission) {
|
||||||
|
// If the user accepts, let's create a notification
|
||||||
if (permission === 'granted') {
|
if (permission === 'granted') {
|
||||||
return notificationGranted(message, opts, onclick);
|
return notificationGranted(message, opts, onclick);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
lineBefore = this.lineBefore(text, textArea);
|
lineBefore = this.lineBefore(text, textArea);
|
||||||
lineAfter = this.lineAfter(text, textArea);
|
lineAfter = this.lineAfter(text, textArea);
|
||||||
if (lineBefore === blockTag && lineAfter === blockTag) {
|
if (lineBefore === blockTag && lineAfter === blockTag) {
|
||||||
|
// To remove the block tag we have to select the line before & after
|
||||||
if (blockTag != null) {
|
if (blockTag != null) {
|
||||||
textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1);
|
textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1);
|
||||||
textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1);
|
textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1);
|
||||||
|
@ -63,11 +64,11 @@
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
try {
|
try {
|
||||||
document.execCommand("ms-beginUndoUnit");
|
document.execCommand("ms-beginUndoUnit");
|
||||||
} catch (undefined) {}
|
} catch (error) {}
|
||||||
textArea.value = this.replaceRange(text, textArea.selectionStart, textArea.selectionEnd, insertText);
|
textArea.value = this.replaceRange(text, textArea.selectionStart, textArea.selectionEnd, insertText);
|
||||||
try {
|
try {
|
||||||
document.execCommand("ms-endUndoUnit");
|
document.execCommand("ms-endUndoUnit");
|
||||||
} catch (undefined) {}
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
return this.moveCursor(textArea, tag, wrap);
|
return this.moveCursor(textArea, tag, wrap);
|
||||||
};
|
};
|
||||||
|
@ -104,9 +105,12 @@
|
||||||
return self.updateText($this.closest('.md-area').find('textarea'), $this.data('md-tag'), $this.data('md-block'), !$this.data('md-prepend'));
|
return self.updateText($this.closest('.md-area').find('textarea'), $this.data('md-tag'), $this.data('md-block'), !$this.data('md-prepend'));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return gl.text.removeListeners = function(form) {
|
gl.text.removeListeners = function(form) {
|
||||||
return $('.js-md', form).off();
|
return $('.js-md', form).off();
|
||||||
};
|
};
|
||||||
|
return gl.text.truncate = function(string, maxLength) {
|
||||||
|
return string.substr(0, (maxLength - 3)) + '...';
|
||||||
|
};
|
||||||
})(window);
|
})(window);
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
if ((base = w.gl).utils == null) {
|
if ((base = w.gl).utils == null) {
|
||||||
base.utils = {};
|
base.utils = {};
|
||||||
}
|
}
|
||||||
|
// Returns an array containing the value(s) of the
|
||||||
|
// of the key passed as an argument
|
||||||
w.gl.utils.getParameterValues = function(sParam) {
|
w.gl.utils.getParameterValues = function(sParam) {
|
||||||
var i, sPageURL, sParameterName, sURLVariables, values;
|
var i, sPageURL, sParameterName, sURLVariables, values;
|
||||||
sPageURL = decodeURIComponent(window.location.search.substring(1));
|
sPageURL = decodeURIComponent(window.location.search.substring(1));
|
||||||
|
@ -23,6 +25,8 @@
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
};
|
};
|
||||||
|
// @param {Object} params - url keys and value to merge
|
||||||
|
// @param {String} url
|
||||||
w.gl.utils.mergeUrlParams = function(params, url) {
|
w.gl.utils.mergeUrlParams = function(params, url) {
|
||||||
var lastChar, newUrl, paramName, paramValue, pattern;
|
var lastChar, newUrl, paramName, paramValue, pattern;
|
||||||
newUrl = decodeURIComponent(url);
|
newUrl = decodeURIComponent(url);
|
||||||
|
@ -37,12 +41,14 @@
|
||||||
newUrl = "" + newUrl + (newUrl.indexOf('?') > 0 ? '&' : '?') + paramName + "=" + paramValue;
|
newUrl = "" + newUrl + (newUrl.indexOf('?') > 0 ? '&' : '?') + paramName + "=" + paramValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remove a trailing ampersand
|
||||||
lastChar = newUrl[newUrl.length - 1];
|
lastChar = newUrl[newUrl.length - 1];
|
||||||
if (lastChar === '&') {
|
if (lastChar === '&') {
|
||||||
newUrl = newUrl.slice(0, -1);
|
newUrl = newUrl.slice(0, -1);
|
||||||
}
|
}
|
||||||
return newUrl;
|
return newUrl;
|
||||||
};
|
};
|
||||||
|
// removes parameter query string from url. returns the modified url
|
||||||
w.gl.utils.removeParamQueryString = function(url, param) {
|
w.gl.utils.removeParamQueryString = function(url, param) {
|
||||||
var urlVariables, variables;
|
var urlVariables, variables;
|
||||||
url = decodeURIComponent(url);
|
url = decodeURIComponent(url);
|
||||||
|
|
|
@ -1,17 +1,49 @@
|
||||||
|
// LineHighlighter
|
||||||
|
//
|
||||||
|
// Handles single- and multi-line selection and highlight for blob views.
|
||||||
|
//
|
||||||
/*= require jquery.scrollTo */
|
/*= require jquery.scrollTo */
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### Example Markup
|
||||||
|
//
|
||||||
|
// <div id="blob-content-holder">
|
||||||
|
// <div class="file-content">
|
||||||
|
// <div class="line-numbers">
|
||||||
|
// <a href="#L1" id="L1" data-line-number="1">1</a>
|
||||||
|
// <a href="#L2" id="L2" data-line-number="2">2</a>
|
||||||
|
// <a href="#L3" id="L3" data-line-number="3">3</a>
|
||||||
|
// <a href="#L4" id="L4" data-line-number="4">4</a>
|
||||||
|
// <a href="#L5" id="L5" data-line-number="5">5</a>
|
||||||
|
// </div>
|
||||||
|
// <pre class="code highlight">
|
||||||
|
// <code>
|
||||||
|
// <span id="LC1" class="line">...</span>
|
||||||
|
// <span id="LC2" class="line">...</span>
|
||||||
|
// <span id="LC3" class="line">...</span>
|
||||||
|
// <span id="LC4" class="line">...</span>
|
||||||
|
// <span id="LC5" class="line">...</span>
|
||||||
|
// </code>
|
||||||
|
// </pre>
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
//
|
||||||
(function() {
|
(function() {
|
||||||
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||||
|
|
||||||
this.LineHighlighter = (function() {
|
this.LineHighlighter = (function() {
|
||||||
|
// CSS class applied to highlighted lines
|
||||||
LineHighlighter.prototype.highlightClass = 'hll';
|
LineHighlighter.prototype.highlightClass = 'hll';
|
||||||
|
|
||||||
|
// Internal copy of location.hash so we're not dependent on `location` in tests
|
||||||
LineHighlighter.prototype._hash = '';
|
LineHighlighter.prototype._hash = '';
|
||||||
|
|
||||||
function LineHighlighter(hash) {
|
function LineHighlighter(hash) {
|
||||||
var range;
|
var range;
|
||||||
if (hash == null) {
|
if (hash == null) {
|
||||||
|
// Initialize a LineHighlighter object
|
||||||
|
//
|
||||||
|
// hash - String URL hash for dependency injection in tests
|
||||||
hash = location.hash;
|
hash = location.hash;
|
||||||
}
|
}
|
||||||
this.setHash = bind(this.setHash, this);
|
this.setHash = bind(this.setHash, this);
|
||||||
|
@ -24,6 +56,8 @@
|
||||||
if (range[0]) {
|
if (range[0]) {
|
||||||
this.highlightRange(range);
|
this.highlightRange(range);
|
||||||
$.scrollTo("#L" + range[0], {
|
$.scrollTo("#L" + range[0], {
|
||||||
|
// Scroll to the first highlighted line on initial load
|
||||||
|
// Offset -50 for the sticky top bar, and another -100 for some context
|
||||||
offset: -150
|
offset: -150
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -32,6 +66,12 @@
|
||||||
|
|
||||||
LineHighlighter.prototype.bindEvents = function() {
|
LineHighlighter.prototype.bindEvents = function() {
|
||||||
$('#blob-content-holder').on('mousedown', 'a[data-line-number]', this.clickHandler);
|
$('#blob-content-holder').on('mousedown', 'a[data-line-number]', this.clickHandler);
|
||||||
|
// While it may seem odd to bind to the mousedown event and then throw away
|
||||||
|
// the click event, there is a method to our madness.
|
||||||
|
//
|
||||||
|
// If not done this way, the line number anchor will sometimes keep its
|
||||||
|
// active state even when the event is cancelled, resulting in an ugly border
|
||||||
|
// around the link and/or a persisted underline text decoration.
|
||||||
return $('#blob-content-holder').on('click', 'a[data-line-number]', function(event) {
|
return $('#blob-content-holder').on('click', 'a[data-line-number]', function(event) {
|
||||||
return event.preventDefault();
|
return event.preventDefault();
|
||||||
});
|
});
|
||||||
|
@ -44,6 +84,8 @@
|
||||||
lineNumber = $(event.target).closest('a').data('line-number');
|
lineNumber = $(event.target).closest('a').data('line-number');
|
||||||
current = this.hashToRange(this._hash);
|
current = this.hashToRange(this._hash);
|
||||||
if (!(current[0] && event.shiftKey)) {
|
if (!(current[0] && event.shiftKey)) {
|
||||||
|
// If there's no current selection, or there is but Shift wasn't held,
|
||||||
|
// treat this like a single-line selection.
|
||||||
this.setHash(lineNumber);
|
this.setHash(lineNumber);
|
||||||
return this.highlightLine(lineNumber);
|
return this.highlightLine(lineNumber);
|
||||||
} else if (event.shiftKey) {
|
} else if (event.shiftKey) {
|
||||||
|
@ -59,10 +101,23 @@
|
||||||
|
|
||||||
LineHighlighter.prototype.clearHighlight = function() {
|
LineHighlighter.prototype.clearHighlight = function() {
|
||||||
return $("." + this.highlightClass).removeClass(this.highlightClass);
|
return $("." + this.highlightClass).removeClass(this.highlightClass);
|
||||||
|
// Unhighlight previously highlighted lines
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Convert a URL hash String into line numbers
|
||||||
|
//
|
||||||
|
// hash - Hash String
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// hashToRange('#L5') # => [5, null]
|
||||||
|
// hashToRange('#L5-15') # => [5, 15]
|
||||||
|
// hashToRange('#foo') # => [null, null]
|
||||||
|
//
|
||||||
|
// Returns an Array
|
||||||
LineHighlighter.prototype.hashToRange = function(hash) {
|
LineHighlighter.prototype.hashToRange = function(hash) {
|
||||||
var first, last, matches;
|
var first, last, matches;
|
||||||
|
//?L(\d+)(?:-(\d+))?$/)
|
||||||
matches = hash.match(/^#?L(\d+)(?:-(\d+))?$/);
|
matches = hash.match(/^#?L(\d+)(?:-(\d+))?$/);
|
||||||
if (matches && matches.length) {
|
if (matches && matches.length) {
|
||||||
first = parseInt(matches[1]);
|
first = parseInt(matches[1]);
|
||||||
|
@ -73,10 +128,16 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Highlight a single line
|
||||||
|
//
|
||||||
|
// lineNumber - Line number to highlight
|
||||||
LineHighlighter.prototype.highlightLine = function(lineNumber) {
|
LineHighlighter.prototype.highlightLine = function(lineNumber) {
|
||||||
return $("#LC" + lineNumber).addClass(this.highlightClass);
|
return $("#LC" + lineNumber).addClass(this.highlightClass);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Highlight all lines within a range
|
||||||
|
//
|
||||||
|
// range - Array containing the starting and ending line numbers
|
||||||
LineHighlighter.prototype.highlightRange = function(range) {
|
LineHighlighter.prototype.highlightRange = function(range) {
|
||||||
var i, lineNumber, ref, ref1, results;
|
var i, lineNumber, ref, ref1, results;
|
||||||
if (range[1]) {
|
if (range[1]) {
|
||||||
|
@ -90,6 +151,7 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set the URL hash string
|
||||||
LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
|
LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
|
||||||
var hash;
|
var hash;
|
||||||
if (lastLineNumber) {
|
if (lastLineNumber) {
|
||||||
|
@ -101,10 +163,15 @@
|
||||||
return this.__setLocationHash__(hash);
|
return this.__setLocationHash__(hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Make the actual hash change in the browser
|
||||||
|
//
|
||||||
|
// This method is stubbed in tests.
|
||||||
LineHighlighter.prototype.__setLocationHash__ = function(value) {
|
LineHighlighter.prototype.__setLocationHash__ = function(value) {
|
||||||
return history.pushState({
|
return history.pushState({
|
||||||
turbolinks: false,
|
turbolinks: false,
|
||||||
url: value
|
url: value
|
||||||
|
// We're using pushState instead of assigning location.hash directly to
|
||||||
|
// prevent the page from scrolling on the hashchange event
|
||||||
}, document.title, value);
|
}, document.title, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,54 +1,12 @@
|
||||||
(function() {
|
(function() {
|
||||||
var clearHighlights, currentTimer, defaultClass, delay, firstPiece, pieceIndex, pieces, start, stop, work;
|
|
||||||
|
|
||||||
Turbolinks.enableProgressBar();
|
Turbolinks.enableProgressBar();
|
||||||
|
|
||||||
defaultClass = 'tanuki-shape';
|
$(document).on('page:fetch', function() {
|
||||||
|
$('.tanuki-logo').addClass('animate');
|
||||||
|
});
|
||||||
|
|
||||||
pieces = ['path#tanuki-right-cheek', 'path#tanuki-right-eye, path#tanuki-right-ear', 'path#tanuki-nose', 'path#tanuki-left-eye, path#tanuki-left-ear', 'path#tanuki-left-cheek'];
|
$(document).on('page:change', function() {
|
||||||
|
$('.tanuki-logo').removeClass('animate');
|
||||||
pieceIndex = 0;
|
});
|
||||||
|
|
||||||
firstPiece = pieces[0];
|
|
||||||
|
|
||||||
currentTimer = null;
|
|
||||||
|
|
||||||
delay = 150;
|
|
||||||
|
|
||||||
clearHighlights = function() {
|
|
||||||
return $("." + defaultClass + ".highlight").attr('class', defaultClass);
|
|
||||||
};
|
|
||||||
|
|
||||||
start = function() {
|
|
||||||
clearHighlights();
|
|
||||||
pieceIndex = 0;
|
|
||||||
if (pieces[0] !== firstPiece) {
|
|
||||||
pieces.reverse();
|
|
||||||
}
|
|
||||||
if (currentTimer) {
|
|
||||||
clearInterval(currentTimer);
|
|
||||||
}
|
|
||||||
return currentTimer = setInterval(work, delay);
|
|
||||||
};
|
|
||||||
|
|
||||||
stop = function() {
|
|
||||||
clearInterval(currentTimer);
|
|
||||||
return clearHighlights();
|
|
||||||
};
|
|
||||||
|
|
||||||
work = function() {
|
|
||||||
clearHighlights();
|
|
||||||
$(pieces[pieceIndex]).attr('class', defaultClass + " highlight");
|
|
||||||
if (pieceIndex === pieces.length - 1) {
|
|
||||||
pieceIndex = 0;
|
|
||||||
return pieces.reverse();
|
|
||||||
} else {
|
|
||||||
return pieceIndex++;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).on('page:fetch', start);
|
|
||||||
|
|
||||||
$(document).on('page:change', stop);
|
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -75,10 +75,8 @@ class MergeConflictResolver {
|
||||||
window.location.href = data.redirect_to;
|
window.location.href = data.redirect_to;
|
||||||
})
|
})
|
||||||
.error(() => {
|
.error(() => {
|
||||||
new Flash('Something went wrong!');
|
|
||||||
})
|
|
||||||
.always(() => {
|
|
||||||
this.vue.isSubmitting = false;
|
this.vue.isSubmitting = false;
|
||||||
|
new Flash('Something went wrong!');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
|
|
||||||
/*= require jquery.waitforimages */
|
/*= require jquery.waitforimages */
|
||||||
|
|
||||||
|
|
||||||
/*= require task_list */
|
/*= require task_list */
|
||||||
|
|
||||||
|
|
||||||
/*= require merge_request_tabs */
|
/*= require merge_request_tabs */
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
@ -12,6 +8,11 @@
|
||||||
|
|
||||||
this.MergeRequest = (function() {
|
this.MergeRequest = (function() {
|
||||||
function MergeRequest(opts) {
|
function MergeRequest(opts) {
|
||||||
|
// Initialize MergeRequest behavior
|
||||||
|
//
|
||||||
|
// Options:
|
||||||
|
// action - String, current controller action
|
||||||
|
//
|
||||||
this.opts = opts != null ? opts : {};
|
this.opts = opts != null ? opts : {};
|
||||||
this.submitNoteForm = bind(this.submitNoteForm, this);
|
this.submitNoteForm = bind(this.submitNoteForm, this);
|
||||||
this.$el = $('.merge-request');
|
this.$el = $('.merge-request');
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
this.initTabs();
|
this.initTabs();
|
||||||
|
// Prevent duplicate event bindings
|
||||||
this.disableTaskList();
|
this.disableTaskList();
|
||||||
this.initMRBtnListeners();
|
this.initMRBtnListeners();
|
||||||
if ($("a.btn-close").length) {
|
if ($("a.btn-close").length) {
|
||||||
|
@ -28,14 +30,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Local jQuery finder
|
||||||
MergeRequest.prototype.$ = function(selector) {
|
MergeRequest.prototype.$ = function(selector) {
|
||||||
return this.$el.find(selector);
|
return this.$el.find(selector);
|
||||||
};
|
};
|
||||||
|
|
||||||
MergeRequest.prototype.initTabs = function() {
|
MergeRequest.prototype.initTabs = function() {
|
||||||
if (this.opts.action !== 'new') {
|
if (this.opts.action !== 'new') {
|
||||||
|
// `MergeRequests#new` has no tab-persisting or lazy-loading behavior
|
||||||
window.mrTabs = new MergeRequestTabs(this.opts);
|
window.mrTabs = new MergeRequestTabs(this.opts);
|
||||||
} else {
|
} else {
|
||||||
|
// Show the first tab (Commits)
|
||||||
return $('.merge-request-tabs a[data-toggle="tab"]:first').tab('show');
|
return $('.merge-request-tabs a[data-toggle="tab"]:first').tab('show');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -96,6 +101,8 @@
|
||||||
url: $('form.js-issuable-update').attr('action'),
|
url: $('form.js-issuable-update').attr('action'),
|
||||||
data: patchData
|
data: patchData
|
||||||
});
|
});
|
||||||
|
// TODO (rspeicher): Make the merge request description inline-editable like a
|
||||||
|
// note so that we can re-use its form here
|
||||||
};
|
};
|
||||||
|
|
||||||
return MergeRequest;
|
return MergeRequest;
|
||||||
|
|
|
@ -1,6 +1,49 @@
|
||||||
|
// MergeRequestTabs
|
||||||
|
//
|
||||||
|
// Handles persisting and restoring the current tab selection and lazily-loading
|
||||||
|
// content on the MergeRequests#show page.
|
||||||
|
//
|
||||||
/*= require jquery.cookie */
|
/*= require jquery.cookie */
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### Example Markup
|
||||||
|
//
|
||||||
|
// <ul class="nav-links 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>
|
||||||
|
//
|
||||||
(function() {
|
(function() {
|
||||||
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||||
|
|
||||||
|
@ -19,6 +62,7 @@
|
||||||
this.setCurrentAction = bind(this.setCurrentAction, this);
|
this.setCurrentAction = bind(this.setCurrentAction, this);
|
||||||
this.tabShown = bind(this.tabShown, this);
|
this.tabShown = bind(this.tabShown, this);
|
||||||
this.showTab = bind(this.showTab, this);
|
this.showTab = bind(this.showTab, this);
|
||||||
|
// Store the `location` object, allowing for easier stubbing in tests
|
||||||
this._location = location;
|
this._location = location;
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
this.activateTab(this.opts.action);
|
this.activateTab(this.opts.action);
|
||||||
|
@ -77,6 +121,7 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Activate a tab based on the current action
|
||||||
MergeRequestTabs.prototype.activateTab = function(action) {
|
MergeRequestTabs.prototype.activateTab = function(action) {
|
||||||
if (action === 'show') {
|
if (action === 'show') {
|
||||||
action = 'notes';
|
action = 'notes';
|
||||||
|
@ -84,20 +129,48 @@
|
||||||
return $(".merge-request-tabs a[data-action='" + action + "']").tab('show');
|
return $(".merge-request-tabs a[data-action='" + action + "']").tab('show');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
//
|
||||||
|
// Returns the new URL String
|
||||||
MergeRequestTabs.prototype.setCurrentAction = function(action) {
|
MergeRequestTabs.prototype.setCurrentAction = function(action) {
|
||||||
var new_state;
|
var new_state;
|
||||||
|
// Normalize action, just to be safe
|
||||||
if (action === 'show') {
|
if (action === 'show') {
|
||||||
action = 'notes';
|
action = 'notes';
|
||||||
}
|
}
|
||||||
this.currentAction = action;
|
this.currentAction = action;
|
||||||
|
// Remove a trailing '/commits' or '/diffs'
|
||||||
new_state = this._location.pathname.replace(/\/(commits|diffs|builds|pipelines)(\.html)?\/?$/, '');
|
new_state = this._location.pathname.replace(/\/(commits|diffs|builds|pipelines)(\.html)?\/?$/, '');
|
||||||
|
// Append the new action if we're on a tab other than 'notes'
|
||||||
if (action !== 'notes') {
|
if (action !== 'notes') {
|
||||||
new_state += "/" + action;
|
new_state += "/" + action;
|
||||||
}
|
}
|
||||||
|
// Ensure parameters and hash come along for the ride
|
||||||
new_state += this._location.search + this._location.hash;
|
new_state += this._location.search + this._location.hash;
|
||||||
history.replaceState({
|
history.replaceState({
|
||||||
turbolinks: true,
|
turbolinks: true,
|
||||||
url: new_state
|
url: new_state
|
||||||
|
// Replace the current history state with the new one without breaking
|
||||||
|
// Turbolinks' history.
|
||||||
|
//
|
||||||
|
// See https://github.com/rails/turbolinks/issues/363
|
||||||
}, document.title, new_state);
|
}, document.title, new_state);
|
||||||
return new_state;
|
return new_state;
|
||||||
};
|
};
|
||||||
|
@ -159,10 +232,10 @@
|
||||||
$('.hll').removeClass('hll');
|
$('.hll').removeClass('hll');
|
||||||
locationHash = window.location.hash;
|
locationHash = window.location.hash;
|
||||||
if (locationHash !== '') {
|
if (locationHash !== '') {
|
||||||
hashClassString = "." + (locationHash.replace('#', ''));
|
dataLineString = '[data-line-code="' + locationHash.replace('#', '') + '"]';
|
||||||
$diffLine = $(locationHash + ":not(.match)", $('#diffs'));
|
$diffLine = $(locationHash + ":not(.match)", $('#diffs'));
|
||||||
if (!$diffLine.is('tr')) {
|
if (!$diffLine.is('tr')) {
|
||||||
$diffLine = $('#diffs').find("td" + locationHash + ", td" + hashClassString);
|
$diffLine = $('#diffs').find("td" + locationHash + ", td" + dataLineString);
|
||||||
} else {
|
} else {
|
||||||
$diffLine = $diffLine.find('td');
|
$diffLine = $diffLine.find('td');
|
||||||
}
|
}
|
||||||
|
@ -206,6 +279,9 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Show or hide the loading spinner
|
||||||
|
//
|
||||||
|
// status - Boolean, true to show, false to hide
|
||||||
MergeRequestTabs.prototype.toggleLoading = function(status) {
|
MergeRequestTabs.prototype.toggleLoading = function(status) {
|
||||||
return $('.mr-loading-status .loading').toggle(status);
|
return $('.mr-loading-status .loading').toggle(status);
|
||||||
};
|
};
|
||||||
|
@ -232,6 +308,7 @@
|
||||||
|
|
||||||
MergeRequestTabs.prototype.diffViewType = function() {
|
MergeRequestTabs.prototype.diffViewType = function() {
|
||||||
return $('.inline-parallel-buttons a.active').data('view-type');
|
return $('.inline-parallel-buttons a.active').data('view-type');
|
||||||
|
// Returns diff view type
|
||||||
};
|
};
|
||||||
|
|
||||||
MergeRequestTabs.prototype.expandViewContainer = function() {
|
MergeRequestTabs.prototype.expandViewContainer = function() {
|
||||||
|
@ -245,6 +322,8 @@
|
||||||
if ($gutterIcon.is('.fa-angle-double-right')) {
|
if ($gutterIcon.is('.fa-angle-double-right')) {
|
||||||
return $gutterIcon.closest('a').trigger('click', [true]);
|
return $gutterIcon.closest('a').trigger('click', [true]);
|
||||||
}
|
}
|
||||||
|
// Wait until listeners are set
|
||||||
|
// Only when sidebar is expanded
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -259,6 +338,9 @@
|
||||||
return $gutterIcon.closest('a').trigger('click', [true]);
|
return $gutterIcon.closest('a').trigger('click', [true]);
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
|
// Expand the issuable sidebar unless the user explicitly collapsed it
|
||||||
|
// Wait until listeners are set
|
||||||
|
// Only when sidebar is collapsed
|
||||||
};
|
};
|
||||||
|
|
||||||
return MergeRequestTabs;
|
return MergeRequestTabs;
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
|
|
||||||
this.MergeRequestWidget = (function() {
|
this.MergeRequestWidget = (function() {
|
||||||
function MergeRequestWidget(opts) {
|
function MergeRequestWidget(opts) {
|
||||||
|
// Initialize MergeRequestWidget behavior
|
||||||
|
//
|
||||||
|
// check_enable - Boolean, whether to check automerge status
|
||||||
|
// merge_check_url - String, URL to use to check automerge status
|
||||||
|
// ci_status_url - String, URL to use to check CI status
|
||||||
|
//
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
$('#modal_merge_info').modal({
|
$('#modal_merge_info').modal({
|
||||||
show: false
|
show: false
|
||||||
|
@ -118,6 +124,8 @@
|
||||||
if (data.coverage) {
|
if (data.coverage) {
|
||||||
_this.showCICoverage(data.coverage);
|
_this.showCICoverage(data.coverage);
|
||||||
}
|
}
|
||||||
|
// The first check should only update the UI, a notification
|
||||||
|
// should only be displayed on status changes
|
||||||
if (showNotification && !_this.firstCICheck) {
|
if (showNotification && !_this.firstCICheck) {
|
||||||
status = _this.ciLabelForStatus(data.status);
|
status = _this.ciLabelForStatus(data.status);
|
||||||
if (status === "preparing") {
|
if (status === "preparing") {
|
||||||
|
|
|
@ -110,6 +110,7 @@
|
||||||
},
|
},
|
||||||
update: function(event, ui) {
|
update: function(event, ui) {
|
||||||
var data;
|
var data;
|
||||||
|
// Prevents sorting from container which element has been removed.
|
||||||
if ($(this).find(ui.item).length > 0) {
|
if ($(this).find(ui.item).length > 0) {
|
||||||
data = $(this).sortable("serialize");
|
data = $(this).sortable("serialize");
|
||||||
return Milestone.sortIssues(data);
|
return Milestone.sortIssues(data);
|
||||||
|
|
|
@ -92,6 +92,7 @@
|
||||||
},
|
},
|
||||||
hidden: function() {
|
hidden: function() {
|
||||||
$selectbox.hide();
|
$selectbox.hide();
|
||||||
|
// display:block overrides the hide-collapse rule
|
||||||
return $value.css('display', '');
|
return $value.css('display', '');
|
||||||
},
|
},
|
||||||
clicked: function(selected, $el, e) {
|
clicked: function(selected, $el, e) {
|
||||||
|
|
|
@ -90,6 +90,7 @@
|
||||||
results = [];
|
results = [];
|
||||||
while (k < this.mspace) {
|
while (k < this.mspace) {
|
||||||
this.colors.push(Raphael.getColor(.8));
|
this.colors.push(Raphael.getColor(.8));
|
||||||
|
// Skipping a few colors in the spectrum to get more contrast between colors
|
||||||
Raphael.getColor();
|
Raphael.getColor();
|
||||||
Raphael.getColor();
|
Raphael.getColor();
|
||||||
results.push(k++);
|
results.push(k++);
|
||||||
|
@ -112,6 +113,7 @@
|
||||||
for (mm = j = 0, len = ref.length; j < len; mm = ++j) {
|
for (mm = j = 0, len = ref.length; j < len; mm = ++j) {
|
||||||
day = ref[mm];
|
day = ref[mm];
|
||||||
if (cuday !== day[0] || cumonth !== day[1]) {
|
if (cuday !== day[0] || cumonth !== day[1]) {
|
||||||
|
// Dates
|
||||||
r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({
|
r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({
|
||||||
font: "12px Monaco, monospace",
|
font: "12px Monaco, monospace",
|
||||||
fill: "#BBB"
|
fill: "#BBB"
|
||||||
|
@ -119,6 +121,7 @@
|
||||||
cuday = day[0];
|
cuday = day[0];
|
||||||
}
|
}
|
||||||
if (cumonth !== day[1]) {
|
if (cumonth !== day[1]) {
|
||||||
|
// Months
|
||||||
r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({
|
r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({
|
||||||
font: "12px Monaco, monospace",
|
font: "12px Monaco, monospace",
|
||||||
fill: "#EEE"
|
fill: "#EEE"
|
||||||
|
@ -207,6 +210,7 @@
|
||||||
}
|
}
|
||||||
r = this.r;
|
r = this.r;
|
||||||
shortrefs = commit.refs;
|
shortrefs = commit.refs;
|
||||||
|
// Truncate if longer than 15 chars
|
||||||
if (shortrefs.length > 17) {
|
if (shortrefs.length > 17) {
|
||||||
shortrefs = shortrefs.substr(0, 15) + "…";
|
shortrefs = shortrefs.substr(0, 15) + "…";
|
||||||
}
|
}
|
||||||
|
@ -217,6 +221,7 @@
|
||||||
title: commit.refs
|
title: commit.refs
|
||||||
});
|
});
|
||||||
textbox = text.getBBox();
|
textbox = text.getBBox();
|
||||||
|
// Create rectangle based on the size of the textbox
|
||||||
rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({
|
rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({
|
||||||
fill: "#000",
|
fill: "#000",
|
||||||
"fill-opacity": .5,
|
"fill-opacity": .5,
|
||||||
|
@ -229,6 +234,7 @@
|
||||||
});
|
});
|
||||||
label = r.set(rect, text);
|
label = r.set(rect, text);
|
||||||
label.transform(["t", -rect.getBBox().width - 15, 0]);
|
label.transform(["t", -rect.getBBox().width - 15, 0]);
|
||||||
|
// Set text to front
|
||||||
return text.toFront();
|
return text.toFront();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -283,11 +289,13 @@
|
||||||
parentY = this.offsetY + this.unitTime * parentCommit.time;
|
parentY = this.offsetY + this.unitTime * parentCommit.time;
|
||||||
parentX1 = this.offsetX + this.unitSpace * (this.mspace - parentCommit.space);
|
parentX1 = this.offsetX + this.unitSpace * (this.mspace - parentCommit.space);
|
||||||
parentX2 = this.offsetX + this.unitSpace * (this.mspace - parent[1]);
|
parentX2 = this.offsetX + this.unitSpace * (this.mspace - parent[1]);
|
||||||
|
// Set line color
|
||||||
if (parentCommit.space <= commit.space) {
|
if (parentCommit.space <= commit.space) {
|
||||||
color = this.colors[commit.space];
|
color = this.colors[commit.space];
|
||||||
} else {
|
} else {
|
||||||
color = this.colors[parentCommit.space];
|
color = this.colors[parentCommit.space];
|
||||||
}
|
}
|
||||||
|
// Build line shape
|
||||||
if (parent[1] === commit.space) {
|
if (parent[1] === commit.space) {
|
||||||
offset = [0, 5];
|
offset = [0, 5];
|
||||||
arrow = "l-2,5,4,0,-2,-5,0,5";
|
arrow = "l-2,5,4,0,-2,-5,0,5";
|
||||||
|
@ -298,13 +306,17 @@
|
||||||
offset = [-3, 3];
|
offset = [-3, 3];
|
||||||
arrow = "l-5,0,2,4,3,-4,-4,2";
|
arrow = "l-5,0,2,4,3,-4,-4,2";
|
||||||
}
|
}
|
||||||
|
// Start point
|
||||||
route = ["M", x + offset[0], y + offset[1]];
|
route = ["M", x + offset[0], y + offset[1]];
|
||||||
|
// Add arrow if not first parent
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
route.push(arrow);
|
route.push(arrow);
|
||||||
}
|
}
|
||||||
|
// Circumvent if overlap
|
||||||
if (commit.space !== parentCommit.space || commit.space !== parent[1]) {
|
if (commit.space !== parentCommit.space || commit.space !== parent[1]) {
|
||||||
route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5);
|
route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5);
|
||||||
}
|
}
|
||||||
|
// End point
|
||||||
route.push("L", parentX1, parentY);
|
route.push("L", parentX1, parentY);
|
||||||
results.push(r.path(route).attr({
|
results.push(r.path(route).attr({
|
||||||
stroke: color,
|
stroke: color,
|
||||||
|
@ -325,6 +337,7 @@
|
||||||
"fill-opacity": .5,
|
"fill-opacity": .5,
|
||||||
stroke: "none"
|
stroke: "none"
|
||||||
});
|
});
|
||||||
|
// Displayed in the center
|
||||||
return this.element.scrollTop(y - this.graphHeight / 2);
|
return this.element.scrollTop(y - this.graphHeight / 2);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
|
// This is a manifest file that'll be compiled into including all the files listed below.
|
||||||
|
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
|
||||||
|
// be included in the compiled file accessible from http://example.com/assets/application.js
|
||||||
|
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||||
|
// the compiled file.
|
||||||
|
//
|
||||||
/*= require_tree . */
|
/*= require_tree . */
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
|
@ -1,22 +1,10 @@
|
||||||
|
|
||||||
/*= require autosave */
|
/*= require autosave */
|
||||||
|
|
||||||
|
|
||||||
/*= require autosize */
|
/*= require autosize */
|
||||||
|
|
||||||
|
|
||||||
/*= require dropzone */
|
/*= require dropzone */
|
||||||
|
|
||||||
|
|
||||||
/*= require dropzone_input */
|
/*= require dropzone_input */
|
||||||
|
|
||||||
|
|
||||||
/*= require gfm_auto_complete */
|
/*= require gfm_auto_complete */
|
||||||
|
|
||||||
|
|
||||||
/*= require jquery.atwho */
|
/*= require jquery.atwho */
|
||||||
|
|
||||||
|
|
||||||
/*= require task_list */
|
/*= require task_list */
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
@ -60,26 +48,43 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
Notes.prototype.addBinding = function() {
|
Notes.prototype.addBinding = function() {
|
||||||
|
// add note to UI after creation
|
||||||
$(document).on("ajax:success", ".js-main-target-form", this.addNote);
|
$(document).on("ajax:success", ".js-main-target-form", this.addNote);
|
||||||
$(document).on("ajax:success", ".js-discussion-note-form", this.addDiscussionNote);
|
$(document).on("ajax:success", ".js-discussion-note-form", this.addDiscussionNote);
|
||||||
|
// catch note ajax errors
|
||||||
$(document).on("ajax:error", ".js-main-target-form", this.addNoteError);
|
$(document).on("ajax:error", ".js-main-target-form", this.addNoteError);
|
||||||
|
// change note in UI after update
|
||||||
$(document).on("ajax:success", "form.edit-note", this.updateNote);
|
$(document).on("ajax:success", "form.edit-note", this.updateNote);
|
||||||
|
// Edit note link
|
||||||
$(document).on("click", ".js-note-edit", this.showEditForm);
|
$(document).on("click", ".js-note-edit", this.showEditForm);
|
||||||
$(document).on("click", ".note-edit-cancel", this.cancelEdit);
|
$(document).on("click", ".note-edit-cancel", this.cancelEdit);
|
||||||
|
// Reopen and close actions for Issue/MR combined with note form submit
|
||||||
$(document).on("click", ".js-comment-button", this.updateCloseButton);
|
$(document).on("click", ".js-comment-button", this.updateCloseButton);
|
||||||
$(document).on("keyup input", ".js-note-text", this.updateTargetButtons);
|
$(document).on("keyup input", ".js-note-text", this.updateTargetButtons);
|
||||||
|
// resolve a discussion
|
||||||
$(document).on('click', '.js-comment-resolve-button', this.resolveDiscussion);
|
$(document).on('click', '.js-comment-resolve-button', this.resolveDiscussion);
|
||||||
|
// remove a note (in general)
|
||||||
$(document).on("click", ".js-note-delete", this.removeNote);
|
$(document).on("click", ".js-note-delete", this.removeNote);
|
||||||
|
// delete note attachment
|
||||||
$(document).on("click", ".js-note-attachment-delete", this.removeAttachment);
|
$(document).on("click", ".js-note-attachment-delete", this.removeAttachment);
|
||||||
|
// reset main target form after submit
|
||||||
$(document).on("ajax:complete", ".js-main-target-form", this.reenableTargetFormSubmitButton);
|
$(document).on("ajax:complete", ".js-main-target-form", this.reenableTargetFormSubmitButton);
|
||||||
$(document).on("ajax:success", ".js-main-target-form", this.resetMainTargetForm);
|
$(document).on("ajax:success", ".js-main-target-form", this.resetMainTargetForm);
|
||||||
|
// reset main target form when clicking discard
|
||||||
$(document).on("click", ".js-note-discard", this.resetMainTargetForm);
|
$(document).on("click", ".js-note-discard", this.resetMainTargetForm);
|
||||||
|
// update the file name when an attachment is selected
|
||||||
$(document).on("change", ".js-note-attachment-input", this.updateFormAttachment);
|
$(document).on("change", ".js-note-attachment-input", this.updateFormAttachment);
|
||||||
|
// reply to diff/discussion notes
|
||||||
$(document).on("click", ".js-discussion-reply-button", this.replyToDiscussionNote);
|
$(document).on("click", ".js-discussion-reply-button", this.replyToDiscussionNote);
|
||||||
|
// add diff note
|
||||||
$(document).on("click", ".js-add-diff-note-button", this.addDiffNote);
|
$(document).on("click", ".js-add-diff-note-button", this.addDiffNote);
|
||||||
|
// hide diff note form
|
||||||
$(document).on("click", ".js-close-discussion-note-form", this.cancelDiscussionForm);
|
$(document).on("click", ".js-close-discussion-note-form", this.cancelDiscussionForm);
|
||||||
|
// fetch notes when tab becomes visible
|
||||||
$(document).on("visibilitychange", this.visibilityChange);
|
$(document).on("visibilitychange", this.visibilityChange);
|
||||||
|
// when issue status changes, we need to refresh data
|
||||||
$(document).on("issuable:change", this.refresh);
|
$(document).on("issuable:change", this.refresh);
|
||||||
|
// when a key is clicked on the notes
|
||||||
return $(document).on("keydown", ".js-note-text", this.keydownNoteText);
|
return $(document).on("keydown", ".js-note-text", this.keydownNoteText);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -112,6 +117,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$textarea = $(e.target);
|
$textarea = $(e.target);
|
||||||
|
// Edit previous note when UP arrow is hit
|
||||||
switch (e.which) {
|
switch (e.which) {
|
||||||
case 38:
|
case 38:
|
||||||
if ($textarea.val() !== '') {
|
if ($textarea.val() !== '') {
|
||||||
|
@ -123,6 +129,7 @@
|
||||||
return myLastNoteEditBtn.trigger('click', [true, myLastNote]);
|
return myLastNoteEditBtn.trigger('click', [true, myLastNote]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
// Cancel creating diff note or editing any note when ESCAPE is hit
|
||||||
case 27:
|
case 27:
|
||||||
discussionNoteForm = $textarea.closest('.js-discussion-note-form');
|
discussionNoteForm = $textarea.closest('.js-discussion-note-form');
|
||||||
if (discussionNoteForm.length) {
|
if (discussionNoteForm.length) {
|
||||||
|
@ -247,10 +254,13 @@
|
||||||
votesBlock = $('.js-awards-block').eq(0);
|
votesBlock = $('.js-awards-block').eq(0);
|
||||||
gl.awardsHandler.addAwardToEmojiBar(votesBlock, note.name);
|
gl.awardsHandler.addAwardToEmojiBar(votesBlock, note.name);
|
||||||
return gl.awardsHandler.scrollToAwards();
|
return gl.awardsHandler.scrollToAwards();
|
||||||
|
// render note if it not present in loaded list
|
||||||
|
// or skip if rendered
|
||||||
} else if (this.isNewNote(note)) {
|
} else if (this.isNewNote(note)) {
|
||||||
this.note_ids.push(note.id);
|
this.note_ids.push(note.id);
|
||||||
$notesList = $('ul.main-notes-list');
|
$notesList = $('ul.main-notes-list');
|
||||||
$notesList.append(note.html).syntaxHighlight();
|
$notesList.append(note.html).syntaxHighlight();
|
||||||
|
// Update datetime format on the recent note
|
||||||
gl.utils.localTimeAgo($notesList.find("#note_" + note.id + " .js-timeago"), false);
|
gl.utils.localTimeAgo($notesList.find("#note_" + note.id + " .js-timeago"), false);
|
||||||
this.initTaskList();
|
this.initTaskList();
|
||||||
this.refresh();
|
this.refresh();
|
||||||
|
@ -291,19 +301,26 @@
|
||||||
row = form.closest("tr");
|
row = form.closest("tr");
|
||||||
note_html = $(note.html);
|
note_html = $(note.html);
|
||||||
note_html.syntaxHighlight();
|
note_html.syntaxHighlight();
|
||||||
|
// is this the first note of discussion?
|
||||||
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
|
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
|
||||||
if ((note.original_discussion_id != null) && discussionContainer.length === 0) {
|
if ((note.original_discussion_id != null) && discussionContainer.length === 0) {
|
||||||
discussionContainer = $(".notes[data-discussion-id='" + note.original_discussion_id + "']");
|
discussionContainer = $(".notes[data-discussion-id='" + note.original_discussion_id + "']");
|
||||||
}
|
}
|
||||||
if (discussionContainer.length === 0) {
|
if (discussionContainer.length === 0) {
|
||||||
|
// insert the note and the reply button after the temp row
|
||||||
row.after(note.diff_discussion_html);
|
row.after(note.diff_discussion_html);
|
||||||
|
// remove the note (will be added again below)
|
||||||
row.next().find(".note").remove();
|
row.next().find(".note").remove();
|
||||||
|
// Before that, the container didn't exist
|
||||||
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
|
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
|
||||||
|
// Add note to 'Changes' page discussions
|
||||||
discussionContainer.append(note_html);
|
discussionContainer.append(note_html);
|
||||||
|
// Init discussion on 'Discussion' page if it is merge request page
|
||||||
if ($('body').attr('data-page').indexOf('projects:merge_request') === 0) {
|
if ($('body').attr('data-page').indexOf('projects:merge_request') === 0) {
|
||||||
$('ul.main-notes-list').append(note.discussion_html).syntaxHighlight();
|
$('ul.main-notes-list').append(note.discussion_html).syntaxHighlight();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// append new note to all matching discussions
|
||||||
discussionContainer.append(note_html);
|
discussionContainer.append(note_html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,11 +344,18 @@
|
||||||
Notes.prototype.resetMainTargetForm = function(e) {
|
Notes.prototype.resetMainTargetForm = function(e) {
|
||||||
var form;
|
var form;
|
||||||
form = $(".js-main-target-form");
|
form = $(".js-main-target-form");
|
||||||
|
// remove validation errors
|
||||||
form.find(".js-errors").remove();
|
form.find(".js-errors").remove();
|
||||||
|
// reset text and preview
|
||||||
form.find(".js-md-write-button").click();
|
form.find(".js-md-write-button").click();
|
||||||
form.find(".js-note-text").val("").trigger("input");
|
form.find(".js-note-text").val("").trigger("input");
|
||||||
form.find(".js-note-text").data("autosave").reset();
|
form.find(".js-note-text").data("autosave").reset();
|
||||||
return this.updateTargetButtons(e);
|
|
||||||
|
var event = document.createEvent('Event');
|
||||||
|
event.initEvent('autosize:update', true, false);
|
||||||
|
form.find('.js-autosize')[0].dispatchEvent(event);
|
||||||
|
|
||||||
|
this.updateTargetButtons(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
Notes.prototype.reenableTargetFormSubmitButton = function() {
|
Notes.prototype.reenableTargetFormSubmitButton = function() {
|
||||||
|
@ -349,9 +373,13 @@
|
||||||
|
|
||||||
Notes.prototype.setupMainTargetNoteForm = function() {
|
Notes.prototype.setupMainTargetNoteForm = function() {
|
||||||
var form;
|
var form;
|
||||||
|
// find the form
|
||||||
form = $(".js-new-note-form");
|
form = $(".js-new-note-form");
|
||||||
|
// Set a global clone of the form for later cloning
|
||||||
this.formClone = form.clone();
|
this.formClone = form.clone();
|
||||||
|
// show the form
|
||||||
this.setupNoteForm(form);
|
this.setupNoteForm(form);
|
||||||
|
// fix classes
|
||||||
form.removeClass("js-new-note-form");
|
form.removeClass("js-new-note-form");
|
||||||
form.addClass("js-main-target-form");
|
form.addClass("js-main-target-form");
|
||||||
form.find("#note_line_code").remove();
|
form.find("#note_line_code").remove();
|
||||||
|
@ -416,6 +444,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderDiscussionNote(note);
|
this.renderDiscussionNote(note);
|
||||||
|
// cleanup after successfully creating a diff/discussion note
|
||||||
this.removeDiscussionNoteForm($form);
|
this.removeDiscussionNoteForm($form);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -428,10 +457,12 @@
|
||||||
|
|
||||||
Notes.prototype.updateNote = function(_xhr, note, _status) {
|
Notes.prototype.updateNote = function(_xhr, note, _status) {
|
||||||
var $html, $note_li;
|
var $html, $note_li;
|
||||||
|
// Convert returned HTML to a jQuery object so we can modify it further
|
||||||
$html = $(note.html);
|
$html = $(note.html);
|
||||||
gl.utils.localTimeAgo($('.js-timeago', $html));
|
gl.utils.localTimeAgo($('.js-timeago', $html));
|
||||||
$html.syntaxHighlight();
|
$html.syntaxHighlight();
|
||||||
$html.find('.js-task-list-container').taskList('enable');
|
$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-row-' + note.id);
|
$note_li = $('.note-row-' + note.id);
|
||||||
|
|
||||||
$note_li.replaceWith($html);
|
$note_li.replaceWith($html);
|
||||||
|
@ -456,15 +487,20 @@
|
||||||
note.addClass("is-editting");
|
note.addClass("is-editting");
|
||||||
form = note.find(".note-edit-form");
|
form = note.find(".note-edit-form");
|
||||||
form.addClass('current-note-edit-form');
|
form.addClass('current-note-edit-form');
|
||||||
|
// Show the attachment delete link
|
||||||
note.find(".js-note-attachment-delete").show();
|
note.find(".js-note-attachment-delete").show();
|
||||||
done = function($noteText) {
|
done = function($noteText) {
|
||||||
var noteTextVal;
|
var noteTextVal;
|
||||||
|
// Neat little trick to put the cursor at the end
|
||||||
noteTextVal = $noteText.val();
|
noteTextVal = $noteText.val();
|
||||||
|
// Store the original note text in a data attribute to retrieve if a user cancels edit.
|
||||||
form.find('form.edit-note').data('original-note', noteTextVal);
|
form.find('form.edit-note').data('original-note', noteTextVal);
|
||||||
return $noteText.val('').val(noteTextVal);
|
return $noteText.val('').val(noteTextVal);
|
||||||
};
|
};
|
||||||
new GLForm(form);
|
new GLForm(form);
|
||||||
if ((scrollTo != null) && (myLastNote != null)) {
|
if ((scrollTo != null) && (myLastNote != null)) {
|
||||||
|
// scroll to the bottom
|
||||||
|
// so the open of the last element doesn't make a jump
|
||||||
$('html, body').scrollTop($(document).height());
|
$('html, body').scrollTop($(document).height());
|
||||||
return $('html, body').animate({
|
return $('html, body').animate({
|
||||||
scrollTop: myLastNote.offset().top - 150
|
scrollTop: myLastNote.offset().top - 150
|
||||||
|
@ -500,6 +536,7 @@
|
||||||
form = note.find(".current-note-edit-form");
|
form = note.find(".current-note-edit-form");
|
||||||
note.removeClass("is-editting");
|
note.removeClass("is-editting");
|
||||||
form.removeClass("current-note-edit-form");
|
form.removeClass("current-note-edit-form");
|
||||||
|
// Replace markdown textarea text with original note text.
|
||||||
return form.find(".js-note-text").val(form.find('form.edit-note').data('original-note'));
|
return form.find(".js-note-text").val(form.find('form.edit-note').data('original-note'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -515,6 +552,9 @@
|
||||||
var noteId;
|
var noteId;
|
||||||
noteId = $(e.currentTarget).closest(".note").attr("id");
|
noteId = $(e.currentTarget).closest(".note").attr("id");
|
||||||
$(".note[id='" + noteId + "']").each((function(_this) {
|
$(".note[id='" + noteId + "']").each((function(_this) {
|
||||||
|
// A same note appears in the "Discussion" and in the "Changes" tab, we have
|
||||||
|
// to remove all. Using $(".note[id='noteId']") ensure we get all the notes,
|
||||||
|
// where $("#noteId") would return only one.
|
||||||
return function(i, el) {
|
return function(i, el) {
|
||||||
var note, notes;
|
var note, notes;
|
||||||
note = $(el);
|
note = $(el);
|
||||||
|
@ -528,13 +568,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if this is the last note for this line
|
||||||
if (notes.find(".note").length === 1) {
|
if (notes.find(".note").length === 1) {
|
||||||
|
// "Discussions" tab
|
||||||
notes.closest(".timeline-entry").remove();
|
notes.closest(".timeline-entry").remove();
|
||||||
|
// "Changes" tab / commit view
|
||||||
notes.closest("tr").remove();
|
notes.closest("tr").remove();
|
||||||
}
|
}
|
||||||
return note.remove();
|
return note.remove();
|
||||||
};
|
};
|
||||||
})(this));
|
})(this));
|
||||||
|
// Decrement the "Discussions" counter only once
|
||||||
return this.updateNotesCount(-1);
|
return this.updateNotesCount(-1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -566,10 +610,12 @@
|
||||||
var form, replyLink;
|
var form, replyLink;
|
||||||
form = this.formClone.clone();
|
form = this.formClone.clone();
|
||||||
replyLink = $(e.target).closest(".js-discussion-reply-button");
|
replyLink = $(e.target).closest(".js-discussion-reply-button");
|
||||||
|
// insert the form after the button
|
||||||
replyLink
|
replyLink
|
||||||
.closest('.discussion-reply-holder')
|
.closest('.discussion-reply-holder')
|
||||||
.hide()
|
.hide()
|
||||||
.after(form);
|
.after(form);
|
||||||
|
// show the form
|
||||||
return this.setupDiscussionNoteForm(replyLink, form);
|
return this.setupDiscussionNoteForm(replyLink, form);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -584,6 +630,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Notes.prototype.setupDiscussionNoteForm = function(dataHolder, form) {
|
Notes.prototype.setupDiscussionNoteForm = function(dataHolder, form) {
|
||||||
|
// setup note target
|
||||||
form.attr('id', "new-discussion-note-form-" + (dataHolder.data("discussionId")));
|
form.attr('id', "new-discussion-note-form-" + (dataHolder.data("discussionId")));
|
||||||
form.attr("data-line-code", dataHolder.data("lineCode"));
|
form.attr("data-line-code", dataHolder.data("lineCode"));
|
||||||
form.find("#note_type").val(dataHolder.data("noteType"));
|
form.find("#note_type").val(dataHolder.data("noteType"));
|
||||||
|
@ -631,6 +678,7 @@
|
||||||
addForm = false;
|
addForm = false;
|
||||||
notesContentSelector = ".notes_content";
|
notesContentSelector = ".notes_content";
|
||||||
rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\" colspan=\"2\"></td><td class=\"notes_content\"><div class=\"content\"></div></td></tr>";
|
rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\" colspan=\"2\"></td><td class=\"notes_content\"><div class=\"content\"></div></td></tr>";
|
||||||
|
// In parallel view, look inside the correct left/right pane
|
||||||
if (this.isParallelView()) {
|
if (this.isParallelView()) {
|
||||||
lineType = $link.data("lineType");
|
lineType = $link.data("lineType");
|
||||||
notesContentSelector += "." + lineType;
|
notesContentSelector += "." + lineType;
|
||||||
|
@ -647,6 +695,7 @@
|
||||||
e.target = replyButton[0];
|
e.target = replyButton[0];
|
||||||
$.proxy(this.replyToDiscussionNote, replyButton[0], e).call();
|
$.proxy(this.replyToDiscussionNote, replyButton[0], e).call();
|
||||||
} else {
|
} else {
|
||||||
|
// In parallel view, the form may not be present in one of the panes
|
||||||
noteForm = notesContent.find(".js-discussion-note-form");
|
noteForm = notesContent.find(".js-discussion-note-form");
|
||||||
if (noteForm.length === 0) {
|
if (noteForm.length === 0) {
|
||||||
addForm = true;
|
addForm = true;
|
||||||
|
@ -654,6 +703,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// add a notes row and insert the form
|
||||||
row.after(rowCssToAdd);
|
row.after(rowCssToAdd);
|
||||||
nextRow = row.next();
|
nextRow = row.next();
|
||||||
notesContent = nextRow.find(notesContentSelector);
|
notesContent = nextRow.find(notesContentSelector);
|
||||||
|
@ -662,6 +712,7 @@
|
||||||
if (addForm) {
|
if (addForm) {
|
||||||
newForm = this.formClone.clone();
|
newForm = this.formClone.clone();
|
||||||
newForm.appendTo(notesContent);
|
newForm.appendTo(notesContent);
|
||||||
|
// show the form
|
||||||
return this.setupDiscussionNoteForm($link, newForm);
|
return this.setupDiscussionNoteForm($link, newForm);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -680,12 +731,15 @@
|
||||||
glForm = form.data('gl-form');
|
glForm = form.data('gl-form');
|
||||||
glForm.destroy();
|
glForm.destroy();
|
||||||
form.find(".js-note-text").data("autosave").reset();
|
form.find(".js-note-text").data("autosave").reset();
|
||||||
|
// show the reply button (will only work for replies)
|
||||||
form
|
form
|
||||||
.prev('.discussion-reply-holder')
|
.prev('.discussion-reply-holder')
|
||||||
.show();
|
.show();
|
||||||
if (row.is(".js-temp-notes-holder")) {
|
if (row.is(".js-temp-notes-holder")) {
|
||||||
|
// remove temporary row for diff lines
|
||||||
return row.remove();
|
return row.remove();
|
||||||
} else {
|
} else {
|
||||||
|
// only remove the form
|
||||||
return form.remove();
|
return form.remove();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -707,6 +761,7 @@
|
||||||
Notes.prototype.updateFormAttachment = function() {
|
Notes.prototype.updateFormAttachment = function() {
|
||||||
var filename, form;
|
var filename, form;
|
||||||
form = $(this).closest("form");
|
form = $(this).closest("form");
|
||||||
|
// get only the basename
|
||||||
filename = $(this).val().replace(/^.*[\\\/]/, "");
|
filename = $(this).val().replace(/^.*[\\\/]/, "");
|
||||||
return form.find(".js-attachment-filename").text(filename);
|
return form.find(".js-attachment-filename").text(filename);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
|
// MarkdownPreview
|
||||||
|
//
|
||||||
|
// Handles toggling the "Write" and "Preview" tab clicks, rendering the preview,
|
||||||
|
// and showing a warning when more than `x` users are referenced.
|
||||||
|
//
|
||||||
(function() {
|
(function() {
|
||||||
var lastTextareaPreviewed, markdownPreview, previewButtonSelector, writeButtonSelector;
|
var lastTextareaPreviewed, markdownPreview, previewButtonSelector, writeButtonSelector;
|
||||||
|
|
||||||
this.MarkdownPreview = (function() {
|
this.MarkdownPreview = (function() {
|
||||||
function MarkdownPreview() {}
|
function MarkdownPreview() {}
|
||||||
|
|
||||||
|
// Minimum number of users referenced before triggering a warning
|
||||||
MarkdownPreview.prototype.referenceThreshold = 10;
|
MarkdownPreview.prototype.referenceThreshold = 10;
|
||||||
|
|
||||||
MarkdownPreview.prototype.ajaxCache = {};
|
MarkdownPreview.prototype.ajaxCache = {};
|
||||||
|
@ -101,8 +107,10 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastTextareaPreviewed = $form.find('textarea.markdown-area');
|
lastTextareaPreviewed = $form.find('textarea.markdown-area');
|
||||||
|
// toggle tabs
|
||||||
$form.find(writeButtonSelector).parent().removeClass('active');
|
$form.find(writeButtonSelector).parent().removeClass('active');
|
||||||
$form.find(previewButtonSelector).parent().addClass('active');
|
$form.find(previewButtonSelector).parent().addClass('active');
|
||||||
|
// toggle content
|
||||||
$form.find('.md-write-holder').hide();
|
$form.find('.md-write-holder').hide();
|
||||||
$form.find('.md-preview-holder').show();
|
$form.find('.md-preview-holder').show();
|
||||||
return markdownPreview.showPreview($form);
|
return markdownPreview.showPreview($form);
|
||||||
|
@ -113,8 +121,10 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastTextareaPreviewed = null;
|
lastTextareaPreviewed = null;
|
||||||
|
// toggle tabs
|
||||||
$form.find(writeButtonSelector).parent().addClass('active');
|
$form.find(writeButtonSelector).parent().addClass('active');
|
||||||
$form.find(previewButtonSelector).parent().removeClass('active');
|
$form.find(previewButtonSelector).parent().removeClass('active');
|
||||||
|
// toggle content
|
||||||
$form.find('.md-write-holder').show();
|
$form.find('.md-write-holder').show();
|
||||||
$form.find('textarea.markdown-area').focus();
|
$form.find('textarea.markdown-area').focus();
|
||||||
return $form.find('.md-preview-holder').hide();
|
return $form.find('.md-preview-holder').hide();
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
GitLabCrop = (function() {
|
GitLabCrop = (function() {
|
||||||
var FILENAMEREGEX;
|
var FILENAMEREGEX;
|
||||||
|
|
||||||
|
// Matches everything but the file name
|
||||||
FILENAMEREGEX = /^.*[\\\/]/;
|
FILENAMEREGEX = /^.*[\\\/]/;
|
||||||
|
|
||||||
function GitLabCrop(input, opts) {
|
function GitLabCrop(input, opts) {
|
||||||
|
@ -17,11 +18,18 @@
|
||||||
this.onModalShow = bind(this.onModalShow, this);
|
this.onModalShow = bind(this.onModalShow, this);
|
||||||
this.onPickImageClick = bind(this.onPickImageClick, this);
|
this.onPickImageClick = bind(this.onPickImageClick, this);
|
||||||
this.fileInput = $(input);
|
this.fileInput = $(input);
|
||||||
|
// We should rename to avoid spec to fail
|
||||||
|
// Form will submit the proper input filed with a file using FormData
|
||||||
this.fileInput.attr('name', (this.fileInput.attr('name')) + "-trigger").attr('id', (this.fileInput.attr('id')) + "-trigger");
|
this.fileInput.attr('name', (this.fileInput.attr('name')) + "-trigger").attr('id', (this.fileInput.attr('id')) + "-trigger");
|
||||||
|
// Set defaults
|
||||||
this.exportWidth = (ref = opts.exportWidth) != null ? ref : 200, this.exportHeight = (ref1 = opts.exportHeight) != null ? ref1 : 200, this.cropBoxWidth = (ref2 = opts.cropBoxWidth) != null ? ref2 : 200, this.cropBoxHeight = (ref3 = opts.cropBoxHeight) != null ? ref3 : 200, this.form = (ref4 = opts.form) != null ? ref4 : this.fileInput.parents('form'), this.filename = opts.filename, this.previewImage = opts.previewImage, this.modalCrop = opts.modalCrop, this.pickImageEl = opts.pickImageEl, this.uploadImageBtn = opts.uploadImageBtn, this.modalCropImg = opts.modalCropImg;
|
this.exportWidth = (ref = opts.exportWidth) != null ? ref : 200, this.exportHeight = (ref1 = opts.exportHeight) != null ? ref1 : 200, this.cropBoxWidth = (ref2 = opts.cropBoxWidth) != null ? ref2 : 200, this.cropBoxHeight = (ref3 = opts.cropBoxHeight) != null ? ref3 : 200, this.form = (ref4 = opts.form) != null ? ref4 : this.fileInput.parents('form'), this.filename = opts.filename, this.previewImage = opts.previewImage, this.modalCrop = opts.modalCrop, this.pickImageEl = opts.pickImageEl, this.uploadImageBtn = opts.uploadImageBtn, this.modalCropImg = opts.modalCropImg;
|
||||||
|
// Required params
|
||||||
|
// Ensure needed elements are jquery objects
|
||||||
|
// If selector is provided we will convert them to a jQuery Object
|
||||||
this.filename = this.getElement(this.filename);
|
this.filename = this.getElement(this.filename);
|
||||||
this.previewImage = this.getElement(this.previewImage);
|
this.previewImage = this.getElement(this.previewImage);
|
||||||
this.pickImageEl = this.getElement(this.pickImageEl);
|
this.pickImageEl = this.getElement(this.pickImageEl);
|
||||||
|
// Modal elements usually are outside the @form element
|
||||||
this.modalCrop = _.isString(this.modalCrop) ? $(this.modalCrop) : this.modalCrop;
|
this.modalCrop = _.isString(this.modalCrop) ? $(this.modalCrop) : this.modalCrop;
|
||||||
this.uploadImageBtn = _.isString(this.uploadImageBtn) ? $(this.uploadImageBtn) : this.uploadImageBtn;
|
this.uploadImageBtn = _.isString(this.uploadImageBtn) ? $(this.uploadImageBtn) : this.uploadImageBtn;
|
||||||
this.modalCropImg = _.isString(this.modalCropImg) ? $(this.modalCropImg) : this.modalCropImg;
|
this.modalCropImg = _.isString(this.modalCropImg) ? $(this.modalCropImg) : this.modalCropImg;
|
||||||
|
@ -93,8 +101,8 @@
|
||||||
return this.modalCropImg.attr('src', '').cropper('destroy');
|
return this.modalCropImg.attr('src', '').cropper('destroy');
|
||||||
};
|
};
|
||||||
|
|
||||||
GitLabCrop.prototype.onUploadImageBtnClick = function(e) {
|
GitLabCrop.prototype.onUploadImageBtnClick = function(e) { // Remove attached image
|
||||||
e.preventDefault();
|
e.preventDefault(); // Destroy cropper instance
|
||||||
this.setBlob();
|
this.setBlob();
|
||||||
this.setPreview();
|
this.setPreview();
|
||||||
this.modalCrop.modal('hide');
|
this.modalCrop.modal('hide');
|
||||||
|
|
|
@ -11,9 +11,11 @@
|
||||||
this.form = (ref = opts.form) != null ? ref : $('.edit-user');
|
this.form = (ref = opts.form) != null ? ref : $('.edit-user');
|
||||||
$('.js-preferences-form').on('change.preference', 'input[type=radio]', function() {
|
$('.js-preferences-form').on('change.preference', 'input[type=radio]', function() {
|
||||||
return $(this).parents('form').submit();
|
return $(this).parents('form').submit();
|
||||||
|
// Automatically submit the Preferences form when any of its radio buttons change
|
||||||
});
|
});
|
||||||
$('#user_notification_email').on('change', function() {
|
$('#user_notification_email').on('change', function() {
|
||||||
return $(this).parents('form').submit();
|
return $(this).parents('form').submit();
|
||||||
|
// Automatically submit email form when it changes
|
||||||
});
|
});
|
||||||
$('.update-username').on('ajax:before', function() {
|
$('.update-username').on('ajax:before', function() {
|
||||||
$('.loading-username').show();
|
$('.loading-username').show();
|
||||||
|
@ -76,6 +78,7 @@
|
||||||
},
|
},
|
||||||
complete: function() {
|
complete: function() {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
|
// Enable submit button after requests ends
|
||||||
return self.form.find(':input[disabled]').enable();
|
return self.form.find(':input[disabled]').enable();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -93,6 +96,7 @@
|
||||||
if (comment && comment.length > 1 && $title.val() === '') {
|
if (comment && comment.length > 1 && $title.val() === '') {
|
||||||
return $title.val(comment[1]).change();
|
return $title.val(comment[1]).change();
|
||||||
}
|
}
|
||||||
|
// Extract the SSH Key title from its comment
|
||||||
});
|
});
|
||||||
if (gl.utils.getPagePath() === 'profiles') {
|
if (gl.utils.getPagePath() === 'profiles') {
|
||||||
return new Profile();
|
return new Profile();
|
||||||
|
|
|
@ -3,5 +3,4 @@
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -11,25 +11,27 @@
|
||||||
url = $("#project_clone").val();
|
url = $("#project_clone").val();
|
||||||
$('#project_clone').val(url);
|
$('#project_clone').val(url);
|
||||||
return $('.clone').text(url);
|
return $('.clone').text(url);
|
||||||
|
// Git protocol switcher
|
||||||
|
// Remove the active class for all buttons (ssh, http, kerberos if shown)
|
||||||
|
// Add the active class for the clicked button
|
||||||
|
// Update the input field
|
||||||
|
// Update the command line instructions
|
||||||
});
|
});
|
||||||
|
// Ref switcher
|
||||||
this.initRefSwitcher();
|
this.initRefSwitcher();
|
||||||
$('.project-refs-select').on('change', function() {
|
$('.project-refs-select').on('change', function() {
|
||||||
return $(this).parents('form').submit();
|
return $(this).parents('form').submit();
|
||||||
});
|
});
|
||||||
$('.hide-no-ssh-message').on('click', function(e) {
|
$('.hide-no-ssh-message').on('click', function(e) {
|
||||||
var path;
|
|
||||||
path = '/';
|
|
||||||
$.cookie('hide_no_ssh_message', 'false', {
|
$.cookie('hide_no_ssh_message', 'false', {
|
||||||
path: path
|
path: gon.relative_url_root || '/'
|
||||||
});
|
});
|
||||||
$(this).parents('.no-ssh-key-message').remove();
|
$(this).parents('.no-ssh-key-message').remove();
|
||||||
return e.preventDefault();
|
return e.preventDefault();
|
||||||
});
|
});
|
||||||
$('.hide-no-password-message').on('click', function(e) {
|
$('.hide-no-password-message').on('click', function(e) {
|
||||||
var path;
|
|
||||||
path = '/';
|
|
||||||
$.cookie('hide_no_password_message', 'false', {
|
$.cookie('hide_no_password_message', 'false', {
|
||||||
path: path
|
path: gon.relative_url_root || '/'
|
||||||
});
|
});
|
||||||
$(this).parents('.no-password-message').remove();
|
$(this).parents('.no-password-message').remove();
|
||||||
return e.preventDefault();
|
return e.preventDefault();
|
||||||
|
@ -65,7 +67,8 @@
|
||||||
url: $dropdown.data('refs-url'),
|
url: $dropdown.data('refs-url'),
|
||||||
data: {
|
data: {
|
||||||
ref: $dropdown.data('ref')
|
ref: $dropdown.data('ref')
|
||||||
}
|
},
|
||||||
|
dataType: "json"
|
||||||
}).done(function(refs) {
|
}).done(function(refs) {
|
||||||
return callback(refs);
|
return callback(refs);
|
||||||
});
|
});
|
||||||
|
@ -73,7 +76,7 @@
|
||||||
selectable: true,
|
selectable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
filterByText: true,
|
filterByText: true,
|
||||||
fieldName: 'ref',
|
fieldName: $dropdown.data('field-name'),
|
||||||
renderRow: function(ref) {
|
renderRow: function(ref) {
|
||||||
var link;
|
var link;
|
||||||
if (ref.header != null) {
|
if (ref.header != null) {
|
||||||
|
|
|
@ -13,8 +13,11 @@
|
||||||
this.selectRowUp = bind(this.selectRowUp, this);
|
this.selectRowUp = bind(this.selectRowUp, this);
|
||||||
this.filePaths = {};
|
this.filePaths = {};
|
||||||
this.inputElement = this.element.find(".file-finder-input");
|
this.inputElement = this.element.find(".file-finder-input");
|
||||||
|
// init event
|
||||||
this.initEvent();
|
this.initEvent();
|
||||||
|
// focus text input box
|
||||||
this.inputElement.focus();
|
this.inputElement.focus();
|
||||||
|
// load file list
|
||||||
this.load(this.options.url);
|
this.load(this.options.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +45,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// init event
|
||||||
};
|
};
|
||||||
|
|
||||||
ProjectFindFile.prototype.findFile = function() {
|
ProjectFindFile.prototype.findFile = function() {
|
||||||
|
@ -49,8 +53,10 @@
|
||||||
searchText = this.inputElement.val();
|
searchText = this.inputElement.val();
|
||||||
result = searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths;
|
result = searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths;
|
||||||
return this.renderList(result, searchText);
|
return this.renderList(result, searchText);
|
||||||
|
// find file
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// files pathes load
|
||||||
ProjectFindFile.prototype.load = function(url) {
|
ProjectFindFile.prototype.load = function(url) {
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
|
@ -67,6 +73,7 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// render result
|
||||||
ProjectFindFile.prototype.renderList = function(filePaths, searchText) {
|
ProjectFindFile.prototype.renderList = function(filePaths, searchText) {
|
||||||
var blobItemUrl, filePath, html, i, j, len, matches, results;
|
var blobItemUrl, filePath, html, i, j, len, matches, results;
|
||||||
this.element.find(".tree-table > tbody").empty();
|
this.element.find(".tree-table > tbody").empty();
|
||||||
|
@ -86,6 +93,7 @@
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> )
|
||||||
highlighter = function(element, text, matches) {
|
highlighter = function(element, text, matches) {
|
||||||
var highlightText, j, lastIndex, len, matchIndex, matchedChars, unmatched;
|
var highlightText, j, lastIndex, len, matchIndex, matchedChars, unmatched;
|
||||||
lastIndex = 0;
|
lastIndex = 0;
|
||||||
|
@ -110,6 +118,7 @@
|
||||||
return element.append(document.createTextNode(text.substring(lastIndex)));
|
return element.append(document.createTextNode(text.substring(lastIndex)));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// make tbody row html
|
||||||
ProjectFindFile.prototype.makeHtml = function(filePath, matches, blobItemUrl) {
|
ProjectFindFile.prototype.makeHtml = function(filePath, matches, blobItemUrl) {
|
||||||
var $tr;
|
var $tr;
|
||||||
$tr = $("<tr class='tree-item'><td class='tree-item-file-name'><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'><a></a></span></td></tr>");
|
$tr = $("<tr class='tree-item'><td class='tree-item-file-name'><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'><a></a></span></td></tr>");
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
this.ProjectNew = (function() {
|
this.ProjectNew = (function() {
|
||||||
function ProjectNew() {
|
function ProjectNew() {
|
||||||
this.toggleSettings = bind(this.toggleSettings, this);
|
this.toggleSettings = bind(this.toggleSettings, this);
|
||||||
|
this.$selects = $('.features select');
|
||||||
|
|
||||||
$('.project-edit-container').on('ajax:before', (function(_this) {
|
$('.project-edit-container').on('ajax:before', (function(_this) {
|
||||||
return function() {
|
return function() {
|
||||||
$('.project-edit-container').hide();
|
$('.project-edit-container').hide();
|
||||||
|
@ -15,18 +17,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectNew.prototype.toggleSettings = function() {
|
ProjectNew.prototype.toggleSettings = function() {
|
||||||
this._showOrHide('#project_builds_enabled', '.builds-feature');
|
var self = this;
|
||||||
return this._showOrHide('#project_merge_requests_enabled', '.merge-requests-feature');
|
|
||||||
|
this.$selects.each(function () {
|
||||||
|
var $select = $(this),
|
||||||
|
className = $select.data('field').replace(/_/g, '-')
|
||||||
|
.replace('access-level', 'feature');
|
||||||
|
self._showOrHide($select, '.' + className);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
ProjectNew.prototype.toggleSettingsOnclick = function() {
|
ProjectNew.prototype.toggleSettingsOnclick = function() {
|
||||||
return $('#project_builds_enabled, #project_merge_requests_enabled').on('click', this.toggleSettings);
|
this.$selects.on('change', this.toggleSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
ProjectNew.prototype._showOrHide = function(checkElement, container) {
|
ProjectNew.prototype._showOrHide = function(checkElement, container) {
|
||||||
var $container;
|
var $container = $(container);
|
||||||
$container = $(container);
|
|
||||||
if ($(checkElement).prop('checked')) {
|
if ($(checkElement).val() !== '0') {
|
||||||
return $container.show();
|
return $container.show();
|
||||||
} else {
|
} else {
|
||||||
return $container.hide();
|
return $container.hide();
|
||||||
|
|
|
@ -7,3 +7,5 @@
|
||||||
})();
|
})();
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
||||||
|
// I kept class for future
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
$('.projects-list-holder').replaceWith(data.html);
|
$('.projects-list-holder').replaceWith(data.html);
|
||||||
return history.replaceState({
|
return history.replaceState({
|
||||||
page: project_filter_url
|
page: project_filter_url
|
||||||
|
// Change url so if user reload a page - search results are saved
|
||||||
}, document.title, project_filter_url);
|
}, document.title, project_filter_url);
|
||||||
},
|
},
|
||||||
dataType: "json"
|
dataType: "json"
|
||||||
|
|
|
@ -45,6 +45,7 @@ class ProtectedBranchDropdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickCreateWildcard() {
|
onClickCreateWildcard() {
|
||||||
|
// Refresh the dropdown's data, which ends up calling `getProtectedBranches`
|
||||||
this.$dropdown.data('glDropdown').remote.execute();
|
this.$dropdown.data('glDropdown').remote.execute();
|
||||||
this.$dropdown.data('glDropdown').selectRowAtIndex(0);
|
this.$dropdown.data('glDropdown').selectRowAtIndex(0);
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue