Commit cae864a1 authored by James Lopez's avatar James Lopez

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into fix/safe-import-url

parents 4196ee06 2bcbc7c6
{
"always-semicolon": true,
"color-case": "lower",
"block-indent": " ",
"color-shorthand": true,
"element-case": "lower",
"space-before-colon": "",
"space-after-colon": " ",
"space-before-combinator": " ",
"space-after-combinator": " ",
"space-between-declarations": "\n",
"space-before-opening-brace": " ",
"space-after-opening-brace": "\n",
"space-before-closing-brace": "\n",
"unitless-zero": true
}
......@@ -15,6 +15,7 @@
.sass-cache/
.secret
.vagrant
.byebug_history
Vagrantfile
backups/*
config/aws.yml
......
......@@ -12,16 +12,18 @@ cache:
variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
# retry tests only in CI environment
RSPEC_RETRY_RETRY_COUNT: "3"
before_script:
- source ./scripts/prepare_build.sh
- ruby -v
- which ruby
- gem install bundler --no-ri --no-rdoc
- retry gem install bundler --no-ri --no-rdoc
- cp config/gitlab.yml.example config/gitlab.yml
- touch log/application.log
- touch log/test.log
- bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"
- retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"
- RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load db:migrate
stages:
......@@ -69,15 +71,6 @@ spec:services:
- ruby
- mysql
spec:benchmark:
stage: test
script:
- RAILS_ENV=test bundle exec rake spec:benchmark
tags:
- ruby
- mysql
allow_failure: true
spec:other:
stage: test
script:
......@@ -129,6 +122,14 @@ rubocop:
- ruby
- mysql
scss-lint:
stage: test
script:
- bundle exec rake scss_lint
tags:
- ruby
allow_failure: true
brakeman:
stage: test
script:
......@@ -155,13 +156,14 @@ flay:
bundler:audit:
stage: test
only:
- master
script:
- "bundle exec bundle-audit update"
- "bundle exec bundle-audit check"
- "bundle exec bundle-audit check --ignore OSVDB-115941"
tags:
- ruby
- mysql
allow_failure: true
# Ruby 2.2 jobs
......@@ -169,7 +171,7 @@ spec:feature:ruby22:
stage: test
image: ruby:2.2
only:
- master
- master
script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature
......@@ -241,22 +243,6 @@ spec:services:ruby22:
- ruby
- mysql
spec:benchmark:ruby22:
stage: test
image: ruby:2.2
only:
- master
script:
- RAILS_ENV=test bundle exec rake spec:benchmark
cache:
key: "ruby22"
paths:
- vendor
tags:
- ruby
- mysql
allow_failure: true
spec:other:ruby22:
stage: test
image: ruby:2.2
......@@ -330,4 +316,4 @@ notify:slack:
- master@gitlab-org/gitlab-ce
- tags@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- tags@gitlab-org/gitlab-ee
\ No newline at end of file
- tags@gitlab-org/gitlab-ee
This diff is collapsed.
# Linter Documentation:
# https://github.com/brigade/scss-lint/blob/master/lib/scss_lint/linter/README.md
scss_files: 'app/assets/stylesheets/**/*.scss'
exclude:
- 'app/assets/stylesheets/pages/emojis.scss'
linters:
BangFormat:
enabled: false
BorderZero:
enabled: false
ColorKeyword:
enabled: false
ColorVariable:
enabled: false
Comment:
enabled: false
DeclarationOrder:
enabled: false
# `scss-lint:disable` control comments should be preceded by a comment
# explaining why these linters are being disabled for this file.
# See https://github.com/brigade/scss-lint#disabling-linters-via-source for
# more information.
DisableLinterReason:
enabled: true
DuplicateProperty:
enabled: false
EmptyLineBetweenBlocks:
enabled: false
EmptyRule:
enabled: false
FinalNewline:
enabled: false
# HEX colors should use three-character values where possible.
HexLength:
enabled: true
# HEX color values should use lower-case colors to differentiate between
# letters and numbers, e.g. `#E3E3E3` vs. `#e3e3e3`.
HexNotation:
enabled: true
IdSelector:
enabled: false
ImportPath:
enabled: false
ImportantRule:
enabled: false
# Indentation should always be done in increments of 2 spaces.
Indentation:
enabled: true
width: 2
LeadingZero:
enabled: false
MergeableSelector:
enabled: false
NameFormat:
enabled: false
NestingDepth:
enabled: false
PlaceholderInExtend:
enabled: false
PropertySortOrder:
enabled: false
PropertySpelling:
enabled: false
PseudoElement:
enabled: false
QualifyingElement:
enabled: false
SelectorDepth:
enabled: false
# Selectors should always use hyphenated-lowercase, rather than camelCase or
# snake_case.
SelectorFormat:
enabled: true
convention: hyphenated_lowercase
# Prefer the shortest shorthand form possible for properties that support it.
Shorthand:
enabled: true
# Each property should have its own line, except in the special case of
# single line rulesets.
SingleLinePerProperty:
enabled: true
allow_single_line_rule_sets: true
SingleLinePerSelector:
enabled: false
SpaceAfterComma:
enabled: false
# Properties should be formatted with a single space separating the colon
# from the property's value.
SpaceAfterPropertyColon:
enabled: true
# Properties should be formatted with no space between the name and the
# colon.
SpaceAfterPropertyName:
enabled: true
SpaceAroundOperator:
enabled: false
SpaceBeforeBrace:
enabled: false
StringQuotes:
enabled: false
TrailingSemicolon:
enabled: false
TrailingWhitespace:
enabled: false
UnnecessaryMantissa:
enabled: false
UnnecessaryParentReference:
enabled: false
VendorPrefix:
enabled: false
# Omit length units on zero values, e.g. `0px` vs. `0`.
ZeroUnit:
enabled: true
This diff is collapsed.
......@@ -427,6 +427,7 @@ merge request:
1. [Rails](https://github.com/bbatsov/rails-style-guide)
1. [Testing](https://github.com/thoughtbot/guides/tree/master/style/testing)
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript)
1. [SCSS styleguide][scss-styleguide]
1. [Shell commands](doc/development/shell_commands.md) created by GitLab
contributors to enhance security
1. [Database Migrations](doc/development/migration_style_guide.md)
......@@ -494,6 +495,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout
[rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab1.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/gitlab1.atype/
......
......@@ -22,6 +22,7 @@ gem 'devise', '~> 3.5.4'
gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.2.0'
gem 'omniauth', '~> 1.3.1'
gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-cas3', '~> 1.1.2'
......@@ -30,7 +31,7 @@ gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-saml', '~> 1.4.2'
gem 'omniauth-saml', '~> 1.5.0'
gem 'omniauth-shibboleth', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.2.0'
gem 'omniauth_crowd', '~> 2.2.0'
......@@ -50,7 +51,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '~> 9.0'
gem "gitlab_git", '~> 10.0'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
......@@ -58,7 +59,9 @@ gem "gitlab_git", '~> 9.0'
gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap"
# Git Wiki
gem 'gollum-lib', '~> 4.1.0'
# Required manually in config/initializers/gollum.rb to control load order
gem 'gollum-lib', '~> 4.1.0', require: false
gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
# Language detection
gem "github-linguist", "~> 4.7.0", require: "linguist"
......@@ -77,9 +80,6 @@ gem "haml-rails", '~> 0.9.0'
# Files attachments
gem "carrierwave", '~> 0.10.0'
# Image editing
gem "mini_magick", '~> 4.4.0'
# Drag and Drop UI
gem 'dropzonejs-rails', '~> 0.7.1'
......@@ -222,6 +222,8 @@ gem 'net-ssh', '~> 3.0.1'
# Sentry integration
gem 'sentry-raven', '~> 0.15'
gem 'premailer-rails', '~> 1.9.0'
# Metrics
group :metrics do
gem 'allocations', '~> 1.0', require: false, platform: :mri
......@@ -263,7 +265,9 @@ group :development, :test do
gem 'database_cleaner', '~> 1.4.0'
gem 'factory_girl_rails', '~> 4.6.0'
gem 'rspec-rails', '~> 3.3.0'
gem 'rspec-retry'
gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.7.0'
......@@ -271,9 +275,9 @@ group :development, :test do
# Generate Fake data
gem 'ffaker', '~> 2.0.0'
gem 'capybara', '~> 2.4.0'
gem 'capybara', '~> 2.6.2'
gem 'capybara-screenshot', '~> 1.0.0'
gem 'poltergeist', '~> 1.8.1'
gem 'poltergeist', '~> 1.9.0'
gem 'teaspoon', '~> 1.0.0'
gem 'teaspoon-jasmine', '~> 2.2.0'
......@@ -283,7 +287,8 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.0.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.35.0', require: false
gem 'rubocop', '~> 0.38.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false
......
......@@ -61,9 +61,7 @@ GEM
faraday_middleware-multi_json (~> 0.0)
oauth2 (~> 1.0)
asciidoctor (1.5.3)
ast (2.1.0)
astrolabe (1.3.1)
parser (~> 2.2)
ast (2.2.0)
attr_encrypted (1.3.4)
encryptor (>= 1.3.0)
attr_required (1.0.0)
......@@ -108,7 +106,8 @@ GEM
thor (~> 0.18)
byebug (8.2.1)
cal-heatmap-rails (3.5.1)
capybara (2.4.4)
capybara (2.6.2)
addressable
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
......@@ -149,6 +148,8 @@ GEM
crack (0.4.3)
safe_yaml (~> 1.0.0)
creole (0.5.0)
css_parser (1.3.7)
addressable
d3_rails (3.5.11)
railties (>= 3.1.0)
daemons (1.2.3)
......@@ -358,11 +359,11 @@ GEM
posix-spawn (~> 0.3)
gitlab_emoji (0.3.1)
gemojione (~> 2.2, >= 2.2.1)
gitlab_git (9.0.0)
gitlab_git (10.0.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
rugged (~> 0.24.0b13)
rugged (~> 0.24.0)
gitlab_meta (7.0)
gitlab_omniauth-ldap (1.2.1)
net-ldap (~> 0.9)
......@@ -380,6 +381,9 @@ GEM
rouge (~> 1.9)
sanitize (~> 2.1.0)
stringex (~> 2.5.1)
gollum-rugged_adapter (0.4.2)
mime-types (>= 1.15)
rugged (~> 0.24.0, >= 0.21.3)
gon (6.0.1)
actionpack (>= 3.0)
json
......@@ -419,6 +423,7 @@ GEM
haml (~> 4.0.0)
nokogiri (~> 1.6.0)
ruby_parser (~> 3.5)
htmlentities (4.3.4)
http-cookie (1.0.2)
domain_name (~> 0.5)
http_parser.rb (0.5.3)
......@@ -468,7 +473,6 @@ GEM
method_source (0.8.2)
mime-types (1.25.1)
mimemagic (0.3.0)
mini_magick (4.4.0)
mini_portile2 (2.0.0)
minitest (5.7.0)
mousetrap-rails (1.4.6)
......@@ -495,6 +499,8 @@ GEM
omniauth (1.3.1)
hashie (>= 1.2, < 4)
rack (>= 1.0, < 3)
omniauth-auth0 (1.4.1)
omniauth-oauth2 (~> 1.1)
omniauth-azure-oauth2 (0.0.6)
jwt (~> 1.0)
omniauth (~> 1.0)
......@@ -532,8 +538,8 @@ GEM
omniauth-oauth2 (1.3.1)
oauth2 (~> 1.0)
omniauth (~> 1.2)
omniauth-saml (1.4.2)
omniauth (~> 1.1)
omniauth-saml (1.5.0)
omniauth (~> 1.3)
ruby-saml (~> 1.1, >= 1.1.1)
omniauth-shibboleth (1.2.1)
omniauth (>= 1.0.0)
......@@ -549,16 +555,22 @@ GEM
orm_adapter (0.5.0)
paranoia (2.1.4)
activerecord (~> 4.0)
parser (2.2.3.0)
ast (>= 1.1, < 3.0)
parser (2.3.0.6)
ast (~> 2.2)
pg (0.18.4)
poltergeist (1.8.1)
poltergeist (1.9.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
posix-spawn (0.3.11)
powerpack (0.1.1)
premailer (1.8.6)
css_parser (>= 1.3.6)
htmlentities (>= 4.0.0)
premailer-rails (1.9.0)
actionmailer (>= 3, < 5)
premailer (~> 1.7, >= 1.7.9)
pry (0.10.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
......@@ -610,7 +622,7 @@ GEM
activesupport (= 4.2.5.2)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.0.0)
rainbow (2.1.0)
raindrops (0.15.0)
rake (10.5.0)
raphael-rails (2.1.2)
......@@ -679,18 +691,19 @@ GEM
rspec-expectations (~> 3.3.0)
rspec-mocks (~> 3.3.0)
rspec-support (~> 3.3.0)
rspec-retry (0.4.5)
rspec-core
rspec-support (3.3.0)
rubocop (0.35.1)
astrolabe (~> 1.3)
parser (>= 2.2.3.0, < 3.0)
rubocop (0.38.0)
parser (>= 2.3.0.6, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
tins (<= 1.6.0)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-progressbar (1.7.5)
ruby-saml (1.1.1)
ruby-saml (1.1.2)
nokogiri (>= 1.5.10)
uuid (~> 2.3)
ruby2ruby (2.2.0)
......@@ -701,7 +714,7 @@ GEM
rubyntlm (0.5.2)
rubypants (0.2.0)
rufus-scheduler (3.1.10)
rugged (0.24.0b13)
rugged (0.24.0)
safe_yaml (1.0.4)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
......@@ -715,6 +728,9 @@ GEM
sawyer (0.6.0)
addressable (~> 2.3.5)
faraday (~> 0.8, < 0.10)
scss_lint (0.47.1)
rake (>= 0.9, < 11)
sass (~> 3.4.15)
sdoc (0.3.20)
json (>= 1.1.3)
rdoc (~> 3.10)
......@@ -764,6 +780,8 @@ GEM
capybara (>= 2.0.0)
railties (>= 3)
spinach (>= 0.4)
spinach-rerun-reporter (0.0.2)
spinach (~> 0.8)
spring (1.6.4)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
......@@ -831,6 +849,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.1)
unicode-display_width (1.0.2)
unicorn (4.9.0)
kgio (~> 2.6)
rack
......@@ -897,7 +916,7 @@ DEPENDENCIES
bundler-audit
byebug
cal-heatmap-rails (~> 3.5.0)
capybara (~> 2.4.0)
capybara (~> 2.6.2)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.10.0)
charlock_holmes (~> 0.7.3)
......@@ -930,10 +949,11 @@ DEPENDENCIES
github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_emoji (~> 0.3.0)
gitlab_git (~> 9.0)
gitlab_git (~> 10.0)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.1.0)
gollum-rugged_adapter (~> 0.4.2)
gon (~> 6.0.1)
grape (~> 0.13.0)
grape-entity (~> 0.4.2)
......@@ -952,7 +972,6 @@ DEPENDENCIES
loofah (~> 2.0.3)
mail_room (~> 0.6.1)
method_source (~> 0.8)
mini_magick (~> 4.4.0)
minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.3.16)
......@@ -963,6 +982,7 @@ DEPENDENCIES
oauth2 (~> 1.0.0)
octokit (~> 3.8.0)
omniauth (~> 1.3.1)
omniauth-auth0 (~> 1.4.1)
omniauth-azure-oauth2 (~> 0.0.6)
omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2)
......@@ -971,14 +991,15 @@ DEPENDENCIES
omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.0)
omniauth-kerberos (~> 0.3.0)
omniauth-saml (~> 1.4.2)
omniauth-saml (~> 1.5.0)
omniauth-shibboleth (~> 1.2.0)
omniauth-twitter (~> 1.2.0)
omniauth_crowd (~> 2.2.0)
org-ruby (~> 0.9.12)
paranoia (~> 2.0)
pg (~> 0.18.2)
poltergeist (~> 1.8.1)
poltergeist (~> 1.9.0)
premailer-rails (~> 1.9.0)
pry-rails
quiet_assets (~> 1.0.2)
rack-attack (~> 4.3.1)
......@@ -999,10 +1020,12 @@ DEPENDENCIES
rouge (~> 1.10.1)
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.3.0)
rubocop (~> 0.35.0)
rspec-retry
rubocop (~> 0.38.0)
ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0)
sass-rails (~> 5.0.0)
scss_lint (~> 0.47.0)
sdoc (~> 0.3.20)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
......@@ -1017,6 +1040,7 @@ DEPENDENCIES
six (~> 0.2.0)
slack-notifier (~> 1.2.0)
spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2)
spring (~> 1.6.4)
spring-commands-rspec (~> 1.0.4)
spring-commands-spinach (~> 1.0.0)
......
......@@ -68,7 +68,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.1
- Git 1.7.10+
- Git 2.7.4+
- Redis 2.8+
- MySQL or PostgreSQL
......
......@@ -4,6 +4,7 @@
namespaces_path: "/api/:version/namespaces.json"
group_projects_path: "/api/:version/groups/:id/projects.json"
projects_path: "/api/:version/projects.json"
labels_path: "/api/:version/projects/:id/labels"
group: (group_id, callback) ->
url = Api.buildUrl(Api.group_path)
......@@ -61,6 +62,19 @@
).done (projects) ->
callback(projects)
newLabel: (project_id, data, callback) ->
url = Api.buildUrl(Api.labels_path)
url = url.replace(':id', project_id)
data.private_token = gon.api_token
$.ajax(
url: url
type: "POST"
data: data
dataType: "json"
).done (label) ->
callback(label)
# Return group projects list. Filtered by query
groupProjects: (group_id, query, callback) ->
url = Api.buildUrl(Api.group_projects_path)
......
......@@ -7,6 +7,7 @@
#= require jquery
#= require jquery-ui/autocomplete
#= require jquery-ui/datepicker
#= require jquery-ui/draggable
#= require jquery-ui/effect-highlight
#= require jquery-ui/sortable
#= require jquery_ujs
......@@ -42,7 +43,6 @@
#= require jquery.nicescroll
#= require_tree .
#= require fuzzaldrin-plus
#= require cropper.js
window.slugify = (text) ->
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
......@@ -108,6 +108,8 @@ window.onload = ->
setTimeout shiftWindow, 100
$ ->
bootstrapBreakpoint = bp.getBreakpointSize()
$(".nicescroll").niceScroll(cursoropacitymax: '0.4', cursorcolor: '#FFF', cursorborder: "1px solid #FFF")
# Click a .js-select-on-focus field, select the contents
......@@ -220,17 +222,17 @@ $ ->
.off 'breakpoint:change'
.on 'breakpoint:change', (e, breakpoint) ->
if breakpoint is 'sm' or breakpoint is 'xs'
$gutterIcon = $('aside .gutter-toggle').find('i')
$gutterIcon = $('.js-sidebar-toggle').find('i')
if $gutterIcon.hasClass('fa-angle-double-right')
$gutterIcon.closest('a').trigger('click')
$(document)
.off 'click', 'aside .gutter-toggle'
.on 'click', 'aside .gutter-toggle', (e, triggered) ->
.off 'click', '.js-sidebar-toggle'
.on 'click', '.js-sidebar-toggle', (e, triggered) ->
e.preventDefault()
$this = $(this)
$thisIcon = $this.find 'i'
$allGutterToggleIcons = $('.gutter-toggle i')
$allGutterToggleIcons = $('.js-sidebar-toggle i')
if $thisIcon.hasClass('fa-angle-double-right')
$allGutterToggleIcons
.removeClass('fa-angle-double-right')
......@@ -256,35 +258,14 @@ $ ->
$('.right-sidebar')
.hasClass('right-sidebar-collapsed'), { path: '/' })
bootstrapBreakpoint = undefined;
checkBootstrapBreakpoints = ->
if $('.device-xs').is(':visible')
bootstrapBreakpoint = "xs"
else if $('.device-sm').is(':visible')
bootstrapBreakpoint = "sm"
else if $('.device-md').is(':visible')
bootstrapBreakpoint = "md"
else if $('.device-lg').is(':visible')
bootstrapBreakpoint = "lg"
setBootstrapBreakpoints = ->
if $('.device-xs').length
return
$("body")
.append('<div class="device-xs visible-xs"></div>'+
'<div class="device-sm visible-sm"></div>'+
'<div class="device-md visible-md"></div>'+
'<div class="device-lg visible-lg"></div>')
checkBootstrapBreakpoints()
fitSidebarForSize = ->
oldBootstrapBreakpoint = bootstrapBreakpoint
checkBootstrapBreakpoints()
bootstrapBreakpoint = bp.getBreakpointSize()
if bootstrapBreakpoint != oldBootstrapBreakpoint
$(document).trigger('breakpoint:change', [bootstrapBreakpoint])
checkInitialSidebarSize = ->
bootstrapBreakpoint = bp.getBreakpointSize()
if bootstrapBreakpoint is "xs" or "sm"
$(document).trigger('breakpoint:change', [bootstrapBreakpoint])
......@@ -293,6 +274,5 @@ $ ->
.on "resize", (e) ->
fitSidebarForSize()
setBootstrapBreakpoints()
checkInitialSidebarSize()
new Aside()
......@@ -5,7 +5,6 @@ class @Aside
e.preventDefault()
btn = $(e.currentTarget)
icon = btn.find('i')
console.log('1')
if icon.hasClass('fa-angle-left')
btn.parent().find('section').hide()
......
class @AwardsHandler
constructor: (@post_emoji_url, @noteable_type, @noteable_id, @aliases) ->
$(".add-award").click (event) =>
$(".js-add-award").on "click", (event) =>
event.stopPropagation()
event.preventDefault()
......@@ -9,27 +9,46 @@ class @AwardsHandler
$("html").on 'click', (event) ->
if !$(event.target).closest(".emoji-menu").length
if $(".emoji-menu").is(":visible")
$(".emoji-menu").hide()
$(".emoji-menu").removeClass "is-visible"
$(".awards")
.off "click"
.on "click", ".js-emoji-btn", @handleClick
@renderFrequentlyUsedBlock()
@setupSearch()
handleClick: (e) ->
e.preventDefault()
emoji = $(this)
.find(".icon")
.data "emoji"
awards_handler.addAward emoji
showEmojiMenu: ->
if $(".emoji-menu").length
$(".emoji-menu").show()
$("#emoji_search").focus()
else
$.get "/emojis", (response) ->
$(".add-award").after response
$(".emoji-menu").show()
if $(".emoji-menu").is ".is-visible"
$(".emoji-menu").removeClass "is-visible"
$("#emoji_search").blur()
else
$(".emoji-menu").addClass "is-visible"
$("#emoji_search").focus()
else
$('.js-add-award').addClass "is-loading"
$.get "/emojis", (response) =>
$('.js-add-award').removeClass "is-loading"
$(".js-award-holder").append response
setTimeout =>
$(".emoji-menu").addClass "is-visible"
$("#emoji_search").focus()
@setupSearch()
, 200
addAward: (emoji) ->
emoji = @normilizeEmojiName(emoji)
@postEmoji emoji, =>
@addAwardToEmojiBar(emoji)
$(".emoji-menu").hide()
$(".emoji-menu").removeClass "is-visible"
addAwardToEmojiBar: (emoji) ->
@addEmojiToFrequentlyUsedList(emoji)
......@@ -39,7 +58,7 @@ class @AwardsHandler
if @isActive(emoji)
@decrementCounter(emoji)
else
counter = @findEmojiIcon(emoji).siblings(".counter")
counter = @findEmojiIcon(emoji).siblings(".js-counter")
counter.text(parseInt(counter.text()) + 1)
counter.parent().addClass("active")
@addMeToAuthorList(emoji)
......@@ -53,7 +72,7 @@ class @AwardsHandler
@findEmojiIcon(emoji).parent().hasClass("active")
decrementCounter: (emoji) ->
counter = @findEmojiIcon(emoji).siblings(".counter")
counter = @findEmojiIcon(emoji).siblings(".js-counter")
emojiIcon = counter.parent()
if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1)
......@@ -70,9 +89,13 @@ class @AwardsHandler
removeMeFromAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent()
authors = award_block.attr("data-original-title").split(", ")
authors = award_block
.attr("data-original-title")
.split(", ")
authors.splice(authors.indexOf("me"),1)
award_block.closest(".award").attr("data-original-title", authors.join(", "))
award_block
.closest(".js-emoji-btn")
.attr("data-original-title", authors.join(", "))
@resetTooltip(award_block)
addMeToAuthorList: (emoji) ->
......@@ -98,14 +121,18 @@ class @AwardsHandler
emojiCssClass = @resolveNameToCssClass(emoji)
nodes = []
nodes.push("<div class='award active' title='me'>")
nodes.push("<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>")
nodes.push("<div class='counter'>1</div>")
nodes.push("</div>")
emoji_node = $(nodes.join("\n")).insertBefore(".awards-controls").find(".emoji-icon").data("emoji", emoji)
$(".award").tooltip()
nodes.push(
"<button class='btn award-control js-emoji-btn has_tooltip active' title='me'>",
"<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>",
"<span class='award-control-text js-counter'>1</span>",
"</button>"
)
emoji_node = $(nodes.join("\n"))
.insertBefore(".js-award-holder")
.find(".emoji-icon")
.data("emoji", emoji)
$('.award-control').tooltip()
resolveNameToCssClass: (emoji) ->
emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']")
......@@ -128,7 +155,7 @@ class @AwardsHandler
callback.call()
findEmojiIcon: (emoji) ->
$(".award [data-emoji='#{emoji}']")
$(".awards > .js-emoji-btn [data-emoji='#{emoji}']")
scrollToAwards: ->
$('body, html').animate({
......@@ -164,13 +191,13 @@ class @AwardsHandler
term = $(ev.target).val()
# Clean previous search results
$("ul.emoji-search,h5.emoji-search").remove()
$("ul.emoji-menu-search, h5.emoji-search").remove()
if term
# Generate a search result block
h5 = $("<h5>").text("Search results").addClass("emoji-search")
found_emojis = @searchEmojis(term).show()
ul = $("<ul>").addClass("emoji-search").append(found_emojis)
ul = $("<ul>").addClass("emoji-menu-list emoji-menu-search").append(found_emojis)
$(".emoji-menu-content ul, .emoji-menu-content h5").hide()
$(".emoji-menu-content").append(h5).append(ul)
else
......
class @Breakpoints
instance = null;
class BreakpointInstance
BREAKPOINTS = ["xs", "sm", "md", "lg"]
constructor: ->
@setup()
setup: ->
allDeviceSelector = BREAKPOINTS.map (breakpoint) ->
".device-#{breakpoint}"
return if $(allDeviceSelector.join(",")).length
# Create all the elements
els = $.map BREAKPOINTS, (breakpoint) ->
"<div class='device-#{breakpoint} visible-#{breakpoint}'></div>"
$("body").append els.join('')
visibleDevice: ->
allDeviceSelector = BREAKPOINTS.map (breakpoint) ->
".device-#{breakpoint}"
$(allDeviceSelector.join(",")).filter(":visible")
getBreakpointSize: ->
$visibleDevice = @visibleDevice
# the page refreshed via turbolinks
if not $visibleDevice().length
@setup()
$visibleDevice = @visibleDevice()
return $visibleDevice.attr("class").split("visible-")[1]
@get: ->
return instance ?= new BreakpointInstance
$ =>
@bp = Breakpoints.get()
......@@ -4,6 +4,8 @@ class CiBuild
constructor: (build_url, build_status) ->
clearInterval(CiBuild.interval)
@initScrollButtonAffix()
if build_status == "running" || build_status == "pending"
#
# Bind autoscroll button to follow build output
......@@ -38,4 +40,15 @@ class CiBuild
checkAutoscroll: ->
$("html,body").scrollTop $("#build-trace").height() if "enabled" is $("#autoscroll-button").data("state")
initScrollButtonAffix: ->
$buildScroll = $('#js-build-scroll')
$body = $('body')
$buildTrace = $('#build-trace')
$buildScroll.affix(
offset:
bottom: ->
$body.outerHeight() - ($buildTrace.outerHeight() + $buildTrace.offset().top)
)
@CiBuild = CiBuild
......@@ -14,7 +14,6 @@ class Dispatcher
path = page.split(':')
shortcut_handler = null
switch page
when 'projects:issues:index'
Issues.init()
......@@ -23,8 +22,10 @@ class Dispatcher
new Issue()
shortcut_handler = new ShortcutsIssuable()
new ZenMode()
when 'projects:milestones:show'
when 'projects:milestones:show', 'groups:milestones:show', 'dashboard:milestones:show'
new Milestone()
when 'dashboard:todos:index'
new Todos()
when 'projects:milestones:new', 'projects:milestones:edit'
new ZenMode()
new DropzoneInput($('.milestone-form'))
......@@ -74,8 +75,9 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
new TreeView() if $('#tree-slider').length
when 'groups:show'
when 'groups:activity'
new Activities()
when 'groups:show'
shortcut_handler = new ShortcutsNavigation()
when 'groups:group_members:index'
new GroupMembers()
......@@ -103,6 +105,8 @@ class Dispatcher
new ProjectFork()
when 'projects:artifacts:browse'
new BuildArtifacts()
when 'projects:group_links:index'
new GroupsSelect()
switch path.first()
when 'admin'
......
class GitLabDropdownFilter
BLUR_KEYCODES = [27, 40]
constructor: (@dropdown, @options) ->
@input = @dropdown.find(".dropdown-input .dropdown-input-field")
# Key events
timeout = ""
@input.on "keyup", (e) =>
if e.keyCode is 13 && @input.val() isnt ""
if @options.enterCallback
@options.enterCallback()
return
clearTimeout timeout
timeout = setTimeout =>
blur_field = @shouldBlur e.keyCode
search_text = @input.val()
if blur_field
@input.blur()
if @options.remote
@options.query search_text, (data) =>
@options.callback(data)
else
@filter search_text
, 250
shouldBlur: (keyCode) ->
return BLUR_KEYCODES.indexOf(keyCode) >= 0
filter: (search_text) ->
data = @options.data()
results = data
if search_text isnt ""
results = fuzzaldrinPlus.filter(data, search_text,
key: @options.keys
)
@options.callback results
class GitLabDropdownRemote
constructor: (@dataEndpoint, @options) ->
execute: ->
if typeof @dataEndpoint is "string"
@fetchData()
else if typeof @dataEndpoint is "function"
if @options.beforeSend
@options.beforeSend()
# Fetch the data by calling the data funcfion
@dataEndpoint "", (data) =>
if @options.success
@options.success(data)
if @options.beforeSend
@options.beforeSend()
# Fetch the data through ajax if the data is a string
fetchData: ->
$.ajax(
url: @dataEndpoint,
dataType: @options.dataType,
beforeSend: =>
if @options.beforeSend
@options.beforeSend()
success: (data) =>
if @options.success
@options.success(data)
)
class GitLabDropdown
LOADING_CLASS = "is-loading"
PAGE_TWO_CLASS = "is-page-two"
ACTIVE_CLASS = "is-active"
constructor: (@el, @options) ->
self = @
@dropdown = $(@el).parent()
search_fields = if @options.search then @options.search.fields else [];
if @options.data
# Remote data
@remote = new GitLabDropdownRemote @options.data, {
dataType: @options.dataType,
beforeSend: @toggleLoading.bind(@)
success: (data) =>
@fullData = data
@parseData @fullData
}
# Init filiterable
if @options.filterable
@filter = new GitLabDropdownFilter @dropdown,
remote: @options.filterRemote
query: @options.data
keys: @options.search.fields
data: =>
return @fullData
callback: (data) =>
@parseData data
enterCallback: =>
@selectFirstRow()
# Event listeners
@dropdown.on "shown.bs.dropdown", @opened
@dropdown.on "hidden.bs.dropdown", @hidden
if @dropdown.find(".dropdown-toggle-page").length
@dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) =>
e.preventDefault()
e.stopPropagation()
@togglePage()
if @options.selectable
selector = ".dropdown-content a"
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content a"
@dropdown.on "click", selector, (e) ->
self.rowClicked $(@)
if self.options.clicked
self.options.clicked()
toggleLoading: ->
$('.dropdown-menu', @dropdown).toggleClass LOADING_CLASS
togglePage: ->
menu = $('.dropdown-menu', @dropdown)
if menu.hasClass(PAGE_TWO_CLASS)
if @remote
@remote.execute()
menu.toggleClass PAGE_TWO_CLASS
parseData: (data) ->
@renderedData = data
# Render each row
html = $.map data, (obj) =>
return @renderItem(obj)
if @options.filterable and data.length is 0
# render no matching results
html = [@noResults()]
# Render the full menu
full_html = @renderMenu(html.join(""))
@appendMenu(full_html)
opened: =>
contentHtml = $('.dropdown-content', @dropdown).html()
if @remote && contentHtml is ""
@remote.execute()
if @options.filterable
@dropdown.find(".dropdown-input-field").focus()
hidden: =>
if @options.filterable
@dropdown
.find(".dropdown-input-field")
.blur()
.val("")
.trigger("keyup")
if @dropdown.find(".dropdown-toggle-page").length
$('.dropdown-menu', @dropdown).removeClass PAGE_TWO_CLASS
# Render the full menu
renderMenu: (html) ->
menu_html = ""
if @options.renderMenu
menu_html = @options.renderMenu(html)
else
menu_html = "<ul>#{html}</ul>"
return menu_html
# Append the menu into the dropdown
appendMenu: (html) ->
selector = '.dropdown-content'
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content"
$(selector, @dropdown).html html
# Render the row
renderItem: (data) ->
html = ""
return "<li class='divider'></li>" if data is "divider"
if @options.renderRow
# Call the render function
html = @options.renderRow(data)
else
selected = if @options.isSelected then @options.isSelected(data) else false
url = if @options.url then @options.url(data) else "#"
text = if @options.text then @options.text(data) else ""
cssClass = "";
if selected
cssClass = "is-active"
html = "<li>"
html += "<a href='#{url}' class='#{cssClass}'>"
html += text
html += "</a>"
html += "</li>"
return html
noResults: ->
html = "<li>"
html += "<a href='#' class='is-focused'>"
html += "No matching results."
html += "</a>"
html += "</li>"
rowClicked: (el) ->
fieldName = @options.fieldName
field = @dropdown.parent().find("input[name='#{fieldName}']")
if el.hasClass(ACTIVE_CLASS)
field.remove()
else
fieldName = @options.fieldName
selectedIndex = el.parent().index()
if @renderedData
selectedObject = @renderedData[selectedIndex]
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
if !value?
field.remove()
if @options.multiSelect
oldValue = field.val()
if oldValue
value = "#{oldValue},#{value}"
else
@dropdown.find(".#{ACTIVE_CLASS}").removeClass ACTIVE_CLASS
# Toggle active class for the tick mark
el.toggleClass "is-active"
# Toggle the dropdown label
if @options.toggleLabel
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject)
if value?
if !field.length
# Create hidden input for form
input = "<input type='hidden' name='#{fieldName}' />"
@dropdown.before input
@dropdown.parent().find("input[name='#{fieldName}']").val value
selectFirstRow: ->
selector = '.dropdown-content li:first-child a'
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content li:first-child a"
# similute a click on the first link
$(selector).trigger "click"
$.fn.glDropdown = (opts) ->
return @.each ->
new GitLabDropdown @, opts
class @IssuableForm
issueMoveConfirmMsg: 'Are you sure you want to move this issue to another project?'
wipRegex: /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i
constructor: (@form) ->
GitLab.GfmAutoComplete.setup()
new UsersSelect()
......@@ -6,14 +9,17 @@ class @IssuableForm
@titleField = @form.find("input[name*='[title]']")
@descriptionField = @form.find("textarea[name*='[description]']")
@issueMoveField = @form.find("#move_to_project_id")
return unless @titleField.length && @descriptionField.length
@initAutosave()
@form.on "submit", @resetAutosave
@form.on "submit", @handleSubmit
@form.on "click", ".btn-cancel", @resetAutosave
@initWip()
initAutosave: ->
new Autosave @titleField, [
document.location.pathname,
......@@ -27,6 +33,50 @@ class @IssuableForm
"description"
]
handleSubmit: =>
if (parseInt(@issueMoveField?.val()) ? 0) > 0
return false unless confirm(@issueMoveConfirmMsg)
@resetAutosave()
resetAutosave: =>
@titleField.data("autosave").reset()
@descriptionField.data("autosave").reset()
initWip: ->
@$wipExplanation = @form.find(".js-wip-explanation")
@$noWipExplanation = @form.find(".js-no-wip-explanation")
return unless @$wipExplanation.length and @$noWipExplanation.length
@form.on "click", ".js-toggle-wip", @toggleWip
@titleField.on "keyup blur", @renderWipExplanation
@renderWipExplanation()
workInProgress: ->
@wipRegex.test @titleField.val()
renderWipExplanation: =>
if @workInProgress()
@$wipExplanation.show()
@$noWipExplanation.hide()
else
@$wipExplanation.hide()
@$noWipExplanation.show()
toggleWip: (event) =>
event.preventDefault()
if @workInProgress()
@removeWip()
else
@addWip()
@renderWipExplanation()
removeWip: ->
@titleField.val @titleField.val().replace(@wipRegex, "")
addWip: ->
@titleField.val "WIP: #{@titleField.val()}"
......@@ -7,6 +7,7 @@ class @Issue
# Prevent duplicate event bindings
@disableTaskList()
@fixAffixScroll()
@initParticipants()
if $('a.btn-close').length
@initTaskList()
@initIssueBtnEventListeners()
......@@ -84,3 +85,27 @@ class @Issue
type: 'PATCH'
url: $('form.js-issuable-update').attr('action')
data: patchData
initParticipants: ->
_this = @
$(document).on "click", ".js-participants-more", @toggleHiddenParticipants
$(".js-participants-author").each (i) ->
if i >= _this.PARTICIPANTS_ROW_COUNT
$(@)
.addClass "js-participants-hidden"
.hide()
toggleHiddenParticipants: (e) ->
e.preventDefault()
currentText = $(this).text().trim()
lessText = $(this).data("less-text")
originalText = $(this).data("original-text")
if currentText is originalText
$(this).text(lessText)
else
$(this).text(originalText)
$(".js-participants-hidden").toggle()
class @IssueStatusSelect
constructor: ->
$('.js-issue-status').each (i, el) ->
fieldName = $(el).data("field-name")
$(el).glDropdown(
selectable: true
fieldName: fieldName
id: (obj, el) ->
$(el).data("id")
)
......@@ -41,24 +41,28 @@
@timer = null
$("#issue_search").keyup ->
clearTimeout(@timer)
@timer = setTimeout(Issues.filterResults, 500)
@timer = setTimeout( ->
Issues.filterResults $("#issue_search_form")
, 500)
filterResults: =>
form = $("#issue_search_form")
search = $("#issue_search").val()
$('.issues-holder').css("opacity", '0.5')
issues_url = form.attr('action') + '?' + form.serialize()
filterResults: (form) =>
$('.issues-holder, .merge-requests-holder').css("opacity", '0.5')
formAction = form.attr('action')
formData = form.serialize()
issuesUrl = formAction
issuesUrl += ("#{if formAction.indexOf("?") < 0 then '?' else '&'}")
issuesUrl += formData
$.ajax
type: "GET"
url: form.attr('action')
data: form.serialize()
url: formAction
data: formData
complete: ->
$('.issues-holder').css("opacity", '1.0')
$('.issues-holder, .merge-requests-holder').css("opacity", '1.0')
success: (data) ->
$('.issues-holder').html(data.html)
$('.issues-holder, .merge-requests-holder').html(data.html)
# Change url so if user reload a page - search results are saved
history.replaceState {page: issues_url}, document.title, issues_url
history.replaceState {page: issuesUrl}, document.title, issuesUrl
Issues.reload()
dataType: "json"
......
class @LabelsSelect
constructor: ->
$('.js-label-select').each (i, dropdown) ->
$dropdown = $(dropdown)
projectId = $dropdown.data('project-id')
labelUrl = $dropdown.data('labels')
selectedLabel = $dropdown.data('selected')
if selectedLabel
selectedLabel = selectedLabel.split(',')
newLabelField = $('#new_label_name')
newColorField = $('#new_label_color')
showNo = $dropdown.data('show-no')
showAny = $dropdown.data('show-any')
defaultLabel = $dropdown.data('default-label')
if newLabelField.length
$('.suggest-colors-dropdown a').on 'click', (e) ->
e.preventDefault()
e.stopPropagation()
newColorField.val $(this).data('color')
$('.js-dropdown-label-color-preview')
.css 'background-color', $(this).data('color')
.addClass 'is-active'
$('.js-new-label-btn').on 'click', (e) ->
e.preventDefault()
e.stopPropagation()
if newLabelField.val() isnt '' and newColorField.val() isnt ''
$('.js-new-label-btn').disable()
# Create new label with API
Api.newLabel projectId, {
name: newLabelField.val()
color: newColorField.val()
}, (label) ->
$('.js-new-label-btn').enable()
$('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
$dropdown.glDropdown(
data: (term, callback) ->
$.ajax(
url: labelUrl
).done (data) ->
if showNo
data.unshift(
id: 0
title: 'No Label'
)
if showAny
data.unshift(
isAny: true
title: 'Any Label'
)
if data.length > 2
data.splice 2, 0, 'divider'
callback data
renderRow: (label) ->
if $.isArray(selectedLabel)
selected = ''
$.each selectedLabel, (i, selectedLbl) ->
selectedLbl = selectedLbl.trim()
if selected is '' and label.title is selectedLbl
selected = 'is-active'
else
selected = if label.title is selectedLabel then 'is-active' else ''
"<li>
<a href='#' class='#{selected}'>
#{label.title}
</a>
</li>"
filterable: true
search:
fields: ['title']
selectable: true
toggleLabel: (selected) ->
if selected and selected.title isnt 'Any Label'
selected.title
else
defaultLabel
fieldName: $dropdown.data('field-name')
id: (label) ->
if label.isAny?
''
else
label.title
clicked: ->
page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
Issues.filterResults $dropdown.closest('form')
else if $dropdown.hasClass 'js-filter-submit'
$dropdown.closest('form').submit()
)
......@@ -6,6 +6,7 @@
class @MarkdownPreview
# Minimum number of users referenced before triggering a warning
referenceThreshold: 10
ajaxCache: {}
showPreview: (form) ->
preview = form.find('.js-md-preview')
......@@ -24,12 +25,16 @@ class @MarkdownPreview
renderMarkdown: (text, success) ->
return unless window.markdown_preview_path
return success(@ajaxCache.response) if text == @ajaxCache.text
$.ajax
type: 'POST'
url: window.markdown_preview_path
data: { text: text }
dataType: 'json'
success: success
success: (response) =>
@ajaxCache = text: text, response: response
success(response)
hideReferencedUsers: (form) ->
referencedUsers = form.find('.referenced-users')
......@@ -49,6 +54,7 @@ markdownPreview = new MarkdownPreview()
previewButtonSelector = '.js-md-preview-button'
writeButtonSelector = '.js-md-write-button'
lastTextareaPreviewed = null
$.fn.setupMarkdownPreview = ->
$form = $(this)
......@@ -58,10 +64,10 @@ $.fn.setupMarkdownPreview = ->
form_textarea.on 'input', -> markdownPreview.hideReferencedUsers($form)
form_textarea.on 'blur', -> markdownPreview.showPreview($form)
$(document).on 'click', previewButtonSelector, (e) ->
e.preventDefault()
$(document).on 'markdown-preview:show', (e, $form) ->
return unless $form
$form = $(this).closest('form')
lastTextareaPreviewed = $form.find('textarea.markdown-area')
# toggle tabs
$form.find(writeButtonSelector).parent().removeClass('active')
......@@ -73,10 +79,10 @@ $(document).on 'click', previewButtonSelector, (e) ->
markdownPreview.showPreview($form)
$(document).on 'click', writeButtonSelector, (e) ->
e.preventDefault()
$(document).on 'markdown-preview:hide', (e, $form) ->
return unless $form
$form = $(this).closest('form')
lastTextareaPreviewed = null
# toggle tabs
$form.find(writeButtonSelector).parent().addClass('active')
......@@ -84,4 +90,30 @@ $(document).on 'click', writeButtonSelector, (e) ->
# toggle content
$form.find('.md-write-holder').show()
$form.find('textarea.markdown-area').focus()
$form.find('.md-preview-holder').hide()
$(document).on 'markdown-preview:toggle', (e, keyboardEvent) ->
$target = $(keyboardEvent.target)
if $target.is('textarea.markdown-area')
$(document).triggerHandler('markdown-preview:show', [$target.closest('form')])
keyboardEvent.preventDefault()
else if lastTextareaPreviewed
$target = lastTextareaPreviewed
$(document).triggerHandler('markdown-preview:hide', [$target.closest('form')])
keyboardEvent.preventDefault()
$(document).on 'click', previewButtonSelector, (e) ->
e.preventDefault()
$form = $(this).closest('form')
$(document).triggerHandler('markdown-preview:show', [$form])
$(document).on 'click', writeButtonSelector, (e) ->
e.preventDefault()
$form = $(this).closest('form')
$(document).triggerHandler('markdown-preview:hide', [$form])
......@@ -3,6 +3,8 @@
# Handles persisting and restoring the current tab selection and lazily-loading
# content on the MergeRequests#show page.
#
#= require jquery.cookie
#
# ### Example Markup
#
# <ul class="nav-links merge-request-tabs">
......@@ -68,11 +70,15 @@ class @MergeRequestTabs
if action == 'commits'
@loadCommits($target.attr('href'))
@expandView()
else if action == 'diffs'
@loadDiff($target.attr('href'))
@shrinkView()
else if action == 'builds'
@loadBuilds($target.attr('href'))
@expandView()
else
@expandView()
@setCurrentAction(action)
......@@ -189,12 +195,24 @@ class @MergeRequestTabs
$('.container-fluid').removeClass('container-limited')
shrinkView: ->
$gutterIcon = $('.gutter-toggle i')
$gutterIcon = $('.js-sidebar-toggle i:visible')
# Wait until listeners are set
setTimeout( ->
# Only when sidebar is collapsed
# Only when sidebar is expanded
if $gutterIcon.is('.fa-angle-double-right')
$gutterIcon.closest('a').trigger('click',[true])
$gutterIcon.closest('a').trigger('click', [true])
, 0)
# Expand the issuable sidebar unless the user explicitly collapsed it
expandView: ->
return if $.cookie('collapsed_gutter') == 'true'
$gutterIcon = $('.js-sidebar-toggle i:visible')
# Wait until listeners are set
setTimeout( ->
# Only when sidebar is collapsed
if $gutterIcon.is('.fa-angle-double-left')
$gutterIcon.closest('a').trigger('click', [true])
, 0)
......@@ -69,7 +69,7 @@ class @Milestone
@bindIssuesSorting()
@bindMergeRequestSorting()
@bindTabsSwitching
@bindTabsSwitching()
bindIssuesSorting: ->
$("#issues-list-unassigned, #issues-list-ongoing, #issues-list-closed").sortable(
......@@ -104,7 +104,7 @@ class @Milestone
).disableSelection()
bindMergeRequestSorting: ->
bindTabsSwitching: ->
$('a[data-toggle="tab"]').on 'show.bs.tab', (e) ->
currentTabClass = $(e.target).data('show')
previousTabClass = $(e.relatedTarget).data('show')
......@@ -112,7 +112,8 @@ class @Milestone
$(previousTabClass).hide()
$(currentTabClass).removeClass('hidden')
$(currentTabClass).show()
bindMergeRequestSorting: ->
$("#merge_requests-list-unassigned, #merge_requests-list-ongoing, #merge_requests-list-closed").sortable(
connectWith: ".merge_requests-sortable-list",
dropOnEmpty: true,
......
class @MilestoneSelect
constructor: ->
$('.js-milestone-select').each (i, dropdown) ->
$dropdown = $(dropdown)
projectId = $dropdown.data('project-id')
milestonesUrl = $dropdown.data('milestones')
selectedMilestone = $dropdown.data('selected')
showNo = $dropdown.data('show-no')
showAny = $dropdown.data('show-any')
useId = $dropdown.data('use-id')
defaultLabel = $dropdown.data('default-label')
$dropdown.glDropdown(
data: (term, callback) ->
$.ajax(
url: milestonesUrl
).done (data) ->
if showNo
data.unshift(
id: '0'
title: 'No Milestone'
)
if showAny
data.unshift(
isAny: true
title: 'Any Milestone'
)
if data.length > 2
data.splice 2, 0, 'divider'
callback(data)
filterable: true
search:
fields: ['title']
selectable: true
toggleLabel: (selected) ->
if selected && 'id' of selected
selected.title
else
defaultLabel
fieldName: $dropdown.data('field-name')
text: (milestone) ->
milestone.title
id: (milestone) ->
if !useId
if !milestone.isAny?
milestone.title
else
''
else
milestone.id
isSelected: (milestone) ->
milestone.title is selectedMilestone
clicked: ->
page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
Issues.filterResults $dropdown.closest('form')
else if $dropdown.hasClass 'js-filter-submit'
$dropdown.closest('form').submit()
)
......@@ -30,8 +30,11 @@ class @Notes
$(document).on "ajax:success", ".js-main-target-form", @addNote
$(document).on "ajax:success", ".js-discussion-note-form", @addDiscussionNote
# catch note ajax errors
$(document).on "ajax:error", ".js-main-target-form", @addNoteError
# change note in UI after update
$(document).on "ajax:success", "form.edit_note", @updateNote
$(document).on "ajax:success", "form.edit-note", @updateNote
# Edit note link
$(document).on "click", ".js-note-edit", @showEditForm
......@@ -51,6 +54,9 @@ class @Notes
$(document).on "ajax:complete", ".js-main-target-form", @reenableTargetFormSubmitButton
$(document).on "ajax:success", ".js-main-target-form", @resetMainTargetForm
# reset main target form when clicking discard
$(document).on "click", ".js-note-discard", @resetMainTargetForm
# update the file name when an attachment is selected
$(document).on "change", ".js-note-attachment-input", @updateFormAttachment
......@@ -72,7 +78,7 @@ class @Notes
cleanBinding: ->
$(document).off "ajax:success", ".js-main-target-form"
$(document).off "ajax:success", ".js-discussion-note-form"
$(document).off "ajax:success", "form.edit_note"
$(document).off "ajax:success", "form.edit-note"
$(document).off "click", ".js-note-edit"
$(document).off "click", ".note-edit-cancel"
$(document).off "click", ".js-note-delete"
......@@ -85,6 +91,7 @@ class @Notes
$(document).off "keyup", ".js-note-text"
$(document).off "click", ".js-note-target-reopen"
$(document).off "click", ".js-note-target-close"
$(document).off "click", ".js-note-discard"
$('.note .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.note .js-task-list-container'
......@@ -219,7 +226,7 @@ class @Notes
Resets text and preview.
Resets buttons.
###
resetMainTargetForm: ->
resetMainTargetForm: (e) =>
form = $(".js-main-target-form")
# remove validation errors
......@@ -231,6 +238,8 @@ class @Notes
form.find(".js-note-text").data("autosave").reset()
@updateTargetButtons(e)
reenableTargetFormSubmitButton: ->
form = $(".js-main-target-form")
......@@ -274,8 +283,10 @@ class @Notes
form.removeClass "js-new-note-form"
form.find('.div-dropzone').remove()
# hide discard button
form.find('.js-note-discard').hide()
# setup preview buttons
form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left"
previewButton = form.find(".js-md-preview-button")
textarea = form.find(".js-note-text")
......@@ -309,6 +320,10 @@ class @Notes
addNote: (xhr, note, status) =>
@renderNote(note)
addNoteError: (xhr, note, status) =>
flash = new Flash('Your comment could not be submitted! Please check your network connection and try again.', 'alert')
flash.pinTo('.md-area')
###
Called in response to the new note form being submitted
......@@ -328,6 +343,7 @@ class @Notes
updateNote: (_xhr, note, _status) =>
# Convert returned HTML to a jQuery object so we can modify it further
$html = $(note.html)
$('.js-timeago', $html).timeago()
$html.syntaxHighlight()
$html.find('.js-task-list-container').taskList('enable')
......@@ -345,24 +361,26 @@ class @Notes
showEditForm: (e) ->
e.preventDefault()
note = $(this).closest(".note")
note.find(".note-body > .note-text").hide()
note.find(".note-header").hide()
base_form = note.find(".note-edit-form")
form = base_form.clone().insertAfter(base_form)
form.addClass('current-note-edit-form gfm-form')
form.find('.div-dropzone').remove()
note.addClass "is-editting"
form = note.find(".note-edit-form")
isNewForm = form.is(':not(.gfm-form)')
if isNewForm
form.addClass('gfm-form')
form.addClass('current-note-edit-form')
# Show the attachment delete link
note.find(".js-note-attachment-delete").show()
# Setup markdown form
GitLab.GfmAutoComplete.setup()
new DropzoneInput(form)
if isNewForm
GitLab.GfmAutoComplete.setup()
new DropzoneInput(form)
form.show()
textarea = form.find("textarea")
textarea.focus()
autosize(textarea)
if isNewForm
autosize(textarea)
# HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?).
# The textarea has the correct value, Chrome just won't show it unless we
......@@ -371,7 +389,8 @@ class @Notes
textarea.val ""
textarea.val value
disableButtonIfEmptyField textarea, form.find(".js-comment-button")
if isNewForm
disableButtonIfEmptyField textarea, form.find(".js-comment-button")
###
Called in response to clicking the edit note link
......@@ -381,9 +400,9 @@ class @Notes
cancelEdit: (e) ->
e.preventDefault()
note = $(this).closest(".note")
note.find(".note-body > .note-text").show()
note.find(".note-header").show()
note.find(".current-note-edit-form").remove()
note.removeClass "is-editting"
note.find(".current-note-edit-form")
.removeClass("current-note-edit-form")
###
Called in response to deleting a note of any kind.
......@@ -462,6 +481,11 @@ class @Notes
form.find("#note_line_code").val dataHolder.data("lineCode")
form.find("#note_noteable_type").val dataHolder.data("noteableType")
form.find("#note_noteable_id").val dataHolder.data("noteableId")
form.find('.js-note-discard')
.show()
.removeClass('js-note-discard')
.addClass('js-close-discussion-note-form')
.text(form.find('.js-close-discussion-note-form').data('cancel-text'))
@setupNoteForm form
form.find(".js-note-text").focus()
form.addClass "js-discussion-note-form"
......@@ -561,21 +585,52 @@ class @Notes
updateCloseButton: (e) =>
textarea = $(e.target)
form = textarea.parents('form')
form.find('.js-note-target-close').text('Close')
closebtn = form.find('.js-note-target-close')
closebtn.text(closebtn.data('original-text'))
updateTargetButtons: (e) =>
textarea = $(e.target)
form = textarea.parents('form')
reopenbtn = form.find('.js-note-target-reopen')
closebtn = form.find('.js-note-target-close')
discardbtn = form.find('.js-note-discard')
if textarea.val().trim().length > 0
form.find('.js-note-target-reopen').text('Comment & reopen')
form.find('.js-note-target-close').text('Comment & close')
form.find('.js-note-target-reopen').addClass('btn-comment-and-reopen')
form.find('.js-note-target-close').addClass('btn-comment-and-close')
reopentext = reopenbtn.data('alternative-text')
closetext = closebtn.data('alternative-text')
if reopenbtn.text() isnt reopentext
reopenbtn.text(reopentext)
if closebtn.text() isnt closetext
closebtn.text(closetext)
if reopenbtn.is(':not(.btn-comment-and-reopen)')
reopenbtn.addClass('btn-comment-and-reopen')
if closebtn.is(':not(.btn-comment-and-close)')
closebtn.addClass('btn-comment-and-close')
if discardbtn.is(':hidden')
discardbtn.show()
else
form.find('.js-note-target-reopen').text('Reopen')
form.find('.js-note-target-close').text('Close')
form.find('.js-note-target-reopen').removeClass('btn-comment-and-reopen')
form.find('.js-note-target-close').removeClass('btn-comment-and-close')
reopentext = reopenbtn.data('original-text')
closetext = closebtn.data('original-text')
if reopenbtn.text() isnt reopentext
reopenbtn.text(reopentext)
if closebtn.text() isnt closetext
closebtn.text(closetext)
if reopenbtn.is('.btn-comment-and-reopen')
reopenbtn.removeClass('btn-comment-and-reopen')
if closebtn.is('.btn-comment-and-close')
closebtn.removeClass('btn-comment-and-close')
if discardbtn.is(':visible')
discardbtn.hide()
initTaskList: ->
@enableTaskList()
......
......@@ -4,64 +4,27 @@ class @Profile
$('.js-preferences-form').on 'change.preference', 'input[type=radio]', ->
$(this).parents('form').submit()
$('.update-username form').on 'ajax:before', ->
$('.loading-gif').show()
$('.update-username').on 'ajax:before', ->
$('.loading-username').show()
$(this).find('.update-success').hide()
$(this).find('.update-failed').hide()
$('.update-username form').on 'ajax:complete', ->
$('.update-username').on 'ajax:complete', ->
$('.loading-username').hide()
$(this).find('.btn-save').enable()
$(this).find('.loading-gif').hide()
$('.update-notifications').on 'ajax:complete', ->
$(this).find('.btn-save').enable()
# Avatar management
$avatarInput = $('.js-user-avatar-input')
$filename = $('.js-avatar-filename')
$modalCrop = $('.modal-profile-crop')
$modalCropImg = $('.modal-profile-crop-image')
$('.js-choose-user-avatar-button').on "click", ->
$form = $(this).closest("form")
$form.find(".js-user-avatar-input").click()
$modalCrop.on 'shown.bs.modal', ->
setTimeout ( -> # The cropper must be asynchronously initialized
$modalCropImg.cropper
aspectRatio: 1
modal: false
scalable: false
rotatable: false
zoomable: false
crop: (event) ->
['x', 'y'].forEach (key) ->
$("#user_avatar_crop_#{key}").val(Math.floor(event[key]))
$("#user_avatar_crop_size").val(Math.floor(event.width))
), 0
$modalCrop.on 'hidden.bs.modal', ->
$modalCropImg.attr('src', '').cropper('destroy')
$avatarInput.val('')
$filename.text($filename.data('label'))
$('.js-upload-user-avatar').on 'click', ->
$('.edit-user').submit()
$('.js-choose-user-avatar-button').bind "click", ->
form = $(this).closest("form")
form.find(".js-user-avatar-input").click()
$avatarInput.on "change", ->
$('.js-user-avatar-input').bind "change", ->
form = $(this).closest("form")
filename = $(this).val().replace(/^.*[\\\/]/, '')
$filename.data('label', $filename.text()).text(filename)
reader = new FileReader
reader.onload = (event) ->
$modalCrop.modal('show')
$modalCropImg.attr('src', event.target.result)
fileData = reader.readAsDataURL(this.files[0])
form.find(".js-avatar-filename").text(filename)
$ ->
# Extract the SSH Key title from its comment
......
......@@ -11,7 +11,6 @@ class @Project
$(@).toggleClass('active')
url = $("#project_clone").val()
console.log("url",url)
# Update the input field
$('#project_clone').val(url)
......
......@@ -3,3 +3,16 @@ class @ProjectNew
$('.project-edit-container').on 'ajax:before', =>
$('.project-edit-container').hide()
$('.save-project-loader').show()
@toggleSettings()
@toggleSettingsOnclick()
toggleSettings: ->
checked = $("#project_builds_enabled").prop("checked")
if checked
$('.builds-feature').show()
else
$('.builds-feature').hide()
toggleSettingsOnclick: ->
$("#project_builds_enabled").on 'click', @toggleSettings
......@@ -2,6 +2,7 @@
init: ->
$(".projects-list-filter").off('keyup')
this.initSearch()
this.initPagination()
initSearch: ->
@timer = null
......@@ -29,3 +30,8 @@
# Change url so if user reload a page - search results are saved
history.replaceState {page: project_filter_url}, document.title, project_filter_url
dataType: "json"
initPagination: ->
$('.projects-list-holder .pagination').on('ajax:success', (e, data) ->
$('.projects-list-holder').replaceWith(data.html)
)
......@@ -4,11 +4,15 @@ class @Shortcuts
Mousetrap.reset()
Mousetrap.bind('?', @selectiveHelp)
Mousetrap.bind('s', Shortcuts.focusSearch)
Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview)
Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL?
selectiveHelp: (e) =>
Shortcuts.showHelp(e, @enabledHelp)
toggleMarkdownPreview: (e) =>
$(document).triggerHandler('markdown-preview:toggle', [e])
@showHelp: (e, location) ->
if $('#modal-shortcuts').length > 0
$('#modal-shortcuts').modal('show')
......@@ -35,3 +39,14 @@ $(document).on 'click.more_help', '.js-more-help-button', (e) ->
$(@).remove()
$('.hidden-shortcut').show()
e.preventDefault()
Mousetrap.stopCallback = (->
defaultStopCallback = Mousetrap.stopCallback
return (e, element, combo) ->
# allowed shortcuts if textarea, input, contenteditable are focused
if ['ctrl+shift+p', 'command+shift+p'].indexOf(combo) != -1
return false
else
return defaultStopCallback.apply(@, arguments)
)()
$(document).on("click", '.toggle-nav-collapse', (e) ->
e.preventDefault()
collapsed = 'page-sidebar-collapsed'
expanded = 'page-sidebar-expanded'
collapsed = 'page-sidebar-collapsed'
expanded = 'page-sidebar-expanded'
toggleSidebar = ->
$('.page-with-sidebar').toggleClass("#{collapsed} #{expanded}")
$('header').toggleClass("header-collapsed header-expanded")
$('.sidebar-wrapper').toggleClass("sidebar-collapsed sidebar-expanded")
......@@ -14,4 +13,15 @@ $(document).on("click", '.toggle-nav-collapse', (e) ->
niceScrollBars.updateScrollBar();
), 300
$(document).on("click", '.toggle-nav-collapse', (e) ->
e.preventDefault()
toggleSidebar()
)
$ ->
size = bp.getBreakpointSize()
if size is "xs" or size is "sm"
if $('.page-with-sidebar').hasClass(expanded)
toggleSidebar()
class @Subscription
constructor: (url) ->
$(".subscribe-button").unbind("click").click (event)=>
btn = $(event.currentTarget)
action = btn.find("span").text()
current_status = $(".subscription-status").attr("data-status")
btn.prop("disabled", true)
$.post url, =>
btn.prop("disabled", false)
status = if current_status == "subscribed" then "unsubscribed" else "subscribed"
$(".subscription-status").attr("data-status", status)
action = if status == "subscribed" then "Unsubscribe" else "Subscribe"
btn.find("span").text(action)
$(".subscription-status>div").toggleClass("hidden")
constructor: (container) ->
$container = $(container)
@url = $container.attr('data-url')
@subscribe_button = $container.find('.subscribe-button')
@subscription_status = $container.find('.subscription-status')
@subscribe_button.unbind('click').click(@toggleSubscription)
toggleSubscription: (event) =>
btn = $(event.currentTarget)
action = btn.find('span').text()
current_status = @subscription_status.attr('data-status')
btn.prop('disabled', true)
$.post @url, =>
btn.prop('disabled', false)
status = if current_status == 'subscribed' then 'unsubscribed' else 'subscribed'
@subscription_status.attr('data-status', status)
action = if status == 'subscribed' then 'Unsubscribe' else 'Subscribe'
btn.find('span').text(action)
@subscription_status.find('>div').toggleClass('hidden')
class @Todos
constructor: (@name) ->
@clearListeners()
@initBtnListeners()
clearListeners: ->
$('.done-todo').off('click')
$('.js-todos-mark-all').off('click')
initBtnListeners: ->
$('.done-todo').on('click', @doneClicked)
$('.js-todos-mark-all').on('click', @allDoneClicked)
doneClicked: (e) =>
e.preventDefault()
e.stopImmediatePropagation()
$this = $(e.currentTarget)
$this.disable()
$.ajax
type: 'POST'
url: $this.attr('href')
dataType: 'json'
data: '_method': 'delete'
success: (data) =>
@clearDone $this.closest('li')
@updateBadges data
allDoneClicked: (e) =>
e.preventDefault()
e.stopImmediatePropagation()
$this = $(e.currentTarget)
$this.disable()
$.ajax
type: 'POST'
url: $this.attr('href')
dataType: 'json'
data: '_method': 'delete'
success: (data) =>
$this.remove()
$('.js-todos-list').remove()
@updateBadges data
clearDone: ($row) ->
$ul = $row.closest('ul')
$row.remove()
if not $ul.find('li').length
$ul.parents('.panel').remove()
updateBadges: (data) ->
$('.todos-pending .badge, .todos-pending-count').text data.count
$('.todos-done .badge').text data.done_count
......@@ -3,6 +3,94 @@ class @UsersSelect
@usersPath = "/autocomplete/users.json"
@userPath = "/autocomplete/users/:id.json"
$('.js-user-search').each (i, dropdown) =>
$dropdown = $(dropdown)
@projectId = $dropdown.data('project-id')
@showCurrentUser = $dropdown.data('current-user')
showNullUser = $dropdown.data('null-user')
showAnyUser = $dropdown.data('any-user')
firstUser = $dropdown.data('first-user')
selectedId = $dropdown.data('selected')
defaultLabel = $dropdown.data('default-label')
$dropdown.glDropdown(
data: (term, callback) =>
@users term, (users) =>
if term.length is 0
showDivider = 0
if firstUser
# Move current user to the front of the list
for obj, index in users
if obj.username == firstUser
users.splice(index, 1)
users.unshift(obj)
break
if showNullUser
showDivider += 1
users.unshift(
name: 'Unassigned',
id: 0
)
if showAnyUser
showDivider += 1
name = showAnyUser
name = 'Any User' if name == true
anyUser = {
name: name,
id: null
}
users.unshift(anyUser)
if showDivider
users.splice(showDivider, 0, "divider")
# Send the data back
callback users
filterable: true
filterRemote: true
search:
fields: ['name', 'username']
selectable: true
fieldName: $dropdown.data('field-name')
toggleLabel: (selected) ->
if selected && 'id' of selected
selected.name
else
defaultLabel
clicked: ->
page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
Issues.filterResults $dropdown.closest('form')
else if $dropdown.hasClass 'js-filter-submit'
$dropdown.closest('form').submit()
renderRow: (user) ->
username = if user.username then "@#{user.username}" else ""
avatar = if user.avatar_url then user.avatar_url else false
selected = if user.id is selectedId then "is-active" else ""
img = ""
if avatar
img = "<img src='#{avatar}' class='avatar avatar-inline' width='30' />"
"<li>
<a href='#' class='dropdown-menu-user-link #{selected}'>
#{img}
<strong class='dropdown-menu-user-full-name'>
#{user.name}
</strong>
<span class='dropdown-menu-user-username'>
#{username}
</span>
</a>
</li>"
)
$('.ajax-users-select').each (i, select) =>
@projectId = $(select).data('project-id')
@groupId = $(select).data('group-id')
......
......@@ -9,7 +9,6 @@
*= require_self
*= require dropzone/basic
*= require cal-heatmap
*= require cropper.css
*/
/*
......
......@@ -16,7 +16,7 @@
}
&.group-avatar, &.project-avatar, &.avatar-tile {
@include border-radius(0px);
@include border-radius(0);
}
&.s16 { width: 16px; height: 16px; margin-right: 6px; }
......
......@@ -23,7 +23,7 @@
margin-bottom: -$gl-padding;
background-color: $background-color;
padding: $gl-padding;
margin-bottom: 0px;
margin-bottom: 0;
border-top: 1px solid $border-color;
border-bottom: 1px solid $border-color;
color: $gl-gray;
......@@ -116,6 +116,10 @@
.cover-desc {
padding: 0 $gl-padding 3px;
color: $gl-text-color;
&.username:last-child {
padding-bottom: $gl-padding;
}
}
.cover-controls {
......@@ -153,3 +157,7 @@
float: right;
}
}
.content-block-small {
padding: 10px 0;
}
......@@ -37,23 +37,23 @@
}
@mixin btn-green {
@include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #FFFFFF);
@include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #fff);
}
@mixin btn-blue {
@include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #FFFFFF);
@include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #fff);
}
@mixin btn-blue-medium {
@include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #FFFFFF);
@include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #fff);
}
@mixin btn-orange {
@include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #FFFFFF);
@include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #fff);
}
@mixin btn-red {
@include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #FFFFFF);
@include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #fff);
}
@mixin btn-gray {
......@@ -127,7 +127,7 @@
margin-right: 7px;
float: left;
&:last-child {
margin-right: 0px;
margin-right: 0;
}
&.btn-xs {
margin-right: 3px;
......@@ -139,7 +139,6 @@
.caret {
margin-left: 5px;
color: $gray-darkest;
}
}
......@@ -170,7 +169,7 @@
margin-right: 7px;
float: left;
&:last-child {
margin-right: 0px;
margin-right: 0;
}
}
}
......@@ -209,3 +208,13 @@
background-color: #e4e7ed !important;
}
}
.btn-loading {
&:not(.disabled) .fa {
display: none;
}
.fa {
margin-right: 5px;
}
}
......@@ -33,19 +33,19 @@
}
.q2 {
fill: #ACD5F2 !important;
fill: #acd5f2 !important;
}
.q3 {
fill: #7FA8D1 !important;
fill: #7fa8d1 !important;
}
.q4 {
fill: #49729B !important;
fill: #49729b !important;
}
.q5 {
fill: #254E77 !important;
fill: #254e77 !important;
}
.domain-background {
......
......@@ -39,6 +39,6 @@
}
.bs-callout-success {
background-color: #dff0d8;
border-color: #5cA64d;
border-color: #5ca64d;
color: #3c763d;
}
/** COLORS **/
.cgray { color: $gl-gray; }
.clgray { color: #BBB }
.clgray { color: #bbb }
.cred { color: $gl-text-red; }
.cgreen { color: $gl-text-green; }
.cdark { color: #444 }
......@@ -8,18 +8,20 @@
/** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; }
.prepend-top-5 { margin-top: 5px; }
.prepend-top-10 { margin-top:10px }
.prepend-top-10 { margin-top: 10px }
.prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-20 { margin-top:20px }
.prepend-left-10 { margin-left:10px }
.prepend-left-default { margin-left:$gl-padding }
.prepend-left-20 { margin-left:20px }
.prepend-top-20 { margin-top: 20px }
.prepend-left-10 { margin-left: 10px }
.prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px }
.append-right-5 { margin-right: 5px }
.append-right-10 { margin-right:10px }
.append-right-20 { margin-right:20px }
.append-bottom-10 { margin-bottom:10px }
.append-bottom-15 { margin-bottom:15px }
.append-bottom-20 { margin-bottom:20px }
.append-right-10 { margin-right: 10px }
.append-right-default { margin-right: $gl-padding; }
.append-right-20 { margin-right: 20px }
.append-bottom-0 { margin-bottom: 0 }
.append-bottom-10 { margin-bottom: 10px }
.append-bottom-15 { margin-bottom: 15px }
.append-bottom-20 { margin-bottom: 20px }
.append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block }
.center { text-align: center }
......@@ -49,7 +51,7 @@ pre {
}
&.well-pre {
border: 1px solid #EEE;
border: 1px solid #eee;
background: #f9f9f9;
border-radius: 0;
color: #555;
......@@ -101,7 +103,7 @@ span.update-author {
}
.user-mention {
color: #2FA0BB;
color: #2fa0bb;
font-weight: bold;
}
......@@ -132,10 +134,10 @@ p.time {
// Fix issue with notes & lists creating a bunch of bottom borders.
li.note {
img { max-width:100% }
img { max-width: 100% }
.note-title {
li {
border-bottom:none !important;
border-bottom: none !important;
}
}
}
......@@ -185,9 +187,9 @@ li.note {
.error-message {
padding: 10px;
background: #C67;
background: #c67;
margin: 0;
color: #FFF;
color: #fff;
a {
color: #fff;
......@@ -198,7 +200,7 @@ li.note {
.browser-alert {
padding: 10px;
text-align: center;
background: #C67;
background: #c67;
color: #fff;
font-weight: bold;
a {
......@@ -269,7 +271,7 @@ img.emoji {
table {
td.permission-x {
background: #D9EDF7 !important;
background: #d9edf7 !important;
text-align: center;
}
}
......@@ -278,7 +280,7 @@ table {
float: left;
text-align: center;
font-size: 32px;
color: #AAA;
color: #aaa;
width: 60px;
}
......@@ -345,7 +347,7 @@ table {
.profiler-button,
.profiler-controls {
border-color: #EEE !important;
border-color: #eee !important;
}
}
......
......@@ -4,11 +4,17 @@
height: 0;
margin-left: 2px;
vertical-align: middle;
border-top: $caret-width-base dashed $dropdown-caret-color;
border-top: $caret-width-base dashed;
border-right: $caret-width-base solid transparent;
border-left: $caret-width-base solid transparent;
}
.btn-group {
.caret {
margin-left: 0;
}
}
.dropdown {
position: relative;
}
......@@ -17,6 +23,47 @@
.dropdown-menu {
display: block;
}
.dropdown-menu-toggle {
border-color: $dropdown-toggle-hover-border-color;
.fa {
color: $dropdown-toggle-hover-icon-color;
}
}
}
.dropdown-menu-toggle {
position: relative;
width: 160px;
padding: 6px 20px 6px 10px;
background-color: $dropdown-toggle-bg;
color: $dropdown-toggle-color;
font-size: 15px;
text-align: left;
border: 1px solid $dropdown-toggle-border-color;
border-radius: 2px;
outline: 0;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
.fa {
position: absolute;
top: 50%;
right: 6px;
margin-top: -4px;
color: $dropdown-toggle-icon-color;
font-size: 10px;
}
&:hover, {
border-color: $dropdown-toggle-hover-border-color;
.fa {
color: $dropdown-toggle-hover-icon-color;
}
}
}
.dropdown-menu {
......@@ -24,7 +71,7 @@
position: absolute;
top: 100%;
left: 0;
z-index: 9999;
z-index: 9;
width: 240px;
margin-top: 2px;
margin-bottom: 0;
......@@ -36,6 +83,21 @@
border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
&.is-loading {
.dropdown-content {
display: none;
}
.dropdown-loading {
display: block;
}
}
ul {
margin: 0;
padding: 0;
}
li {
text-align: left;
list-style: none;
......@@ -61,13 +123,69 @@
white-space: nowrap;
overflow: hidden;
&:hover {
&:hover,
&:focus,
&.is-focused {
background-color: $dropdown-link-hover-bg;
text-decoration: none;
outline: 0;
}
}
}
.dropdown-menu-paging {
.dropdown-page-two,
.dropdown-menu-back {
display: none;
}
&.is-page-two {
.dropdown-page-one {
display: none;
}
.dropdown-page-two,
.dropdown-menu-back {
display: block;
}
}
}
.dropdown-menu-user {
.avatar {
float: left;
width: 30px;
height: 30px;
margin: 0 10px 0 0;
}
}
.dropdown-menu-user-link {
padding-top: 7px;
padding-bottom: 7px;
}
.dropdown-menu-user-full-name {
display: block;
font-weight: 600;
line-height: 16px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.dropdown-menu-user-username {
display: block;
line-height: 16px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.dropdown-select {
width: 280px;
}
.dropdown-menu-align-right {
left: auto;
right: 0;
......@@ -81,8 +199,9 @@
&::before {
content: "\f00c";
position: absolute;
left: 4px;
top: 8px;
left: 5px;
top: 50%;
margin-top: -7px;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
......@@ -94,9 +213,136 @@
}
.dropdown-header {
padding-left: 10px;
padding-right: 10px;
padding-left: 5px;
padding-right: 5px;
color: $dropdown-header-color;
font-size: 13px;
line-height: 22px;
}
.dropdown-title {
position: relative;
margin-bottom: 10px;
padding-left: 30px;
padding-right: 30px;
padding-bottom: 10px;
font-weight: 600;
line-height: 1;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
border-bottom: 1px solid $dropdown-divider-color;
overflow: hidden;
}
.dropdown-title-button {
position: absolute;
top: -1px;
padding: 0;
color: $dropdown-title-btn-color;
font-size: 14px;
border: 0;
background: none;
outline: 0;
&:hover {
color: darken($dropdown-title-btn-color, 15%);
}
}
.dropdown-menu-close {
right: 0;
}
.dropdown-menu-back {
left: 0;
}
.dropdown-input {
position: relative;
margin-bottom: 10px;
.fa {
position: absolute;
top: 10px;
right: 10px;
color: #c7c7c7;
font-size: 12px;
pointer-events: none;
}
}
.dropdown-input-field {
width: 100%;
padding: 0 7px;
color: $dropdown-input-color;
line-height: 30px;
border: 1px solid $dropdown-divider-color;
border-radius: 2px;
outline: 0;
&:focus {
color: $dropdown-link-color;
border-color: $dropdown-input-focus-border;
box-shadow: 0 0 4px $dropdown-input-focus-shadow;
+ .fa {
color: $dropdown-link-color;
}
}
&:hover {
+ .fa {
color: $dropdown-link-color;
}
}
}
.dropdown-content {
max-height: 215px;
overflow-y: scroll;
}
.dropdown-footer {
padding-top: 10px;
margin-top: 10px;
font-size: 13px;
border-top: 1px solid $dropdown-divider-color;
}
.dropdown-footer-list {
font-size: 14px;
a {
padding-left: 10px;
}
}
.dropdown-loading {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
z-index: 9;
background-color: $dropdown-loading-bg;
font-size: 28px;
.fa {
position: absolute;
top: 50%;
left: 50%;
margin-top: -14px;
margin-left: -14px;
}
}
.dropdown-menu-labels {
.label {
position: relative;
width: 30px;
margin-right: 5px;
text-indent: -99999px;
}
}
......@@ -30,7 +30,7 @@
right: 15px;
.btn {
padding: 0px 10px;
padding: 0 10px;
font-size: 13px;
line-height: 28px;
}
......@@ -84,7 +84,7 @@
&.blob-no-preview {
background: #eee;
text-shadow: 0 1px 2px #FFF;
text-shadow: 0 1px 2px #fff;
padding: 100px 0;
}
......@@ -124,7 +124,7 @@
}
td.line-numbers {
float: none;
border-left: 1px solid #DDD;
border-left: 1px solid #ddd;
}
td.lines {
padding: 0;
......@@ -169,6 +169,7 @@
*/
&.code {
padding: 0;
-webkit-overflow-scrolling: auto; // See https://gitlab.com/gitlab-org/gitlab-ce/issues/13987
}
}
}
......
.filter-item {
margin-right: 6px;
vertical-align: top;
}
@media (min-width: 800px) {
@media (min-width: $screen-sm-min) {
.issues-filters,
.issues_bulk_update {
select, .select2-container {
width: 120px !important;
display: inline-block;
}
}
}
@media (min-width: 1200px) {
.issues-filters,
.issues_bulk_update {
select, .select2-container {
width: 150px !important;
display: inline-block;
.dropdown-menu-toggle {
width: 132px;
}
}
}
......@@ -41,8 +41,8 @@ input[type='search'].search-input {
}
input[type='text'].danger {
background: #F2DEDE!important;
border-color: #D66;
background: #f2dede!important;
border-color: #d66;
text-shadow: 0 1px 1px #fff
}
......
......@@ -23,13 +23,13 @@
&:hover {
background-color: $color-darker;
a {
color: #FFF;
color: #fff;
}
}
}
.collapse-nav a {
color: #FFF;
color: #fff;
background: $color;
}
......@@ -42,7 +42,7 @@
&:hover {
background-color: $color-dark;
color: #FFF;
color: #fff;
text-decoration: none;
}
}
......@@ -71,7 +71,7 @@
}
&.active a {
color: #FFF;
color: #fff;
background: $color-dark;
&.no-highlight {
......@@ -79,42 +79,42 @@
}
i {
color: #FFF
color: #fff
}
}
}
}
}
$theme-blue: #2980B9;
$theme-blue: #2980b9;
$theme-charcoal: #333c47;
$theme-graphite: #888888;
$theme-graphite: #888;
$theme-gray: #373737;
$theme-green: #019875;
$theme-violet: #554488;
$theme-violet: #548;
body {
&.ui_blue {
@include gitlab-theme(#BECDE9, $theme-blue, #1970A9, #096099);
@include gitlab-theme(#becde9, $theme-blue, #1970a9, #096099);
}
&.ui_charcoal {
@include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272D);
@include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272d);
}
&.ui_graphite {
@include gitlab-theme(#CCCCCC, $theme-graphite, #777777, #666666);
@include gitlab-theme(#ccc, $theme-graphite, #777, #666);
}
&.ui_gray {
@include gitlab-theme(#979797, $theme-gray, #272727, #222222);
@include gitlab-theme(#979797, $theme-gray, #272727, #222);
}
&.ui_green {
@include gitlab-theme(#AADDCC, $theme-green, #018865, #017855);
@include gitlab-theme(#adc, $theme-green, #018865, #017855);
}
&.ui_violet {
@include gitlab-theme(#9988CC, $theme-violet, #443366, #332255);
@include gitlab-theme(#98c, $theme-violet, #436, #325);
}
}
\ No newline at end of file
......@@ -7,8 +7,8 @@ header {
&.navbar-empty {
height: 58px;
background: #FFF;
border-bottom: 1px solid #EEE;
background: #fff;
border-bottom: 1px solid #eee;
.center-logo {
margin: 11px 0;
......@@ -28,7 +28,7 @@ header {
min-height: $header-height;
background-color: #fff;
border: none;
border-bottom: 1px solid #EEE;
border-bottom: 1px solid #eee;
.container-fluid {
width: 100% !important;
......@@ -47,7 +47,7 @@ header {
text-align: center;
&:hover, &:focus, &:active {
background-color: #FFF;
background-color: #fff;
}
}
......@@ -59,7 +59,7 @@ header {
right: 2px;
&:hover {
background-color: #EEE;
background-color: #eee;
}
&.active {
color: #7f8fa4;
......@@ -141,22 +141,18 @@ header {
margin-left: $sidebar_collapsed_width;
}
@media (max-width: $screen-md-max) {
.header-collapsed {
margin-left: $sidebar_collapsed_width;
}
.header-expanded {
margin-left: $sidebar_width;
}
}
.header-collapsed {
margin-left: $sidebar_collapsed_width;
@media(min-width: $screen-md-max) {
.header-collapsed {
@media (min-width: $screen-md-min) {
@include collapsed-header;
}
}
.header-expanded {
margin-left: $sidebar_collapsed_width;
.header-expanded {
@media (min-width: $screen-md-min) {
margin-left: $sidebar_width;
}
}
......@@ -166,7 +162,7 @@ header {
font-size: 18px;
.navbar-nav {
margin: 0px;
margin: 0;
float: none !important;
.visible-xs, .visable-sm {
......
.file-content.code {
border: none;
box-shadow: none;
margin: 0px;
padding: 0px;
margin: 0;
padding: 0;
table-layout: fixed;
pre {
......
......@@ -20,7 +20,7 @@
display: block;
float: left;
margin-right: 10px;
color: #FFF;
color: #fff;
font-size: $gl-font-size;
line-height: 25px;
......
......@@ -3,13 +3,13 @@
font-size: $font-size-base;
&.ui-datepicker-inline {
border: 1px solid #DDD;
border: 1px solid #ddd;
padding: 10px;
width: 270px;
.ui-datepicker-header {
background: #FFF;
border-color: #DDD;
background: #fff;
border-color: #ddd;
}
.ui-datepicker-calendar td a {
......@@ -19,7 +19,7 @@
}
&.ui-autocomplete {
border-color: #DDD;
border-color: #ddd;
padding: 0;
margin-top: 2px;
z-index: 1001;
......@@ -30,20 +30,20 @@
}
.ui-state-default {
border: 1px solid #FFF;
background: #FFF;
border: 1px solid #fff;
background: #fff;
color: #777;
}
.ui-state-highlight {
border: 1px solid #EEE;
background: #EEE;
border: 1px solid #eee;
background: #eee;
}
.ui-state-active {
border: 1px solid $gl-primary;
background: $gl-primary;
color: #FFF;
color: #fff;
}
.ui-state-hover,
......
......@@ -111,14 +111,17 @@ ul.content-list {
> li {
border-color: $table-border-color;
color: $list-text-color;
font-size: $list-font-size;
color: $list-text-color;
.title {
color: $list-title-color;
font-weight: 600;
}
a {
color: $gl-dark-link-color;
}
.description {
p {
@include str-truncated;
......@@ -141,6 +144,10 @@ ul.content-list {
}
}
.panel > .content-list > li {
padding: $gl-padding-top $gl-padding;
}
ul.controls {
padding-top: 1px;
float: right;
......
......@@ -71,7 +71,7 @@
}
.md-preview-holder {
background: #FFF;
background: #fff;
border: 1px solid #ddd;
min-height: 169px;
padding: 5px;
......@@ -80,7 +80,7 @@
.markdown-area {
@include border-radius(0);
background: #FFF;
background: #fff;
border: 1px solid #ddd;
min-height: 140px;
max-height: 500px;
......
......@@ -41,12 +41,6 @@
transition: $transition;
}
@mixin transform($transform) {
-webkit-transform: $transform;
-ms-transform: $transform;
transform: $transform;
}
/**
* Prefilled mixins
* Mixins with fixed values
......@@ -73,17 +67,17 @@
* Base mixin for lists in GitLab
*/
@mixin basic-list {
margin: 5px 0px;
padding: 0px;
margin: 5px 0;
padding: 0;
list-style: none;
> li {
@include clearfix;
padding: 10px 0;
border-bottom: 1px solid #EEE;
border-bottom: 1px solid #eee;
display: block;
margin: 0px;
margin: 0;
&:last-child {
border-bottom: none;
......
......@@ -128,12 +128,12 @@
.show-aside {
display: none;
position: fixed;
right: 0px;
right: 0;
top: 30%;
padding: 5px 15px;
background: #EEE;
background: #eee;
font-size: 20px;
color: #777;
z-index: 100;
@include box-shadow(0 1px 2px #DDD);
@include box-shadow(0 1px 2px #ddd);
}
This diff is collapsed.
......@@ -95,7 +95,7 @@
}
&.label-inverse {
background-color: #333333;
background-color: #333;
}
}
......@@ -138,7 +138,7 @@
}
.btn-clipboard {
min-width: 0px;
min-width: 0;
}
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment