diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000000..ee4c391da30 --- /dev/null +++ b/.babelrc @@ -0,0 +1,21 @@ +{ + "presets": [ + ["latest", { "es2015": { "modules": false } }], + "stage-2" + ], + "env": { + "coverage": { + "plugins": [ + ["istanbul", { + "exclude": [ + "app/assets/javascripts/droplab/**/*", + "spec/javascripts/**/*" + ] + }], + ["transform-define", { + "process.env.BABEL_ENV": "coverage" + }] + ] + } + } +} diff --git a/.eslintrc b/.eslintrc index 0fcd866778f..b0ae2a31919 100644 --- a/.eslintrc +++ b/.eslintrc @@ -23,7 +23,7 @@ } }, "rules": { - "filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"], + "filenames/match-regex": [2, "^[a-z0-9_]+$"], "no-multiple-empty-lines": ["error", { "max": 1 }] } } diff --git a/.flayignore b/.flayignore index fc64b0b5892..47597025115 100644 --- a/.flayignore +++ b/.flayignore @@ -2,3 +2,4 @@ lib/gitlab/sanitizers/svg/whitelist.rb lib/gitlab/diff/position_tracer.rb app/policies/project_policy.rb +app/models/concerns/relative_positioning.rb diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 70cce05d2b5..00000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.js.es6 gitlab-language=javascript diff --git a/.gitignore b/.gitignore index 5e9f19d8319..51b4d06b01b 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,4 @@ eslint-report.html /builds/* /shared/* /.gitlab_workhorse_secret +/webpack-report/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 433b3119fba..34c10b3b77f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,8 +7,6 @@ cache: variables: MYSQL_ALLOW_EMPTY_PASSWORD: "1" - # retry tests only in CI environment - RSPEC_RETRY_RETRY_COUNT: "3" RAILS_ENV: "test" SIMPLECOV: "true" SETUP_DB: "true" @@ -60,7 +58,7 @@ stages: <<: *dedicated-runner <<: *use-db script: - - JOB_NAME=( $CI_BUILD_NAME ) + - JOB_NAME=( $CI_JOB_NAME ) - export CI_NODE_INDEX=${JOB_NAME[1]} - export CI_NODE_TOTAL=${JOB_NAME[2]} - export KNAPSACK_REPORT_PATH=knapsack/rspec_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json @@ -69,16 +67,18 @@ stages: - knapsack rspec "--color --format documentation" artifacts: expire_in: 31d + when: always paths: - - knapsack/ - coverage/ + - knapsack/ + - tmp/capybara/ .spinach-knapsack: &spinach-knapsack stage: test <<: *dedicated-runner <<: *use-db script: - - JOB_NAME=( $CI_BUILD_NAME ) + - JOB_NAME=( $CI_JOB_NAME ) - export CI_NODE_INDEX=${JOB_NAME[1]} - export CI_NODE_TOTAL=${JOB_NAME[2]} - export KNAPSACK_REPORT_PATH=knapsack/spinach_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json @@ -87,9 +87,11 @@ stages: - knapsack spinach "-r rerun" || retry '[[ -e tmp/spinach-rerun.txt ]] && bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)' artifacts: expire_in: 31d + when: always paths: - - knapsack/ - coverage/ + - knapsack/ + - tmp/capybara/ # Prepare and merge knapsack tests @@ -178,7 +180,7 @@ spinach 9 10: *spinach-knapsack <<: *dedicated-runner stage: test script: - - bundle exec $CI_BUILD_NAME + - bundle exec $CI_JOB_NAME rubocop: <<: *ruby-static-analysis @@ -209,7 +211,7 @@ rake ee_compat_check: - ee_compat_check/repo/ - vendor/ruby artifacts: - name: "${CI_BUILD_NAME}_${CI_BUILD_REF_NAME}_${CI_BUILD_REF}" + name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}" when: on_failure expire_in: 10d paths: @@ -222,6 +224,14 @@ rake db:migrate:reset: script: - bundle exec rake db:migrate:reset +rake db:rollback: + stage: test + <<: *use-db + <<: *dedicated-runner + script: + - bundle exec rake db:rollback STEP=120 + - bundle exec rake db:migrate + rake db:seed_fu: stage: test <<: *use-db @@ -240,6 +250,25 @@ rake db:seed_fu: paths: - log/development.log +rake gitlab:assets:compile: + stage: test + <<: *dedicated-runner + dependencies: [] + variables: + NODE_ENV: "production" + RAILS_ENV: "production" + SETUP_DB: "false" + USE_DB: "false" + SKIP_STORAGE_VALIDATION: "true" + WEBPACK_REPORT: "true" + script: + - bundle exec rake yarn:install gitlab:assets:compile + artifacts: + name: webpack-report + expire_in: 31d + paths: + - webpack-report/ + rake karma: cache: paths: @@ -248,6 +277,8 @@ rake karma: stage: test <<: *use-db <<: *dedicated-runner + variables: + BABEL_ENV: "coverage" script: - bundle exec rake karma artifacts: @@ -281,7 +312,7 @@ bundler:audit: - master@gitlab/gitlabhq - master@gitlab/gitlab-ee script: - - "bundle exec bundle-audit check --update --ignore OSVDB-115941" + - "bundle exec bundle-audit check --update" migration paths: stage: test @@ -301,7 +332,7 @@ migration paths: - sed -i 's/localhost/redis/g' config/resque.yml - bundle install --without postgres production --jobs $(nproc) $FLAGS --retry=3 - bundle exec rake db:drop db:create db:schema:load db:seed_fu - - git checkout $CI_BUILD_REF + - git checkout $CI_COMMIT_SHA - source scripts/prepare_build.sh - bundle exec rake db:migrate @@ -339,7 +370,7 @@ lint:javascript:report: stage: post-test before_script: [] script: - - find app/ spec/ -name '*.js' -or -name '*.js.es6' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files + - find app/ spec/ -name '*.js' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files - yarn run eslint-report || true # ignore exit code artifacts: name: eslint-report @@ -360,12 +391,13 @@ trigger_docs: cache: {} artifacts: {} script: - - "curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master -F variables[PROJECT]=ce https://gitlab.com/api/v3/projects/1794617/trigger/builds" + - "HTTP_STATUS=$(curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master -F variables[PROJECT]=${CI_PROJECT_NAME} --silent --output curl.log --write-out '%{http_code}' https://gitlab.com/api/v3/projects/1794617/trigger/builds)" + - if [ "${HTTP_STATUS}" -ne "201" ]; then echo "Error ${HTTP_STATUS}"; cat curl.log; echo; exit 1; fi only: - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee # Notify slack in the end - notify:slack: stage: post-test <<: *dedicated-runner @@ -373,7 +405,7 @@ notify:slack: SETUP_DB: "false" USE_BUNDLE_INSTALL: "false" script: - - ./scripts/notify_slack.sh "#development" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See " + - ./scripts/notify_slack.sh "#development" "Build on \`$CI_COMMIT_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See " when: on_failure only: - master@gitlab-org/gitlab-ce @@ -388,6 +420,7 @@ pages: dependencies: - coverage - rake karma + - rake gitlab:assets:compile - lint:javascript:report script: - mv public/ .public/ @@ -395,11 +428,13 @@ pages: - mv coverage/ public/coverage-ruby/ || true - mv coverage-javascript/ public/coverage-javascript/ || true - mv eslint-report.html public/ || true + - mv webpack-report/ public/webpack-report/ || true artifacts: paths: - public only: - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee # Insurance in case a gem needed by one of our releases gets yanked from # rubygems.org in the future. @@ -416,3 +451,4 @@ cache gems: - vendor/cache only: - master@gitlab-org/gitlab-ce + - master@gitlab-org/gitlab-ee diff --git a/.gitlab/issue_templates/Feature Proposal.md b/.gitlab/issue_templates/Feature Proposal.md index ea895ee6275..2636010e2fb 100644 --- a/.gitlab/issue_templates/Feature Proposal.md +++ b/.gitlab/issue_templates/Feature Proposal.md @@ -5,3 +5,13 @@ ### Proposal ### Links / references + +### Documentation blurb + +(Write the start of the documentation of this feature here, include: + +1. Why should someone use it; what's the underlying problem. +2. What is the solution. +3. How does someone use this + +During implementation, this can then be copied and used as a starter for the documentation.) diff --git a/.rubocop.yml b/.rubocop.yml index a836b469cc7..fa1370ea1f3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -22,14 +22,12 @@ AllCops: - 'db/fixtures/**/*' - 'tmp/**/*' - 'bin/**/*' - - 'lib/backup/**/*' - - 'lib/ci/backup/**/*' - - 'lib/tasks/**/*' - - 'lib/ci/migrate/**/*' - - 'lib/email_validator.rb' - - 'lib/gitlab/upgrader.rb' - - 'lib/gitlab/seeder.rb' - 'generator_templates/**/*' + - 'builds/**/*' + +# Gems in consecutive lines should be alphabetically sorted +Bundler/OrderedGems: + Enabled: false # Style ####################################################################### @@ -54,6 +52,11 @@ Style/AlignArray: Style/AlignHash: Enabled: true +# Here we check if the parameters on a multi-line method call or +# definition are aligned. +Style/AlignParameters: + Enabled: false + # Whether `and` and `or` are banned only in conditionals (conditionals) # or completely (always). Style/AndOr: @@ -83,15 +86,24 @@ Style/BeginBlock: Style/BlockComments: Enabled: true -# Put end statement of multiline block on its own line. -Style/BlockEndNewline: - Enabled: true - # Avoid using {...} for multi-line blocks (multiline chaining is # always # ugly). Prefer {...} over do...end for single-line blocks. Style/BlockDelimiters: Enabled: true +# Put end statement of multiline block on its own line. +Style/BlockEndNewline: + Enabled: true + + # This cop checks for braces around the last parameter in a method call +# if the last parameter is a hash. +Style/BracesAroundHashParameters: + Enabled: false + +# This cop checks for uses of the case equality operator(===). +Style/CaseEquality: + Enabled: false + # Indentation of when in a case/when/[else/]end. Style/CaseIndentation: Enabled: true @@ -110,7 +122,7 @@ Style/ClassAndModuleChildren: # Enforces consistent use of `Object#is_a?` or `Object#kind_of?`. Style/ClassCheck: - Enabled: false + Enabled: true # Use self when defining module/class methods. Style/ClassMethods: @@ -120,10 +132,26 @@ Style/ClassMethods: Style/ClassVars: Enabled: true +# This cop checks for methods invoked via the :: operator instead +# of the . operator (like FileUtils::rmdir instead of FileUtils.rmdir). +Style/ColonMethodCall: + Enabled: true + +# This cop checks that comment annotation keywords are written according +# to guidelines. +Style/CommentAnnotation: + Enabled: false + # Indentation of comments. Style/CommentIndentation: Enabled: true +# Check for `if` and `case` statements where each branch is used for +# assignment to the same variable when using the return of the +# condition can be used instead. +Style/ConditionalAssignment: + Enabled: true + # Constants should use SCREAMING_SNAKE_CASE. Style/ConstantName: Enabled: true @@ -136,13 +164,19 @@ Style/DefWithParentheses: Style/Documentation: Enabled: false +# This cop checks for uses of double negation (!!) to convert something +# to a boolean value. As this is both cryptic and usually redundant, it +# should be avoided. +Style/DoubleNegation: + Enabled: false + # Align elses and elsifs correctly. Style/ElseAlignment: Enabled: true # Use empty lines between defs. Style/EmptyLineBetweenDefs: - Enabled: false + Enabled: true # Don't use several empty lines in a row. Style/EmptyLines: @@ -160,14 +194,14 @@ Style/EmptyLinesAroundBlockBody: Style/EmptyLinesAroundClassBody: Enabled: true -# Keeps track of empty lines around module bodies. -Style/EmptyLinesAroundModuleBody: - Enabled: true - # Keeps track of empty lines around method bodies. Style/EmptyLinesAroundMethodBody: Enabled: true +# Keeps track of empty lines around module bodies. +Style/EmptyLinesAroundModuleBody: + Enabled: true + # Avoid the use of END blocks. Style/EndBlock: Enabled: true @@ -200,24 +234,28 @@ Style/For: # Checks if there is a magic comment to enforce string literals Style/FrozenStringLiteralComment: Enabled: false + # Do not introduce global variables. Style/GlobalVars: Enabled: true + Exclude: + - 'lib/backup/**/*' + - 'lib/tasks/**/*' # Prefer Ruby 1.9 hash syntax `{ a: 1, b: 2 }` # over 1.8 syntax `{ :a => 1, :b => 2 }`. Style/HashSyntax: Enabled: true -# Do not use if x; .... Use the ternary operator instead. -Style/IfWithSemicolon: - Enabled: true - # Checks that conditional statements do not have an identical line at the # end of each branch, which can validly be moved out of the conditional. Style/IdenticalConditionalBranches: Enabled: true +# Do not use if x; .... Use the ternary operator instead. +Style/IfWithSemicolon: + Enabled: true + # Checks the indentation of the first line of the right-hand-side of a # multi-line assignment. Style/IndentAssignment: @@ -258,7 +296,7 @@ Style/ModuleFunction: # Checks that the closing brace in an array literal is either on the same line # as the last array element, or a new line. Style/MultilineArrayBraceLayout: - Enabled: false + Enabled: true EnforcedStyle: symmetrical # Avoid multi-line chains of blocks. @@ -272,7 +310,7 @@ Style/MultilineBlockLayout: # Checks that the closing brace in a hash literal is either on the same line as # the last hash element, or a new line. Style/MultilineHashBraceLayout: - Enabled: false + Enabled: true EnforcedStyle: symmetrical # Do not use then for multi-line if/unless. @@ -304,6 +342,14 @@ Style/MultilineOperationIndentation: Style/MultilineTernaryOperator: Enabled: true +# This cop checks whether some constant value isn't a +# mutable literal (e.g. array or hash). +Style/MutableConstant: + Enabled: true + Exclude: + - 'db/migrate/**/*' + - 'db/post_migrate/**/*' + # Favor unless over if for negative conditions (or control flow or). Style/NegatedIf: Enabled: true @@ -406,6 +452,10 @@ Style/SpaceBeforeComment: Style/SpaceBeforeSemicolon: Enabled: true +# Checks for spaces inside square brackets. +Style/SpaceInsideBrackets: + Enabled: true + # Use spaces inside hash literal braces - or don't. Style/SpaceInsideHashLiteralBraces: Enabled: true @@ -442,6 +492,10 @@ Style/Tab: Style/TrailingBlankLines: Enabled: true +# This cop checks for trailing comma in array and hash literals. +Style/TrailingCommaInLiteral: + Enabled: false + # Checks for %W when interpolation is not needed. Style/UnneededCapitalW: Enabled: true @@ -477,7 +531,7 @@ Style/WhileUntilModifier: # Use %w or %W for arrays of words. Style/WordArray: - Enabled: false + Enabled: true # Metrics ##################################################################### @@ -487,6 +541,10 @@ Metrics/AbcSize: Enabled: true Max: 60 +# This cop checks if the length of a block exceeds some maximum value. +Metrics/BlockLength: + Enabled: false + # Avoid excessive block nesting. Metrics/BlockNesting: Enabled: true @@ -526,20 +584,21 @@ Metrics/PerceivedComplexity: # Lint ######################################################################## -# Checks for useless access modifiers. -Lint/UselessAccessModifier: - Enabled: true - -# Checks for attempts to use `private` or `protected` to set the visibility -# of a class method, which does not work. -Lint/IneffectiveAccessModifier: - Enabled: false - # Checks for ambiguous operators in the first argument of a method invocation # without parentheses. Lint/AmbiguousOperator: Enabled: true +# This cop checks for ambiguous regexp literals in the first argument of +# a method invocation without parentheses. +Lint/AmbiguousRegexpLiteral: + Enabled: false + +# This cop checks for assignments in the conditions of +# if/while/until. +Lint/AssignmentInCondition: + Enabled: false + # Align block ends correctly. Lint/BlockAlignment: Enabled: true @@ -593,10 +652,6 @@ Lint/EndInMethod: Lint/EnsureReturn: Enabled: true -# The use of eval represents a serious security risk. -Lint/Eval: - Enabled: true - # Catches floating-point literals too large or small for Ruby to represent. Lint/FloatOutOfRange: Enabled: true @@ -605,11 +660,20 @@ Lint/FloatOutOfRange: Lint/FormatParameterMismatch: Enabled: true +# This cop checks for *rescue* blocks with no body. +Lint/HandleExceptions: + Enabled: false + # Checks for adjacent string literals on the same line, which could better be # represented as a single string literal. Lint/ImplicitStringConcatenation: Enabled: true +# Checks for attempts to use `private` or `protected` to set the visibility +# of a class method, which does not work. +Lint/IneffectiveAccessModifier: + Enabled: false + # Checks for invalid character literals with a non-escaped whitespace # character. Lint/InvalidCharacterLiteral: @@ -623,6 +687,10 @@ Lint/LiteralInCondition: Lint/LiteralInInterpolation: Enabled: true +# This cop checks for uses of *begin...end while/until something*. +Lint/Loop: + Enabled: false + # Do not use nested method definitions. Lint/NestedMethodDefinition: Enabled: true @@ -652,6 +720,11 @@ Lint/RescueException: Lint/ShadowedException: Enabled: false +# This cop looks for use of the same name as outer local variables +# for block arguments or block local variables. +Lint/ShadowingOuterLocalVariable: + Enabled: false + # Checks for Object#to_s usage in string interpolation. Lint/StringConversionInInterpolation: Enabled: true @@ -660,16 +733,36 @@ Lint/StringConversionInInterpolation: Lint/UnderscorePrefixedVariableName: Enabled: true +# This cop checks for using Fixnum or Bignum constant +Lint/UnifiedInteger: + Enabled: true + # Checks for rubocop:disable comments that can be removed. # Note: this cop is not disabled when disabling all cops. # It must be explicitly disabled. Lint/UnneededDisable: Enabled: false +# This cop checks for unneeded usages of splat expansion +Lint/UnneededSplatExpansion: + Enabled: false + # Unreachable code. Lint/UnreachableCode: Enabled: true +# This cop checks for unused block arguments. +Lint/UnusedBlockArgument: + Enabled: false + +# This cop checks for unused method arguments. +Lint/UnusedMethodArgument: + Enabled: false + +# Checks for useless access modifiers. +Lint/UselessAccessModifier: + Enabled: true + # Checks for useless assignment to a local variable. Lint/UselessAssignment: Enabled: true @@ -709,6 +802,22 @@ Performance/LstripRstrip: Performance/RangeInclude: Enabled: true +# This cop identifies the use of a `&block` parameter and `block.call` +# where `yield` would do just as well. +Performance/RedundantBlockCall: + Enabled: true + +# This cop identifies use of `Regexp#match` or `String#match in a context +# where the integral return value of `=~` would do just as well. +Performance/RedundantMatch: + Enabled: true + +# This cop identifies places where `Hash#merge!` can be replaced by +# `Hash#[]=`. +Performance/RedundantMerge: + Enabled: true + MaxKeyValuePairs: 1 + # Use `sort` instead of `sort_by { |x| x }`. Performance/RedundantSortBy: Enabled: true @@ -728,6 +837,17 @@ Performance/StringReplacement: Performance/TimesMap: Enabled: true +# Security #################################################################### + +# This cop checks for the use of JSON class methods which have potential +# security issues. +Security/JSONLoad: + Enabled: true + +# This cop checks for the use of *Kernel#eval*. +Security/Eval: + Enabled: true + # Rails ####################################################################### # Enables Rails cops. @@ -746,8 +866,19 @@ Rails/Date: # Prefer delegate method for delegations. Rails/Delegate: + Enabled: true + +# This cop checks dynamic `find_by_*` methods. +Rails/DynamicFindBy: Enabled: false +# This cop enforces that 'exit' calls are not used within a rails app. +Rails/Exit: + Enabled: true + Exclude: + - lib/gitlab/upgrader.rb + - 'lib/backup/**/*' + # Prefer `find_by` over `where.first`. Rails/FindBy: Enabled: true @@ -760,9 +891,25 @@ Rails/FindEach: Rails/HasAndBelongsToMany: Enabled: true +# This cop is used to identify usages of http methods like `get`, `post`, +# `put`, `patch` without the usage of keyword arguments in your tests and +# change them to use keyword args. +Rails/HttpPositionalArguments: + Enabled: false + # Checks for calls to puts, print, etc. Rails/Output: Enabled: true + Exclude: + - lib/gitlab/seeder.rb + - lib/gitlab/upgrader.rb + - 'lib/backup/**/*' + - 'lib/tasks/**/*' + +# This cop checks for the use of output safety calls like html_safe and +# raw. +Rails/OutputSafety: + Enabled: false # Checks for incorrect grammar when using methods like `3.day.ago`. Rails/PluralizationGrammar: @@ -776,6 +923,14 @@ Rails/ReadWriteAttribute: Rails/ScopeArgs: Enabled: true +# This cop checks for the use of Time methods without zone. +Rails/TimeZone: + Enabled: false + +# This cop checks for the use of old-style attribute validation macros. +Rails/Validation: + Enabled: true + # RSpec ####################################################################### # Check that instances are not being stubbed globally. @@ -784,7 +939,7 @@ RSpec/AnyInstance: # Check for expectations where `be(...)` can replace `eql(...)`. RSpec/BeEql: - Enabled: false + Enabled: true # Check that the first argument to the top level describe is the tested class or # module. @@ -833,21 +988,51 @@ RSpec/Focus: RSpec/InstanceVariable: Enabled: false +# Checks for `subject` definitions that come after `let` definitions. +RSpec/LeadingSubject: + Enabled: false + +# Checks unreferenced `let!` calls being used for test setup. +RSpec/LetSetup: + Enabled: false + +# Check that chains of messages are not being stubbed. +RSpec/MessageChain: + Enabled: false + +# Checks that message expectations are set using spies. +RSpec/MessageSpies: + Enabled: false + # Checks for multiple top-level describes. RSpec/MultipleDescribes: Enabled: false +# Checks if examples contain too many `expect` calls. +RSpec/MultipleExpectations: + Enabled: false + +# Checks for explicitly referenced test subjects. +RSpec/NamedSubject: + Enabled: false + +# Checks for nested example groups. +RSpec/NestedGroups: + Enabled: false + # Enforces the usage of the same method on all negative message expectations. RSpec/NotToNot: EnforcedStyle: not_to Enabled: true +# Check for repeated description strings in example groups. +RSpec/RepeatedDescription: + Enabled: false + +# Checks for stubbed test subjects. +RSpec/SubjectStub: + Enabled: false + # Prefer using verifying doubles over normal doubles. RSpec/VerifiedDoubles: Enabled: false - -# Custom ###################################################################### - -# Disallow the `git` and `github` arguments in the Gemfile. -GemFetcher: - Enabled: true diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a5b4d2f5b02..c24142c0a11 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,79 +1,13 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 0` -# on 2017-01-11 09:38:25 +0000 using RuboCop version 0.46.0. +# on 2017-02-22 13:02:35 -0600 using RuboCop version 0.47.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 27 -# Configuration parameters: Include. -# Include: **/Gemfile, **/gems.rb -Bundler/OrderedGems: - Enabled: false - -# Offense count: 175 -Lint/AmbiguousRegexpLiteral: - Enabled: false - -# Offense count: 53 -# Configuration parameters: AllowSafeAssignment. -Lint/AssignmentInCondition: - Enabled: false - -# Offense count: 20 -Lint/HandleExceptions: - Enabled: false - -# Offense count: 1 -Lint/Loop: - Enabled: false - -# Offense count: 27 -Lint/ShadowingOuterLocalVariable: - Enabled: false - -# Offense count: 10 -# Cop supports --auto-correct. -Lint/UnifiedInteger: - Enabled: false - -# Offense count: 21 -# Cop supports --auto-correct. -Lint/UnneededSplatExpansion: - Enabled: false - -# Offense count: 82 -# Cop supports --auto-correct. -# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. -Lint/UnusedBlockArgument: - Enabled: false - -# Offense count: 173 -# Cop supports --auto-correct. -# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. -Lint/UnusedMethodArgument: - Enabled: false - -# Offense count: 93 -# Configuration parameters: CountComments. -Metrics/BlockLength: - Enabled: false - -# Offense count: 3 -# Cop supports --auto-correct. -Performance/RedundantBlockCall: - Enabled: false - -# Offense count: 5 -# Cop supports --auto-correct. -Performance/RedundantMatch: - Enabled: false - -# Offense count: 32 -# Cop supports --auto-correct. -# Configuration parameters: MaxKeyValuePairs. -Performance/RedundantMerge: +# Offense count: 51 +RSpec/BeforeAfterAll: Enabled: false # Offense count: 15 @@ -81,7 +15,11 @@ Performance/RedundantMerge: RSpec/EmptyExampleGroup: Enabled: false -# Offense count: 58 +# Offense count: 1 +RSpec/ExpectOutput: + Enabled: false + +# Offense count: 63 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: implicit, each, example RSpec/HookArgument: @@ -93,147 +31,59 @@ RSpec/HookArgument: RSpec/ImplicitExpect: Enabled: false -# Offense count: 237 -RSpec/LeadingSubject: +# Offense count: 36 +RSpec/RepeatedExample: Enabled: false -# Offense count: 253 -RSpec/LetSetup: - Enabled: false - -# Offense count: 13 -RSpec/MessageChain: - Enabled: false - -# Offense count: 479 -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: have_received, receive -RSpec/MessageSpies: - Enabled: false - -# Offense count: 3036 -RSpec/MultipleExpectations: - Enabled: false - -# Offense count: 2133 -RSpec/NamedSubject: - Enabled: false - -# Offense count: 1974 -# Configuration parameters: MaxNesting. -RSpec/NestedGroups: - Enabled: false - -# Offense count: 32 -RSpec/RepeatedDescription: +# Offense count: 34 +RSpec/ScatteredSetup: Enabled: false # Offense count: 1 RSpec/SingleArgumentMessageChain: Enabled: false -# Offense count: 133 -RSpec/SubjectStub: +# Offense count: 163 +Rails/FilePath: Enabled: false -# Offense count: 104 -# Cop supports --auto-correct. -# Configuration parameters: Whitelist. -# Whitelist: find_by_sql -Rails/DynamicFindBy: - Enabled: false - -# Offense count: 932 -# Cop supports --auto-correct. +# Offense count: 2 # Configuration parameters: Include. -# Include: spec/**/*, test/**/* -Rails/HttpPositionalArguments: +# Include: db/migrate/*.rb +Rails/ReversibleMigration: + Enabled: false + +# Offense count: 278 +# Configuration parameters: Blacklist. +# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters +Rails/SkipsModelValidations: + Enabled: false + +# Offense count: 7 +# Cop supports --auto-correct. +Security/YAMLLoad: Enabled: false # Offense count: 55 -Rails/OutputSafety: - Enabled: false - -# Offense count: 182 -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: strict, flexible -Rails/TimeZone: - Enabled: false - -# Offense count: 15 -# Cop supports --auto-correct. -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/Validation: - Enabled: false - -# Offense count: 8 -# Cop supports --auto-correct. -# Configuration parameters: AutoCorrect. -Security/JSONLoad: - Enabled: false - -# Offense count: 346 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: with_first_parameter, with_fixed_indentation -Style/AlignParameters: - Enabled: false - -# Offense count: 54 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: percent_q, bare_percent Style/BarePercentLiterals: Enabled: false -# Offense count: 358 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: braces, no_braces, context_dependent -Style/BracesAroundHashParameters: - Enabled: false - -# Offense count: 6 -Style/CaseEquality: - Enabled: false - -# Offense count: 37 -# Cop supports --auto-correct. -Style/ColonMethodCall: - Enabled: false - -# Offense count: 4 -# Cop supports --auto-correct. -# Configuration parameters: Keywords. -# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW -Style/CommentAnnotation: - Enabled: false - -# Offense count: 29 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly. -# SupportedStyles: assign_to_condition, assign_inside_condition -Style/ConditionalAssignment: - Enabled: false - -# Offense count: 1210 +# Offense count: 1304 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: leading, trailing Style/DotPosition: Enabled: false -# Offense count: 18 -Style/DoubleNegation: - Enabled: false - -# Offense count: 7 +# Offense count: 6 # Cop supports --auto-correct. Style/EachWithObject: Enabled: false -# Offense count: 24 +# Offense count: 25 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: empty, nil, both @@ -245,14 +95,14 @@ Style/EmptyElse: Style/EmptyLiteral: Enabled: false -# Offense count: 57 +# Offense count: 56 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: compact, expanded Style/EmptyMethod: Enabled: false -# Offense count: 147 +# Offense count: 184 # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. Style/ExtraSpacing: @@ -264,50 +114,50 @@ Style/ExtraSpacing: Style/FormatString: Enabled: false -# Offense count: 238 +# Offense count: 268 # Configuration parameters: MinBodyLength. Style/GuardClause: Enabled: false -# Offense count: 11 +# Offense count: 14 Style/IfInsideElse: Enabled: false -# Offense count: 173 +# Offense count: 179 # Cop supports --auto-correct. # Configuration parameters: MaxLineLength. Style/IfUnlessModifier: Enabled: false -# Offense count: 55 +# Offense count: 57 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_brackets Style/IndentArray: Enabled: false -# Offense count: 101 +# Offense count: 120 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_braces Style/IndentHash: Enabled: false -# Offense count: 41 +# Offense count: 45 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: line_count_dependent, lambda, literal Style/Lambda: Enabled: false -# Offense count: 5 +# Offense count: 7 # Cop supports --auto-correct. Style/LineEndConcatenation: Enabled: false -# Offense count: 19 +# Offense count: 22 # Cop supports --auto-correct. -Style/MethodCallParentheses: +Style/MethodCallWithoutArgsParentheses: Enabled: false # Offense count: 9 @@ -319,61 +169,49 @@ Style/MethodMissing: Style/MultilineIfModifier: Enabled: false -# Offense count: 179 -# Cop supports --auto-correct. -Style/MutableConstant: - Enabled: false - -# Offense count: 8 +# Offense count: 22 # Cop supports --auto-correct. Style/NestedParenthesizedCalls: Enabled: false -# Offense count: 13 +# Offense count: 17 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. # SupportedStyles: skip_modifier_ifs, always Style/Next: Enabled: false -# Offense count: 19 +# Offense count: 31 # Cop supports --auto-correct. # Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. # SupportedOctalStyles: zero_with_o, zero_only Style/NumericLiteralPrefix: Enabled: false -# Offense count: 19 +# Offense count: 77 # Cop supports --auto-correct. # Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles. # SupportedStyles: predicate, comparison Style/NumericPredicate: Enabled: false -# Offense count: 34 +# Offense count: 36 # Cop supports --auto-correct. Style/ParallelAssignment: Enabled: false -# Offense count: 417 +# Offense count: 477 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: Enabled: false -# Offense count: 10 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: lower_case_q, upper_case_q -Style/PercentQLiterals: - Enabled: false - -# Offense count: 13 +# Offense count: 14 # Cop supports --auto-correct. Style/PerlBackrefs: Enabled: false -# Offense count: 64 +# Offense count: 72 # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. # NamePrefix: is_, has_, have_ # NamePrefixBlacklist: is_, has_, have_ @@ -381,7 +219,7 @@ Style/PerlBackrefs: Style/PredicateName: Enabled: false -# Offense count: 33 +# Offense count: 39 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: short, verbose @@ -393,7 +231,7 @@ Style/PreferredHashMethods: Style/Proc: Enabled: false -# Offense count: 50 +# Offense count: 62 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: compact, exploded @@ -405,30 +243,30 @@ Style/RaiseArgs: Style/RedundantBegin: Enabled: false -# Offense count: 29 +# Offense count: 32 # Cop supports --auto-correct. Style/RedundantFreeze: Enabled: false -# Offense count: 11 +# Offense count: 15 # Cop supports --auto-correct. # Configuration parameters: AllowMultipleReturnValues. Style/RedundantReturn: Enabled: false -# Offense count: 359 +# Offense count: 365 # Cop supports --auto-correct. Style/RedundantSelf: Enabled: false -# Offense count: 105 +# Offense count: 108 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. # SupportedStyles: slashes, percent_r, mixed Style/RegexpLiteral: Enabled: false -# Offense count: 19 +# Offense count: 22 # Cop supports --auto-correct. Style/RescueModifier: Enabled: false @@ -438,19 +276,13 @@ Style/RescueModifier: Style/SelfAssignment: Enabled: false -# Offense count: 2 -# Configuration parameters: Methods. -# Methods: {"reduce"=>["acc", "elem"]}, {"inject"=>["acc", "elem"]} -Style/SingleLineBlockParams: - Enabled: false - # Offense count: 50 # Cop supports --auto-correct. # Configuration parameters: AllowIfMethodIsEmpty. Style/SingleLineMethods: Enabled: false -# Offense count: 138 +# Offense count: 155 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: space, no_space @@ -463,26 +295,22 @@ Style/SpaceBeforeBlockBraces: Style/SpaceBeforeFirstArg: Enabled: false -# Offense count: 37 +# Offense count: 38 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: require_no_space, require_space Style/SpaceInLambdaLiteral: Enabled: false -# Offense count: 174 +# Offense count: 203 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. +# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. # SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space Style/SpaceInsideBlockBraces: Enabled: false -# Offense count: 115 -# Cop supports --auto-correct. -Style/SpaceInsideBrackets: - Enabled: false - -# Offense count: 77 +# Offense count: 91 # Cop supports --auto-correct. Style/SpaceInsideParens: Enabled: false @@ -492,21 +320,21 @@ Style/SpaceInsideParens: Style/SpaceInsidePercentLiteralDelimiters: Enabled: false -# Offense count: 53 +# Offense count: 55 # Cop supports --auto-correct. # Configuration parameters: SupportedStyles. # SupportedStyles: use_perl_names, use_english_names Style/SpecialGlobalVars: EnforcedStyle: use_perl_names -# Offense count: 25 +# Offense count: 40 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: single_quotes, double_quotes Style/StringLiteralsInInterpolation: Enabled: false -# Offense count: 54 +# Offense count: 57 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. # IgnoredMethods: respond_to, define_method @@ -520,27 +348,20 @@ Style/SymbolProc: Style/TernaryParentheses: Enabled: false -# Offense count: 36 +# Offense count: 43 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. -# SupportedStyles: comma, consistent_comma, no_comma +# Configuration parameters: EnforcedStyleForMultiline, SupportedStylesForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma Style/TrailingCommaInArguments: Enabled: false -# Offense count: 150 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. -# SupportedStyles: comma, consistent_comma, no_comma -Style/TrailingCommaInLiteral: - Enabled: false - -# Offense count: 7 +# Offense count: 13 # Cop supports --auto-correct. # Configuration parameters: AllowNamedUnderscoreVariables. Style/TrailingUnderscoreVariable: Enabled: false -# Offense count: 67 +# Offense count: 70 # Cop supports --auto-correct. Style/TrailingWhitespace: Enabled: false @@ -552,12 +373,12 @@ Style/TrailingWhitespace: Style/TrivialAccessors: Enabled: false -# Offense count: 2 +# Offense count: 6 # Cop supports --auto-correct. Style/UnlessElse: Enabled: false -# Offense count: 17 +# Offense count: 22 # Cop supports --auto-correct. Style/UnneededInterpolation: Enabled: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b8cf2ad83..da1898e3770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,230 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 8.17.4 (2017-03-19) + +- Only show public emails in atom feeds. +- To protect against Server-side Request Forgery project import URLs are now prohibited against localhost or the server IP except for the assigned instance URL and port. Imports are also prohibited from ports below 1024 with the exception of ports 22, 80, and 443. + +## 8.17.3 (2017-03-07) + +- Fix the redirect to custom home page URL. !9518 +- Fix broken migration when upgrading straight to 8.17.1. !9613 +- Make projects dropdown only show projects you are a member of. !9614 +- Fix creating a file in an empty repo using the API. !9632 +- Don't copy tooltip when copying GFM. +- Fix cherry-picking or reverting through an MR. + +## 8.17.2 (2017-03-01) + +- Expire all webpack assets after 8.17.1 included a badly compiled asset. !9602 + +## 8.17.1 (2017-02-28) + +- Replace setInterval with setTimeout to prevent highly frequent requests. !9271 (Takuya Noguchi) +- Disable unused tags count cache for Projects, Builds and Runners. +- Spam check and reCAPTCHA improvements. +- Allow searching issues for strings containing colons. +- Disabled tooltip on add issues button in usse boards. +- Fixed commit search UI. +- Fix MR changes tab size count when there are over 100 files in the diff. +- Disable invalid service templates. +- Use default branch as target_branch when parameter is missing. +- Upgrade GitLab Pages to v0.3.2. +- Add performance query regression fix for !9088 affecting #27267. +- Chat slash commands show labels correctly. + +## 8.17.0 (2017-02-22) + +- API: Fix file downloading. !0 (8267) +- Changed composer installer script in the CI PHP example doc. !4342 (Jeffrey Cafferata) +- Display fullscreen button on small screens. !5302 (winniehell) +- Add system hook for when a project is updated (other than rename/transfer). !5711 (Tommy Beadle) +- Fix notifications when set at group level. !6813 (Alexandre Maia) +- Project labels can now be promoted to group labels. !7242 (Olaf Tomalka) +- use webpack to bundle frontend assets and use karma for frontend testing. !7288 +- Adds back ability to stop all environments. !7379 +- Added labels empty state. !7443 +- Add ability to define a coverage regex in the .gitlab-ci.yml. !7447 (Leandro Camargo) +- Disable automatic login after clicking email confirmation links. !7472 +- Search feature: redirects to commit page if query is commit sha and only commit found. !8028 (YarNayar) +- Create a TODO for user who set auto-merge when a build fails, merge conflict occurs. !8056 (twonegatives) +- Don't group issues by project on group-level and dashboard issue indexes. !8111 (Bernardo Castro) +- Mark MR as WIP when pushing WIP commits. !8124 (Jurre Stender @jurre) +- Flag multiple empty lines in eslint, fix offenses. !8137 +- Add sorting pipeline for a commit. !8319 (Takuya Noguchi) +- Adds service trigger events to api. !8324 +- Update pipeline and commit links when CI status is updated. !8351 +- Hide version check image if there is no internet connection. !8355 (Ken Ding) +- Prevent removal of input fields if it is the parent dropdown element. !8397 +- Introduce maximum session time for terminal websocket connection. !8413 +- Allow creating protected branches when user can merge to such branch. !8458 +- Refactor MergeRequests::BuildService. !8462 (Rydkin Maxim) +- Added GitLab Pages to CE. !8463 +- Support notes when a project is not specified (personal snippet notes). !8468 +- Use warning icon in mini-graph if stage passed conditionally. !8503 +- Don’t count tasks that are not defined as list items correctly. !8526 +- Reformat messages ChatOps. !8528 +- Copy commit SHA to clipboard. !8547 +- Improve button accessibility on pipelines page. !8561 +- Display project ID in project settings. !8572 (winniehell) +- PlantUML support for Markdown. !8588 (Horacio Sanson) +- Fix reply by email without sub-addressing for some clients from Microsoft and Apple. !8620 +- Fix nested tasks in ordered list. !8626 +- Fix Sort by Recent Sign-in in Admin Area. !8637 (Poornima M) +- Avoid repeated dashes in $CI_ENVIRONMENT_SLUG. !8638 +- Only show Merge Request button when user can create a MR. !8639 +- Prevent copying of line numbers in parallel diff view. !8706 +- Improve build policy and access abilities. !8711 +- API: Remove /projects/:id/keys/.. endpoints. !8716 (Robert Schilling) +- API: Remove deprecated 'expires_at' from project snippets. !8723 (Robert Schilling) +- Add `copy` backup strategy to combat file changed errors. !8728 +- adds avatar for discussion note. !8734 +- Add link verification to badge partial in order to render a badge without a link. !8740 +- Reduce hits to LDAP on Git HTTP auth by reordering auth mechanisms. !8752 +- prevent diff unfolding link from appearing when there are no more lines to show. !8761 +- Redesign searchbar in admin project list. !8776 +- Rename Builds to Pipelines, CI/CD Pipelines, or Jobs everywhere. !8787 +- dismiss sidebar on repo buttons click. !8798 (Adam Pahlevi) +- fixed small mini pipeline graph line glitch. !8804 +- Make all system notes lowercase. !8807 +- Support unauthenticated LFS object downloads for public projects. !8824 (Ben Boeckel) +- Add read-only full_path and full_name attributes to Group API. !8827 +- allow relative url change without recompiling frontend assets. !8831 +- Use vue.js Pipelines table in commit and merge request view. !8844 +- Use reCaptcha when an issue is identified as a spam. !8846 +- resolve deprecation warnings. !8855 (Adam Pahlevi) +- Cop for gem fetched from a git source. !8856 (Adam Pahlevi) +- Remove flash warning from login page. !8864 (Gerald J. Padilla) +- Adds documentation for how to use Vue.js. !8866 +- Add 'View on [env]' link to blobs and individual files in diffs. !8867 +- Replace word user with member. !8872 +- Change the reply shortcut to focus the field even without a selection. !8873 (Brian Hall) +- Unify MR diff file button style. !8874 +- Unify projects search by removing /projects/:search endpoint. !8877 +- Fix disable storing of sensitive information when importing a new repo. !8885 (Bernard Pietraga) +- Fix pipeline graph vertical spacing in Firefox and Safari. !8886 +- Fix filtered search user autocomplete for gitlab instances that are hosted on a subdirectory. !8891 +- Fix Ctrl+Click support for Todos and Merge Request page tabs. !8898 +- Fix wrong call to ProjectCacheWorker.perform. !8910 +- Don't perform Devise trackable updates on blocked User records. !8915 +- Add ability to export project inherited group members to Import/Export. !8923 +- replace `find_with_namespace` with `find_by_full_path`. !8949 (Adam Pahlevi) +- Fixes flickering of avatar border in mention dropdown. !8950 +- Remove unnecessary queries for .atom and .json in Dashboard::ProjectsController#index. !8956 +- Fix deleting projects with pipelines and builds. !8960 +- Fix broken anchor links when special characters are used. !8961 (Andrey Krivko) +- Ensure autogenerated title does not cause failing spec. !8963 (brian m. carlson) +- Update doc for enabling or disabling GitLab CI. !8965 (Takuya Noguchi) +- Remove deprecated MR and Issue endpoints and preserve V3 namespace. !8967 +- Fixed "substract" typo on /help/user/project/slash_commands. !8976 (Jason Aquino) +- Preserve backward compatibility CI/CD and disallow setting `coverage` regexp in global context. !8981 +- use babel to transpile all non-vendor javascript assets regardless of file extension. !8988 +- Fix MR widget url. !8989 +- Fixes hover cursor on pipeline pagenation. !9003 +- Layer award emoji dropdown over the right sidebar. !9004 +- Do not display deploy keys in user's own ssh keys list. !9024 +- upgrade babel 5.8.x to babel 6.22.x. !9072 +- upgrade to webpack v2.2. !9078 +- Trigger autocomplete after selecting a slash command. !9117 +- Add space between text and loading icon in Megre Request Widget. !9119 +- Fix job to pipeline renaming. !9147 +- Replace static fixture for merge_request_tabs_spec.js. !9172 (winniehell) +- Replace static fixture for right_sidebar_spec.js. !9211 (winniehell) +- Show merge errors in merge request widget. !9229 +- Increase process_commit queue weight from 2 to 3. !9326 (blackst0ne) +- Don't require lib/gitlab/request_profiler/middleware.rb in config/initializers/request_profiler.rb. +- Force new password after password reset via API. (George Andrinopoulos) +- Allows to search within project by commit hash. (YarNayar) +- Show organisation membership and delete comment on smaller viewports, plus change comment author name to username. +- Remove turbolinks. +- Convert pipeline action icons to svg to have them propperly positioned. +- Remove rogue scrollbars for issue comments with inline elements. +- Align Segoe UI label text. +- Color + and - signs in diffs to increase code legibility. +- Fix tab index order on branch commits list page. (Ryan Harris) +- Add hover style to copy icon on commit page header. (Ryan Harris) +- Remove hover animation from row elements. +- Improve pipeline status icon linking in widgets. +- Fix commit title bar and repository view copy clipboard button order on last commit in repository view. +- Fix mini-pipeline stage tooltip text wrapping. +- Updated builds info link on the project settings page. (Ryan Harris) +- 27240 Make progress bars consistent. +- Only render hr when user can't archive project. +- 27352-search-label-filter-header. +- Include :author, :project, and :target in Event.with_associations. +- Don't instantiate AR objects in Event.in_projects. +- Don't capitalize environment name in show page. +- Update and pin the `jwt` gem to ~> 1.5.6. +- Edited the column header for the environments list from created to updated and added created to environments detail page colum header titles. +- Give ci status text on pipeline graph a better font-weight. +- Add default labels to bulk assign dropdowns. +- Only return target project's comments for a commit. +- Fixes Pipelines table is not showing branch name for commit. +- Fix regression where cmd-click stopped working for todos and merge request tabs. +- Fix stray pipelines API request when showing MR. +- Fix Merge request pipelines displays JSON. +- Fix current build arrow indicator. +- Fix contribution activity alignment. +- Show Pipeline(not Job) in MR desktop notification. +- Fix tooltips in mini pipeline graph. +- Display loading indicator when filtering ref switcher dropdown. +- Show pipeline graph in MR widget if there are any stages. +- Fix icon colors in merge request widget mini graph. +- Improve blockquote formatting in notification emails. +- Adds container to tooltip in order to make it work with overflow:hidden in parent element. +- Restore pagination to admin abuse reports. +- Ensure export files are removed after a namespace is deleted. +- Add `y` keyboard shortcut to move to file permalink. +- Adds /target_branch slash command functionality for merge requests. (YarNayar) +- Patch Asciidocs rendering to block XSS. +- contribution calendar scrolls from right to left. +- Copying a rendered issue/comment will paste into GFM textareas as actual GFM. +- Don't delete assigned MRs/issues when user is deleted. +- Remove new branch button for confidential issues. +- Don't allow project guests to subscribe to merge requests through the API. (Robert Schilling) +- Don't connect in Gitlab::Database.adapter_name. +- Prevent users from creating notes on resources they can't access. +- Ignore encrypted attributes in Import/Export. +- Change rspec test to guarantee window is resized before visiting page. +- Prevent users from deleting system deploy keys via the project deploy key API. +- Fix XSS vulnerability in SVG attachments. +- Make MR-review-discussions more reliable. +- fix incorrect sidekiq concurrency count in admin background page. (wendy0402) +- Make notification_service spec DRYer by making test reusable. (YarNayar) +- Redirect http://someproject.git to http://someproject. (blackst0ne) +- Fixed group label links in issue/merge request sidebar. +- Improve gl.utils.handleLocationHash tests. +- Fixed Issuable sidebar not closing on smaller/mobile sized screens. +- Resets assignee dropdown when sidebar is open. +- Disallow system notes for closed issuables. +- Fix timezone on issue boards due date. +- Remove unused js response from refs controller. +- Prevent the GitHub importer from assigning labels and comments to merge requests or issues belonging to other projects. +- Fixed merge requests tab extra margin when fixed to window. +- Patch XSS vulnerability in RDOC support. +- Refresh authorizations when transferring projects. +- Remove issue and MR counts from labels index. +- Don't use backup Active Record connections for Sidekiq. +- Add index to ci_trigger_requests for commit_id. +- Add indices to improve loading of labels page. +- Reduced query count for snippet search. +- Update GitLab Pages to v0.3.1. +- Upgrade omniauth gem to 1.3.2. +- Remove deprecated GitlabCiService. +- Requeue pending deletion projects. + +## 8.16.8 (2017-03-19) + +- Only show public emails in atom feeds. +- To protect against Server-side Request Forgery project import URLs are now prohibited against localhost or the server IP except for the assigned instance URL and port. Imports are also prohibited from ports below 1024 with the exception of ports 22, 80, and 443. + +## 8.16.7 (2017-02-27) + +- No changes. +- No changes. +- Fix MR changes tab size count when there are over 100 files in the diff. + ## 8.16.6 (2017-02-17) - API: Fix file downloading. !0 (8267) @@ -197,6 +421,11 @@ entry. - Add margin to markdown math blocks. - Add hover state to MR comment reply button. +## 8.15.8 (2017-03-19) + +- Only show public emails in atom feeds. +- To protect against Server-side Request Forgery project import URLs are now prohibited against localhost or the server IP except for the assigned instance URL and port. Imports are also prohibited from ports below 1024 with the exception of ports 22, 80, and 443. + ## 8.15.7 (2017-02-15) - No changes. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index de32a953f63..a285e8ab74f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,32 +1,48 @@ +## Contributor license agreement + +By submitting code as an individual you agree to the +[individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md). +By submitting code as an entity you agree to the +[corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md). + +_This notice should stay as the first item in the CONTRIBUTING.MD file._ + +--- + **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +- [Contributor license agreement](#contributor-license-agreement) - [Contribute to GitLab](#contribute-to-gitlab) - - [Contributor license agreement](#contributor-license-agreement) - - [Security vulnerability disclosure](#security-vulnerability-disclosure) - - [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests) - - [Helping others](#helping-others) - - [I want to contribute!](#i-want-to-contribute) - - [Implement design & UI elements](#implement-design-ui-elements) - - [Issue tracker](#issue-tracker) - - [Feature proposals](#feature-proposals) - - [Issue tracker guidelines](#issue-tracker-guidelines) - - [Issue weight](#issue-weight) - - [Regression issues](#regression-issues) - - [Technical debt](#technical-debt) - - [Stewardship](#stewardship) - - [Merge requests](#merge-requests) - - [Merge request guidelines](#merge-request-guidelines) - - [Contribution acceptance criteria](#contribution-acceptance-criteria) - - [Changes for Stable Releases](#changes-for-stable-releases) - - [Definition of done](#definition-of-done) - - [Style guides](#style-guides) - - [Code of conduct](#code-of-conduct) +- [Security vulnerability disclosure](#security-vulnerability-disclosure) +- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests) +- [Helping others](#helping-others) +- [I want to contribute!](#i-want-to-contribute) +- [Implement design & UI elements](#implement-design-ui-elements) +- [Release retrospective and kickoff](#release-retrospective-and-kickoff) + - [Retrospective](#retrospective) + - [Kickoff](#kickoff) +- [Issue tracker](#issue-tracker) + - [Feature proposals](#feature-proposals) + - [Issue tracker guidelines](#issue-tracker-guidelines) + - [Issue weight](#issue-weight) + - [Regression issues](#regression-issues) + - [Technical debt](#technical-debt) + - [Stewardship](#stewardship) +- [Merge requests](#merge-requests) + - [Merge request guidelines](#merge-request-guidelines) + - [Contribution acceptance criteria](#contribution-acceptance-criteria) +- [Changes for Stable Releases](#changes-for-stable-releases) +- [Definition of done](#definition-of-done) +- [Style guides](#style-guides) +- [Code of conduct](#code-of-conduct) -# Contribute to GitLab +--- + +## Contribute to GitLab Thank you for your interest in contributing to GitLab. This guide details how to contribute to GitLab in a way that is efficient for everyone. @@ -41,13 +57,6 @@ operates please see [the GitLab contributing process](PROCESS.md). - [GitLab Inc engineers should refer to the engineering workflow document](https://about.gitlab.com/handbook/engineering/workflow/) -## Contributor license agreement - -By submitting code as an individual you agree to the -[individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md). -By submitting code as an entity you agree to the -[corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md). - ## Security vulnerability disclosure Please report suspected security vulnerabilities in private to @@ -69,6 +78,13 @@ towards getting your issue resolved. Issues and merge requests should be in English and contain appropriate language for audiences of all ages. +If a contributor is no longer actively working on a submitted merge request +we can decide that the merge request will be finished by one of our +[Merge request coaches][team] or close the merge request. We make this decision +based on how important the change is for our product vision. If a Merge request +coach is going to finish the merge request we assign the +~"coach will finish" label. + ## Helping others Please help other GitLab users when you can. The channels people will reach out @@ -85,6 +101,10 @@ look for [issues with the label `Accepting Merge Requests` and weight < 5][accep These issues will be of reasonable size and challenge, for anyone to start contributing to GitLab. +## Workflow labels + +Labelling issues is described in the [GitLab Inc engineering workflow]. + ## Implement design & UI elements Please see the [UX Guide for GitLab]. @@ -290,10 +310,13 @@ request is as follows: 1. [Generate a changelog entry with `bin/changelog`][changelog] 1. If you are writing documentation, make sure to follow the [documentation styleguide][doc-styleguide] -1. If you have multiple commits please combine them into one commit by - [squashing them][git-squash] +1. If you have multiple commits please combine them into a few logically + organized commits by [squashing them][git-squash] 1. Push the commit(s) to your fork 1. Submit a merge request (MR) to the `master` branch +1. Leave the approvals settings as they are: + 1. Your merge request needs at least 1 approval + 1. You don't have to select any approvers 1. The MR title should describe the change you want to make 1. The MR description should give a motive for your change and the method you used to achieve it. @@ -336,13 +359,31 @@ The ['How to get faster PR reviews' document of Kubernetes](https://github.com/k For examples of feedback on merge requests please look at already [closed merge requests][closed-merge-requests]. If you would like quick feedback -on your merge request feel free to mention one of the Merge Marshalls in the -[core team] or one of the [Merge request coaches](https://about.gitlab.com/team/). +on your merge request feel free to mention someone from the [core team] or one +of the [Merge request coaches][team]. Please ensure that your merge request meets the contribution acceptance criteria. When having your code reviewed and when reviewing merge requests please take the [code review guidelines](doc/development/code_review.md) into account. +### Getting your merge request reviewed, approved, and merged + +There are a few rules to get your merge request accepted: + +1. Your merge request should only be **merged by a [maintainer][team]**. + 1. If your merge request includes only backend changes [^1], it must be + **approved by a [backend maintainer][team]**. + 1. If your merge request includes only frontend changes [^1], it must be + **approved by a [frontend maintainer][team]**. + 1. If your merge request includes frontend and backend changes [^1], it must + be approved by a frontend **and** a backend maintainer. +1. To lower the amount of merge requests maintainers need to review, you can + ask or assign any [reviewers][team] for a first review. + 1. If you need some guidance (e.g. it's your first merge request), feel free + to ask one of the [Merge request coaches][team]. + 1. The reviewer will assign the merge request to a maintainer once the + reviewer is satisfied with the state of the merge request. + ### Contribution acceptance criteria 1. The change is as small as possible @@ -365,6 +406,12 @@ When having your code reviewed and when reviewing merge requests please take the 1. Contains functionality we think other users will benefit from too 1. Doesn't add configuration options or settings options since they complicate making and testing future changes +1. Changes do not adversely degrade performance. + - Avoid repeated polling of endpoints that require a significant amount of overhead + - Check for N+1 queries via the SQL log or [`QueryRecorder`](https://docs.gitlab.com/ce/development/merge_request_performance_guidelines.html) + - Avoid repeated access of filesystem +1. If you need polling to support real-time features, please use + [polling with ETag caching][polling-etag]. 1. Changes after submitting the merge request should be in separate commits (no squashing). If necessary, you will be asked to squash when the review is over, before merging. @@ -400,6 +447,7 @@ the feature you contribute through all of these steps. 1. Description explaining the relevancy (see following item) 1. Working and clean code that is commented where needed 1. Unit and integration tests that pass on the CI server +1. Performance/scalability implications have been considered, addressed, and tested 1. [Documented][doc-styleguide] in the /doc directory 1. Changelog entry added 1. Reviewed and any concerns are addressed @@ -426,7 +474,7 @@ merge request: 1. [Ruby](https://github.com/bbatsov/ruby-style-guide). Important sections include [Source Code Layout][rss-source] and [Naming][rss-naming]. Use: - - multi-line method chaining style **Option B**: dot `.` on previous line + - multi-line method chaining style **Option A**: dot `.` on the second line - string literal quoting style **Option A**: single quoted by default 1. [Rails](https://github.com/bbatsov/rails-style-guide) 1. [Newlines styleguide][newlines-styleguide] @@ -480,6 +528,7 @@ This Code of Conduct is adapted from the [Contributor Covenant][contributor-cove available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/). [core team]: https://about.gitlab.com/core-team/ +[team]: https://about.gitlab.com/team/ [getting-help]: https://about.gitlab.com/getting-help/ [codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq [accepting-mrs-weight]: https://gitlab.com/gitlab-org/gitlab-ce/issues?assignee_id=0&label_name[]=Accepting%20Merge%20Requests&sort=weight_asc @@ -504,3 +553,9 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor [newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide" [UX Guide for GitLab]: http://docs.gitlab.com/ce/development/ux_guide/ [license-finder-doc]: doc/development/licensing.md +[GitLab Inc engineering workflow]: https://about.gitlab.com/handbook/engineering/workflow/#labelling-issues +[polling-etag]: https://docs.gitlab.com/ce/development/polling.html + +[^1]: Specs other than JavaScript specs are considered backend code. Haml + changes are considered backend code if they include Ruby code other than just + pure HTML. diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION new file mode 100644 index 00000000000..0d91a54c7d4 --- /dev/null +++ b/GITALY_SERVER_VERSION @@ -0,0 +1 @@ +0.3.0 diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION index 9e11b32fcaa..1d0ba9ea182 100644 --- a/GITLAB_PAGES_VERSION +++ b/GITLAB_PAGES_VERSION @@ -1 +1 @@ -0.3.1 +0.4.0 diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 627a3f43a64..0062ac97180 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -4.1.1 +5.0.0 diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index f0bb29e7638..347f5833ee6 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -1.3.0 +1.4.1 diff --git a/Gemfile b/Gemfile index 01861f1ffac..6af27ce0f3e 100644 --- a/Gemfile +++ b/Gemfile @@ -18,25 +18,26 @@ gem 'pg', '~> 0.18.2', group: :postgres gem 'rugged', '~> 0.24.0' # Authentication libraries -gem 'devise', '~> 4.2' -gem 'doorkeeper', '~> 4.2.0' -gem 'omniauth', '~> 1.3.2' -gem 'omniauth-auth0', '~> 1.4.1' -gem 'omniauth-azure-oauth2', '~> 0.0.6' -gem 'omniauth-cas3', '~> 1.1.2' -gem 'omniauth-facebook', '~> 4.0.0' -gem 'omniauth-github', '~> 1.1.1' -gem 'omniauth-gitlab', '~> 1.0.2' +gem 'devise', '~> 4.2' +gem 'doorkeeper', '~> 4.2.0' +gem 'doorkeeper-openid_connect', '~> 1.1.0' +gem 'omniauth', '~> 1.4.2' +gem 'omniauth-auth0', '~> 1.4.1' +gem 'omniauth-azure-oauth2', '~> 0.0.6' +gem 'omniauth-cas3', '~> 1.1.2' +gem 'omniauth-facebook', '~> 4.0.0' +gem 'omniauth-github', '~> 1.1.1' +gem 'omniauth-gitlab', '~> 1.0.2' gem 'omniauth-google-oauth2', '~> 0.4.1' -gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos +gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos gem 'omniauth-oauth2-generic', '~> 0.2.2' -gem 'omniauth-saml', '~> 1.7.0' -gem 'omniauth-shibboleth', '~> 1.2.0' -gem 'omniauth-twitter', '~> 1.2.0' -gem 'omniauth_crowd', '~> 2.2.0' -gem 'omniauth-authentiq', '~> 0.3.0' -gem 'rack-oauth2', '~> 1.2.1' -gem 'jwt', '~> 1.5.6' +gem 'omniauth-saml', '~> 1.7.0' +gem 'omniauth-shibboleth', '~> 1.2.0' +gem 'omniauth-twitter', '~> 1.2.0' +gem 'omniauth_crowd', '~> 2.2.0' +gem 'omniauth-authentiq', '~> 0.3.0' +gem 'rack-oauth2', '~> 1.2.1' +gem 'jwt', '~> 1.5.6' # Spam and anti-bot protection gem 'recaptcha', '~> 3.0', require: 'recaptcha/rails' @@ -68,9 +69,9 @@ gem 'gollum-rugged_adapter', '~> 0.4.2', require: false gem 'github-linguist', '~> 4.7.0', require: 'linguist' # API -gem 'grape', '~> 0.18.0' +gem 'grape', '~> 0.19.0' gem 'grape-entity', '~> 0.6.0' -gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' +gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' # Pagination gem 'kaminari', '~> 0.17.0' @@ -79,7 +80,7 @@ gem 'kaminari', '~> 0.17.0' gem 'hamlit', '~> 2.6.1' # Files attachments -gem 'carrierwave', '~> 0.10.0' +gem 'carrierwave', '~> 0.11.0' # Drag and Drop UI gem 'dropzonejs-rails', '~> 0.7.1' @@ -102,19 +103,19 @@ gem 'unf', '~> 0.1.4' gem 'seed-fu', '~> 2.3.5' # Markdown and HTML processing -gem 'html-pipeline', '~> 1.11.0' -gem 'deckar01-task_list', '1.0.6', require: 'task_list/railtie' -gem 'gitlab-markup', '~> 1.5.1' -gem 'redcarpet', '~> 3.3.3' -gem 'RedCloth', '~> 4.3.2' -gem 'rdoc', '~> 4.2' -gem 'org-ruby', '~> 0.9.12' -gem 'creole', '~> 0.5.0' -gem 'wikicloth', '0.8.1' -gem 'asciidoctor', '~> 1.5.2' +gem 'html-pipeline', '~> 1.11.0' +gem 'deckar01-task_list', '1.0.6', require: 'task_list/railtie' +gem 'gitlab-markup', '~> 1.5.1' +gem 'redcarpet', '~> 3.4' +gem 'RedCloth', '~> 4.3.2' +gem 'rdoc', '~> 4.2' +gem 'org-ruby', '~> 0.9.12' +gem 'creole', '~> 0.5.0' +gem 'wikicloth', '0.8.1' +gem 'asciidoctor', '~> 1.5.2' gem 'asciidoctor-plantuml', '0.0.7' -gem 'rouge', '~> 2.0' -gem 'truncato', '~> 0.7.8' +gem 'rouge', '~> 2.0' +gem 'truncato', '~> 0.7.8' # See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s # and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM @@ -201,7 +202,7 @@ gem 'babosa', '~> 1.0.2' gem 'loofah', '~> 2.0.3' # Working with license -gem 'licensee', '~> 8.0.0' +gem 'licensee', '~> 8.7.0' # Protect against bruteforcing gem 'rack-attack', '~> 4.4.1' @@ -229,19 +230,18 @@ gem 'sass-rails', '~> 5.0.6' gem 'coffee-rails', '~> 4.1.0' gem 'uglifier', '~> 2.7.2' -gem 'addressable', '~> 2.3.8' -gem 'bootstrap-sass', '~> 3.3.0' -gem 'font-awesome-rails', '~> 4.6.1' -gem 'gemojione', '~> 3.0' -gem 'gon', '~> 6.1.0' +gem 'addressable', '~> 2.3.8' +gem 'bootstrap-sass', '~> 3.3.0' +gem 'font-awesome-rails', '~> 4.7' +gem 'gemojione', '~> 3.0' +gem 'gon', '~> 6.1.0' gem 'jquery-atwho-rails', '~> 1.3.2' -gem 'jquery-rails', '~> 4.1.0' -gem 'jquery-ui-rails', '~> 5.0.0' -gem 'request_store', '~> 1.3' -gem 'select2-rails', '~> 3.5.9' -gem 'virtus', '~> 1.0.1' -gem 'net-ssh', '~> 3.0.1' -gem 'base32', '~> 0.3.0' +gem 'jquery-rails', '~> 4.1.0' +gem 'request_store', '~> 1.3' +gem 'select2-rails', '~> 3.5.9' +gem 'virtus', '~> 1.0.1' +gem 'net-ssh', '~> 3.0.1' +gem 'base32', '~> 0.3.0' # Sentry integration gem 'sentry-raven', '~> 2.0.0' @@ -279,13 +279,13 @@ group :development, :test do gem 'awesome_print', '~> 1.2.0', require: false gem 'fuubar', '~> 2.0.0' - gem 'database_cleaner', '~> 1.5.0' + gem 'database_cleaner', '~> 1.5.0' gem 'factory_girl_rails', '~> 4.7.0' - gem 'rspec-rails', '~> 3.5.0' - gem 'rspec-retry', '~> 0.4.5' - gem 'spinach-rails', '~> 0.2.1' + gem 'rspec-rails', '~> 3.5.0' + gem 'rspec-retry', '~> 0.4.5' + gem 'spinach-rails', '~> 0.2.1' gem 'spinach-rerun-reporter', '~> 0.0.2' - gem 'rspec_profiling', '~> 0.0.5' + gem 'rspec_profiling', '~> 0.0.5' # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) gem 'minitest', '~> 5.7.0' @@ -293,18 +293,18 @@ group :development, :test do # Generate Fake data gem 'ffaker', '~> 2.4' - gem 'capybara', '~> 2.6.2' + gem 'capybara', '~> 2.6.2' gem 'capybara-screenshot', '~> 1.0.0' - gem 'poltergeist', '~> 1.9.0' + gem 'poltergeist', '~> 1.9.0' - gem 'spring', '~> 1.7.0' - gem 'spring-commands-rspec', '~> 1.0.4' - gem 'spring-commands-spinach', '~> 1.1.0' + gem 'spring', '~> 1.7.0' + gem 'spring-commands-rspec', '~> 1.0.4' + gem 'spring-commands-spinach', '~> 1.1.0' - gem 'rubocop', '~> 0.46.0', require: false - gem 'rubocop-rspec', '~> 1.9.1', require: false + gem 'rubocop', '~> 0.47.1', require: false + gem 'rubocop-rspec', '~> 1.12.0', require: false gem 'scss_lint', '~> 0.47.0', require: false - gem 'haml_lint', '~> 0.18.2', require: false + gem 'haml_lint', '~> 0.21.0', require: false gem 'simplecov', '0.12.0', require: false gem 'flay', '~> 2.6.1', require: false gem 'bundler-audit', '~> 0.5.0', require: false @@ -329,8 +329,6 @@ group :test do gem 'timecop', '~> 0.8.0' end -gem 'newrelic_rpm', '~> 3.16' - gem 'octokit', '~> 4.6.2' gem 'mail_room', '~> 0.9.1' @@ -347,8 +345,11 @@ gem 'oauth2', '~> 1.2.0' gem 'paranoia', '~> 2.2' # Health check -gem 'health_check', '~> 2.2.0' +gem 'health_check', '~> 2.6.0' # System information gem 'vmstat', '~> 2.3.0' gem 'sys-filesystem', '~> 1.1.6' + +# Gitaly GRPC client +gem 'gitaly', '~> 0.3.0' diff --git a/Gemfile.lock b/Gemfile.lock index 2a3be763753..043ca4f8800 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,7 @@ GEM remote: https://rubygems.org/ specs: RedCloth (4.3.2) - ace-rails-ap (4.1.0) + ace-rails-ap (4.1.2) actionmailer (4.2.8) actionpack (= 4.2.8) actionview (= 4.2.8) @@ -78,6 +78,7 @@ GEM better_errors (1.0.1) coderay (>= 1.0.0) erubis (>= 2.6.6) + bindata (2.3.5) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) bootstrap-sass (3.3.6) @@ -103,11 +104,12 @@ GEM capybara-screenshot (1.0.11) capybara (>= 1.0, < 3) launchy - carrierwave (0.10.0) + carrierwave (0.11.2) activemodel (>= 3.2.0) activesupport (>= 3.2.0) json (>= 1.7) mime-types (>= 1.16) + mimemagic (>= 0.3.0) cause (0.1) charlock_holmes (0.7.3) chronic (0.10.2) @@ -166,6 +168,9 @@ GEM unf (>= 0.0.5, < 1.0.0) doorkeeper (4.2.0) railties (>= 4.2) + doorkeeper-openid_connect (1.1.2) + doorkeeper (~> 4.0) + json-jwt (~> 1.6) dropzonejs-rails (0.7.2) rails (> 3.1) email_reply_trimmer (0.1.6) @@ -231,7 +236,7 @@ GEM fog-xml (0.1.2) fog-core nokogiri (~> 1.5, >= 1.5.11) - font-awesome-rails (4.6.1.0) + font-awesome-rails (4.7.0.1) railties (>= 3.2, < 5.1) foreman (0.78.0) thor (~> 0.19.1) @@ -245,6 +250,9 @@ GEM json get_process_mem (0.2.0) gherkin-ruby (0.3.2) + gitaly (0.3.0) + google-protobuf (~> 3.1) + grpc (~> 1.0) github-linguist (4.7.6) charlock_holmes (~> 0.7.3) escape_utils (~> 1.1.0) @@ -296,6 +304,7 @@ GEM multi_json (~> 1.10) retriable (~> 1.4) signet (~> 0.6) + google-protobuf (3.2.0.2) googleauth (0.5.1) faraday (~> 0.9) jwt (~> 1.4) @@ -304,7 +313,7 @@ GEM multi_json (~> 1.11) os (~> 0.9) signet (~> 0.7) - grape (0.18.0) + grape (0.19.1) activesupport builder hashie (>= 2.1.0) @@ -317,19 +326,22 @@ GEM grape-entity (0.6.0) activesupport multi_json (>= 1.3.2) + grpc (1.1.2) + google-protobuf (~> 3.1) + googleauth (~> 0.5.1) haml (4.0.7) tilt - haml_lint (0.18.2) + haml_lint (0.21.0) haml (~> 4.0) - rake (>= 10, < 12) - rubocop (>= 0.36.0) + rake (>= 10, < 13) + rubocop (>= 0.47.0) sysexits (~> 1.1) hamlit (2.6.1) temple (~> 0.7.6) thor tilt - hashie (3.4.4) - health_check (2.2.1) + hashie (3.5.5) + health_check (2.6.0) rails (>= 4.0) hipchat (1.5.2) httparty @@ -353,8 +365,8 @@ GEM json (~> 1.8) multi_xml (>= 0.5.2) httpclient (2.8.2) - i18n (0.8.0) - ice_nine (0.11.1) + i18n (0.8.1) + ice_nine (0.11.2) influxdb (0.2.3) cause json @@ -367,9 +379,13 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - jquery-ui-rails (5.0.5) - railties (>= 3.2.16) json (1.8.6) + json-jwt (1.7.1) + activesupport + bindata + multi_json (>= 1.3) + securecompare + url_safe_base64 json-schema (2.6.2) addressable (~> 2.3.8) jwt (1.5.6) @@ -398,8 +414,8 @@ GEM rubyzip thor xml-simple - licensee (8.0.0) - rugged (>= 0.24b) + licensee (8.7.0) + rugged (~> 0.24) little-plugger (1.1.4) logging (2.1.0) little-plugger (~> 1.1) @@ -417,7 +433,7 @@ GEM minitest (5.7.0) mousetrap-rails (1.4.6) multi_json (1.12.1) - multi_xml (0.5.5) + multi_xml (0.6.0) multipart-post (2.0.0) mustermann (0.4.0) tool (~> 0.2) @@ -427,7 +443,6 @@ GEM net-ldap (0.12.1) net-ssh (3.0.1) netrc (0.11.0) - newrelic_rpm (3.16.0.318) nokogiri (1.6.8.1) mini_portile2 (~> 2.1.0) numerizer (0.1.1) @@ -441,7 +456,7 @@ GEM octokit (4.6.2) sawyer (~> 0.8.0, >= 0.5.3) oj (2.17.4) - omniauth (1.3.2) + omniauth (1.4.2) hashie (>= 1.2, < 4) rack (>= 1.0, < 3) omniauth-auth0 (1.4.1) @@ -501,7 +516,7 @@ GEM os (0.9.6) paranoia (2.2.0) activerecord (>= 4.0, < 5.1) - parser (2.3.1.4) + parser (2.4.0.0) ast (~> 2.2) pg (0.18.4) poltergeist (1.9.0) @@ -579,7 +594,7 @@ GEM recaptcha (3.0.0) json recursive-open-struct (1.0.0) - redcarpet (3.3.3) + redcarpet (3.4.0) redis (3.2.2) redis-actionpack (5.0.1) actionpack (>= 4.0, < 6) @@ -642,13 +657,13 @@ GEM pg rails sqlite3 - rubocop (0.46.0) - parser (>= 2.3.1.1, < 3.0) + rubocop (0.47.1) + parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) - rubocop-rspec (1.9.1) + rubocop-rspec (1.12.0) rubocop (>= 0.42.0) ruby-fogbugz (0.2.1) crack (~> 0.4) @@ -660,7 +675,7 @@ GEM sexp_processor (~> 4.1) rubyntlm (0.5.2) rubypants (0.2.0) - rubyzip (1.2.0) + rubyzip (1.2.1) rufus-scheduler (3.1.10) rugged (0.24.0) safe_yaml (1.0.4) @@ -679,6 +694,7 @@ GEM scss_lint (0.47.1) rake (>= 0.9, < 11) sass (~> 3.4.15) + securecompare (1.0.0) seed-fu (2.3.6) activerecord (>= 3.1) activesupport (>= 3.1) @@ -758,8 +774,8 @@ GEM eventmachine (~> 1.0, >= 1.0.4) rack (>= 1, < 3) thor (0.19.4) - thread_safe (0.3.5) - tilt (2.0.5) + thread_safe (0.3.6) + tilt (2.0.6) timecop (0.8.1) timfel-krb5-auth (0.8.3) tool (0.2.3) @@ -776,7 +792,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.2) - unicode-display_width (1.1.1) + unicode-display_width (1.1.3) unicorn (5.1.0) kgio (~> 2.6) raindrops (~> 0.7) @@ -784,6 +800,7 @@ GEM get_process_mem (~> 0) unicorn (>= 4, < 6) uniform_notifier (1.10.0) + url_safe_base64 (0.2.2) validates_hostname (1.0.6) activerecord (>= 3.0) activesupport (>= 3.0) @@ -846,7 +863,7 @@ DEPENDENCIES bundler-audit (~> 0.5.0) capybara (~> 2.6.2) capybara-screenshot (~> 1.0.0) - carrierwave (~> 0.10.0) + carrierwave (~> 0.11.0) charlock_holmes (~> 0.7.3) chronic (~> 0.10.2) chronic_duration (~> 0.10.6) @@ -861,6 +878,7 @@ DEPENDENCIES devise-two-factor (~> 3.0.0) diffy (~> 3.1.0) doorkeeper (~> 4.2.0) + doorkeeper-openid_connect (~> 1.1.0) dropzonejs-rails (~> 0.7.1) email_reply_trimmer (~> 0.1) email_spec (~> 1.6.0) @@ -873,11 +891,12 @@ DEPENDENCIES fog-local (~> 0.3) fog-openstack (~> 0.1) fog-rackspace (~> 0.1.1) - font-awesome-rails (~> 4.6.1) + font-awesome-rails (~> 4.7) foreman (~> 0.78.0) fuubar (~> 2.0.0) gemnasium-gitlab-service (~> 0.2) gemojione (~> 3.0) + gitaly (~> 0.3.0) github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.5.1) @@ -886,11 +905,11 @@ DEPENDENCIES gollum-rugged_adapter (~> 0.4.2) gon (~> 6.1.0) google-api-client (~> 0.8.6) - grape (~> 0.18.0) + grape (~> 0.19.0) grape-entity (~> 0.6.0) - haml_lint (~> 0.18.2) + haml_lint (~> 0.21.0) hamlit (~> 2.6.1) - health_check (~> 2.2.0) + health_check (~> 2.6.0) hipchat (~> 1.5.0) html-pipeline (~> 1.11.0) html2text @@ -899,7 +918,6 @@ DEPENDENCIES jira-ruby (~> 1.1.2) jquery-atwho-rails (~> 1.3.2) jquery-rails (~> 4.1.0) - jquery-ui-rails (~> 5.0.0) json-schema (~> 2.6.2) jwt (~> 1.5.6) kaminari (~> 0.17.0) @@ -907,7 +925,7 @@ DEPENDENCIES kubeclient (~> 2.2.0) letter_opener_web (~> 1.3.0) license_finder (~> 2.1.0) - licensee (~> 8.0.0) + licensee (~> 8.7.0) loofah (~> 2.0.3) mail_room (~> 0.9.1) method_source (~> 0.8) @@ -915,12 +933,11 @@ DEPENDENCIES mousetrap-rails (~> 1.4.6) mysql2 (~> 0.3.16) net-ssh (~> 3.0.1) - newrelic_rpm (~> 3.16) nokogiri (~> 1.6.7, >= 1.6.7.2) oauth2 (~> 1.2.0) octokit (~> 4.6.2) oj (~> 2.17.4) - omniauth (~> 1.3.2) + omniauth (~> 1.4.2) omniauth-auth0 (~> 1.4.1) omniauth-authentiq (~> 0.3.0) omniauth-azure-oauth2 (~> 0.0.6) @@ -952,7 +969,7 @@ DEPENDENCIES rblineprof (~> 0.3.6) rdoc (~> 4.2) recaptcha (~> 3.0) - redcarpet (~> 3.3.3) + redcarpet (~> 3.4) redis (~> 3.2) redis-namespace (~> 1.5.2) redis-rails (~> 5.0.1) @@ -963,8 +980,8 @@ DEPENDENCIES rspec-rails (~> 3.5.0) rspec-retry (~> 0.4.5) rspec_profiling (~> 0.0.5) - rubocop (~> 0.46.0) - rubocop-rspec (~> 1.9.1) + rubocop (~> 0.47.1) + rubocop-rspec (~> 1.12.0) ruby-fogbugz (~> 0.2.1) ruby-prof (~> 0.16.2) rugged (~> 0.24.0) @@ -1011,4 +1028,4 @@ DEPENDENCIES wikicloth (= 0.8.1) BUNDLED WITH - 1.14.3 + 1.14.5 diff --git a/VERSION b/VERSION index 5c99c061a47..64de8316674 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.17.0-pre +8.18.0-pre diff --git a/app/assets/images/emoji.png b/app/assets/images/emoji.png index 6f1a34a5591..5dcd9c09b70 100644 Binary files a/app/assets/images/emoji.png and b/app/assets/images/emoji.png differ diff --git a/app/assets/images/emoji/100.png b/app/assets/images/emoji/100.png new file mode 100644 index 00000000000..6903ff0304a Binary files /dev/null and b/app/assets/images/emoji/100.png differ diff --git a/app/assets/images/emoji/1234.png b/app/assets/images/emoji/1234.png new file mode 100644 index 00000000000..248dc7e55b6 Binary files /dev/null and b/app/assets/images/emoji/1234.png differ diff --git a/app/assets/images/emoji/1F627.png b/app/assets/images/emoji/1F627.png new file mode 100644 index 00000000000..f99026a3bc7 Binary files /dev/null and b/app/assets/images/emoji/1F627.png differ diff --git a/app/assets/images/emoji/8ball.png b/app/assets/images/emoji/8ball.png new file mode 100644 index 00000000000..38ca662eded Binary files /dev/null and b/app/assets/images/emoji/8ball.png differ diff --git a/app/assets/images/emoji/a.png b/app/assets/images/emoji/a.png new file mode 100644 index 00000000000..8603ff05a17 Binary files /dev/null and b/app/assets/images/emoji/a.png differ diff --git a/app/assets/images/emoji/ab.png b/app/assets/images/emoji/ab.png new file mode 100644 index 00000000000..d9f2d17dea0 Binary files /dev/null and b/app/assets/images/emoji/ab.png differ diff --git a/app/assets/images/emoji/abc.png b/app/assets/images/emoji/abc.png new file mode 100644 index 00000000000..7688de692a9 Binary files /dev/null and b/app/assets/images/emoji/abc.png differ diff --git a/app/assets/images/emoji/abcd.png b/app/assets/images/emoji/abcd.png new file mode 100644 index 00000000000..0996a870570 Binary files /dev/null and b/app/assets/images/emoji/abcd.png differ diff --git a/app/assets/images/emoji/accept.png b/app/assets/images/emoji/accept.png new file mode 100644 index 00000000000..8afd7ce99cf Binary files /dev/null and b/app/assets/images/emoji/accept.png differ diff --git a/app/assets/images/emoji/aerial_tramway.png b/app/assets/images/emoji/aerial_tramway.png new file mode 100644 index 00000000000..3eb4b61bf1d Binary files /dev/null and b/app/assets/images/emoji/aerial_tramway.png differ diff --git a/app/assets/images/emoji/airplane.png b/app/assets/images/emoji/airplane.png new file mode 100644 index 00000000000..268d2ac3c8e Binary files /dev/null and b/app/assets/images/emoji/airplane.png differ diff --git a/app/assets/images/emoji/airplane_arriving.png b/app/assets/images/emoji/airplane_arriving.png new file mode 100644 index 00000000000..d66841962f2 Binary files /dev/null and b/app/assets/images/emoji/airplane_arriving.png differ diff --git a/app/assets/images/emoji/airplane_departure.png b/app/assets/images/emoji/airplane_departure.png new file mode 100644 index 00000000000..a5766f9f4ae Binary files /dev/null and b/app/assets/images/emoji/airplane_departure.png differ diff --git a/app/assets/images/emoji/airplane_small.png b/app/assets/images/emoji/airplane_small.png new file mode 100644 index 00000000000..b731b15e3a8 Binary files /dev/null and b/app/assets/images/emoji/airplane_small.png differ diff --git a/app/assets/images/emoji/alarm_clock.png b/app/assets/images/emoji/alarm_clock.png new file mode 100644 index 00000000000..cdbc2fbb950 Binary files /dev/null and b/app/assets/images/emoji/alarm_clock.png differ diff --git a/app/assets/images/emoji/alembic.png b/app/assets/images/emoji/alembic.png new file mode 100644 index 00000000000..307a7324249 Binary files /dev/null and b/app/assets/images/emoji/alembic.png differ diff --git a/app/assets/images/emoji/alien.png b/app/assets/images/emoji/alien.png new file mode 100644 index 00000000000..3b90e97433b Binary files /dev/null and b/app/assets/images/emoji/alien.png differ diff --git a/app/assets/images/emoji/ambulance.png b/app/assets/images/emoji/ambulance.png new file mode 100644 index 00000000000..6fb8076d766 Binary files /dev/null and b/app/assets/images/emoji/ambulance.png differ diff --git a/app/assets/images/emoji/amphora.png b/app/assets/images/emoji/amphora.png new file mode 100644 index 00000000000..96de5056059 Binary files /dev/null and b/app/assets/images/emoji/amphora.png differ diff --git a/app/assets/images/emoji/anchor.png b/app/assets/images/emoji/anchor.png new file mode 100644 index 00000000000..b036f70a00b Binary files /dev/null and b/app/assets/images/emoji/anchor.png differ diff --git a/app/assets/images/emoji/angel.png b/app/assets/images/emoji/angel.png new file mode 100644 index 00000000000..66ea97a3b99 Binary files /dev/null and b/app/assets/images/emoji/angel.png differ diff --git a/app/assets/images/emoji/angel_tone1.png b/app/assets/images/emoji/angel_tone1.png new file mode 100644 index 00000000000..391694dc07e Binary files /dev/null and b/app/assets/images/emoji/angel_tone1.png differ diff --git a/app/assets/images/emoji/angel_tone2.png b/app/assets/images/emoji/angel_tone2.png new file mode 100644 index 00000000000..700cbe6ed2c Binary files /dev/null and b/app/assets/images/emoji/angel_tone2.png differ diff --git a/app/assets/images/emoji/angel_tone3.png b/app/assets/images/emoji/angel_tone3.png new file mode 100644 index 00000000000..be597437d25 Binary files /dev/null and b/app/assets/images/emoji/angel_tone3.png differ diff --git a/app/assets/images/emoji/angel_tone4.png b/app/assets/images/emoji/angel_tone4.png new file mode 100644 index 00000000000..b06d3c853ef Binary files /dev/null and b/app/assets/images/emoji/angel_tone4.png differ diff --git a/app/assets/images/emoji/angel_tone5.png b/app/assets/images/emoji/angel_tone5.png new file mode 100644 index 00000000000..17bd677e334 Binary files /dev/null and b/app/assets/images/emoji/angel_tone5.png differ diff --git a/app/assets/images/emoji/anger.png b/app/assets/images/emoji/anger.png new file mode 100644 index 00000000000..d63c2e000e4 Binary files /dev/null and b/app/assets/images/emoji/anger.png differ diff --git a/app/assets/images/emoji/anger_right.png b/app/assets/images/emoji/anger_right.png new file mode 100644 index 00000000000..f5c97c4d297 Binary files /dev/null and b/app/assets/images/emoji/anger_right.png differ diff --git a/app/assets/images/emoji/angry.png b/app/assets/images/emoji/angry.png new file mode 100644 index 00000000000..cfc4a6ecde5 Binary files /dev/null and b/app/assets/images/emoji/angry.png differ diff --git a/app/assets/images/emoji/ant.png b/app/assets/images/emoji/ant.png new file mode 100644 index 00000000000..994127ed6b3 Binary files /dev/null and b/app/assets/images/emoji/ant.png differ diff --git a/app/assets/images/emoji/apple.png b/app/assets/images/emoji/apple.png new file mode 100644 index 00000000000..da650c60f62 Binary files /dev/null and b/app/assets/images/emoji/apple.png differ diff --git a/app/assets/images/emoji/aquarius.png b/app/assets/images/emoji/aquarius.png new file mode 100644 index 00000000000..641a4f68889 Binary files /dev/null and b/app/assets/images/emoji/aquarius.png differ diff --git a/app/assets/images/emoji/aries.png b/app/assets/images/emoji/aries.png new file mode 100644 index 00000000000..21a189d0ede Binary files /dev/null and b/app/assets/images/emoji/aries.png differ diff --git a/app/assets/images/emoji/arrow_backward.png b/app/assets/images/emoji/arrow_backward.png new file mode 100644 index 00000000000..ee38e3b038e Binary files /dev/null and b/app/assets/images/emoji/arrow_backward.png differ diff --git a/app/assets/images/emoji/arrow_double_down.png b/app/assets/images/emoji/arrow_double_down.png new file mode 100644 index 00000000000..90193bfcb40 Binary files /dev/null and b/app/assets/images/emoji/arrow_double_down.png differ diff --git a/app/assets/images/emoji/arrow_double_up.png b/app/assets/images/emoji/arrow_double_up.png new file mode 100644 index 00000000000..13543d5eef2 Binary files /dev/null and b/app/assets/images/emoji/arrow_double_up.png differ diff --git a/app/assets/images/emoji/arrow_down.png b/app/assets/images/emoji/arrow_down.png new file mode 100644 index 00000000000..b8eefd0b19f Binary files /dev/null and b/app/assets/images/emoji/arrow_down.png differ diff --git a/app/assets/images/emoji/arrow_down_small.png b/app/assets/images/emoji/arrow_down_small.png new file mode 100644 index 00000000000..5870b9a2241 Binary files /dev/null and b/app/assets/images/emoji/arrow_down_small.png differ diff --git a/app/assets/images/emoji/arrow_forward.png b/app/assets/images/emoji/arrow_forward.png new file mode 100644 index 00000000000..4e2b682857c Binary files /dev/null and b/app/assets/images/emoji/arrow_forward.png differ diff --git a/app/assets/images/emoji/arrow_heading_down.png b/app/assets/images/emoji/arrow_heading_down.png new file mode 100644 index 00000000000..2d9d24bca80 Binary files /dev/null and b/app/assets/images/emoji/arrow_heading_down.png differ diff --git a/app/assets/images/emoji/arrow_heading_up.png b/app/assets/images/emoji/arrow_heading_up.png new file mode 100644 index 00000000000..f29bfcfc0de Binary files /dev/null and b/app/assets/images/emoji/arrow_heading_up.png differ diff --git a/app/assets/images/emoji/arrow_left.png b/app/assets/images/emoji/arrow_left.png new file mode 100644 index 00000000000..8c685e0a81b Binary files /dev/null and b/app/assets/images/emoji/arrow_left.png differ diff --git a/app/assets/images/emoji/arrow_lower_left.png b/app/assets/images/emoji/arrow_lower_left.png new file mode 100644 index 00000000000..88b37716078 Binary files /dev/null and b/app/assets/images/emoji/arrow_lower_left.png differ diff --git a/app/assets/images/emoji/arrow_lower_right.png b/app/assets/images/emoji/arrow_lower_right.png new file mode 100644 index 00000000000..7e807da7392 Binary files /dev/null and b/app/assets/images/emoji/arrow_lower_right.png differ diff --git a/app/assets/images/emoji/arrow_right.png b/app/assets/images/emoji/arrow_right.png new file mode 100644 index 00000000000..4755670b5cc Binary files /dev/null and b/app/assets/images/emoji/arrow_right.png differ diff --git a/app/assets/images/emoji/arrow_right_hook.png b/app/assets/images/emoji/arrow_right_hook.png new file mode 100644 index 00000000000..e7258ad3268 Binary files /dev/null and b/app/assets/images/emoji/arrow_right_hook.png differ diff --git a/app/assets/images/emoji/arrow_up.png b/app/assets/images/emoji/arrow_up.png new file mode 100644 index 00000000000..af8218a87f7 Binary files /dev/null and b/app/assets/images/emoji/arrow_up.png differ diff --git a/app/assets/images/emoji/arrow_up_down.png b/app/assets/images/emoji/arrow_up_down.png new file mode 100644 index 00000000000..dfa32b97186 Binary files /dev/null and b/app/assets/images/emoji/arrow_up_down.png differ diff --git a/app/assets/images/emoji/arrow_up_small.png b/app/assets/images/emoji/arrow_up_small.png new file mode 100644 index 00000000000..20a13dcd5cd Binary files /dev/null and b/app/assets/images/emoji/arrow_up_small.png differ diff --git a/app/assets/images/emoji/arrow_upper_left.png b/app/assets/images/emoji/arrow_upper_left.png new file mode 100644 index 00000000000..f38718fbe34 Binary files /dev/null and b/app/assets/images/emoji/arrow_upper_left.png differ diff --git a/app/assets/images/emoji/arrow_upper_right.png b/app/assets/images/emoji/arrow_upper_right.png new file mode 100644 index 00000000000..c43e12d0f64 Binary files /dev/null and b/app/assets/images/emoji/arrow_upper_right.png differ diff --git a/app/assets/images/emoji/arrows_clockwise.png b/app/assets/images/emoji/arrows_clockwise.png new file mode 100644 index 00000000000..26e49c38388 Binary files /dev/null and b/app/assets/images/emoji/arrows_clockwise.png differ diff --git a/app/assets/images/emoji/arrows_counterclockwise.png b/app/assets/images/emoji/arrows_counterclockwise.png new file mode 100644 index 00000000000..8d06d8e0912 Binary files /dev/null and b/app/assets/images/emoji/arrows_counterclockwise.png differ diff --git a/app/assets/images/emoji/art.png b/app/assets/images/emoji/art.png new file mode 100644 index 00000000000..bd6afe9ff06 Binary files /dev/null and b/app/assets/images/emoji/art.png differ diff --git a/app/assets/images/emoji/articulated_lorry.png b/app/assets/images/emoji/articulated_lorry.png new file mode 100644 index 00000000000..c8217317132 Binary files /dev/null and b/app/assets/images/emoji/articulated_lorry.png differ diff --git a/app/assets/images/emoji/asterisk.png b/app/assets/images/emoji/asterisk.png new file mode 100644 index 00000000000..2f8e5113803 Binary files /dev/null and b/app/assets/images/emoji/asterisk.png differ diff --git a/app/assets/images/emoji/astonished.png b/app/assets/images/emoji/astonished.png new file mode 100644 index 00000000000..bd0ac55ec8e Binary files /dev/null and b/app/assets/images/emoji/astonished.png differ diff --git a/app/assets/images/emoji/athletic_shoe.png b/app/assets/images/emoji/athletic_shoe.png new file mode 100644 index 00000000000..423fa07dd5d Binary files /dev/null and b/app/assets/images/emoji/athletic_shoe.png differ diff --git a/app/assets/images/emoji/atm.png b/app/assets/images/emoji/atm.png new file mode 100644 index 00000000000..4d935307b94 Binary files /dev/null and b/app/assets/images/emoji/atm.png differ diff --git a/app/assets/images/emoji/atom.png b/app/assets/images/emoji/atom.png new file mode 100644 index 00000000000..5f4567aa093 Binary files /dev/null and b/app/assets/images/emoji/atom.png differ diff --git a/app/assets/images/emoji/avocado.png b/app/assets/images/emoji/avocado.png new file mode 100644 index 00000000000..06f0d124aed Binary files /dev/null and b/app/assets/images/emoji/avocado.png differ diff --git a/app/assets/images/emoji/b.png b/app/assets/images/emoji/b.png new file mode 100644 index 00000000000..25875bc6a14 Binary files /dev/null and b/app/assets/images/emoji/b.png differ diff --git a/app/assets/images/emoji/baby.png b/app/assets/images/emoji/baby.png new file mode 100644 index 00000000000..a4af92c63c7 Binary files /dev/null and b/app/assets/images/emoji/baby.png differ diff --git a/app/assets/images/emoji/baby_bottle.png b/app/assets/images/emoji/baby_bottle.png new file mode 100644 index 00000000000..2bd10524180 Binary files /dev/null and b/app/assets/images/emoji/baby_bottle.png differ diff --git a/app/assets/images/emoji/baby_chick.png b/app/assets/images/emoji/baby_chick.png new file mode 100644 index 00000000000..dccd96576ea Binary files /dev/null and b/app/assets/images/emoji/baby_chick.png differ diff --git a/app/assets/images/emoji/baby_symbol.png b/app/assets/images/emoji/baby_symbol.png new file mode 100644 index 00000000000..64a10b71710 Binary files /dev/null and b/app/assets/images/emoji/baby_symbol.png differ diff --git a/app/assets/images/emoji/baby_tone1.png b/app/assets/images/emoji/baby_tone1.png new file mode 100644 index 00000000000..d20911d40db Binary files /dev/null and b/app/assets/images/emoji/baby_tone1.png differ diff --git a/app/assets/images/emoji/baby_tone2.png b/app/assets/images/emoji/baby_tone2.png new file mode 100644 index 00000000000..b0a9b30ed17 Binary files /dev/null and b/app/assets/images/emoji/baby_tone2.png differ diff --git a/app/assets/images/emoji/baby_tone3.png b/app/assets/images/emoji/baby_tone3.png new file mode 100644 index 00000000000..7de5286fac1 Binary files /dev/null and b/app/assets/images/emoji/baby_tone3.png differ diff --git a/app/assets/images/emoji/baby_tone4.png b/app/assets/images/emoji/baby_tone4.png new file mode 100644 index 00000000000..9b7a86ac615 Binary files /dev/null and b/app/assets/images/emoji/baby_tone4.png differ diff --git a/app/assets/images/emoji/baby_tone5.png b/app/assets/images/emoji/baby_tone5.png new file mode 100644 index 00000000000..fe1be34cb88 Binary files /dev/null and b/app/assets/images/emoji/baby_tone5.png differ diff --git a/app/assets/images/emoji/back.png b/app/assets/images/emoji/back.png new file mode 100644 index 00000000000..d32c5d4f17f Binary files /dev/null and b/app/assets/images/emoji/back.png differ diff --git a/app/assets/images/emoji/bacon.png b/app/assets/images/emoji/bacon.png new file mode 100644 index 00000000000..f38a485fbe4 Binary files /dev/null and b/app/assets/images/emoji/bacon.png differ diff --git a/app/assets/images/emoji/badminton.png b/app/assets/images/emoji/badminton.png new file mode 100644 index 00000000000..7ba15708990 Binary files /dev/null and b/app/assets/images/emoji/badminton.png differ diff --git a/app/assets/images/emoji/baggage_claim.png b/app/assets/images/emoji/baggage_claim.png new file mode 100644 index 00000000000..409b593e78a Binary files /dev/null and b/app/assets/images/emoji/baggage_claim.png differ diff --git a/app/assets/images/emoji/balloon.png b/app/assets/images/emoji/balloon.png new file mode 100644 index 00000000000..07916fe6df1 Binary files /dev/null and b/app/assets/images/emoji/balloon.png differ diff --git a/app/assets/images/emoji/ballot_box.png b/app/assets/images/emoji/ballot_box.png new file mode 100644 index 00000000000..9b6767aea9e Binary files /dev/null and b/app/assets/images/emoji/ballot_box.png differ diff --git a/app/assets/images/emoji/ballot_box_with_check.png b/app/assets/images/emoji/ballot_box_with_check.png new file mode 100644 index 00000000000..284d9573847 Binary files /dev/null and b/app/assets/images/emoji/ballot_box_with_check.png differ diff --git a/app/assets/images/emoji/bamboo.png b/app/assets/images/emoji/bamboo.png new file mode 100644 index 00000000000..5d5e0e728a0 Binary files /dev/null and b/app/assets/images/emoji/bamboo.png differ diff --git a/app/assets/images/emoji/banana.png b/app/assets/images/emoji/banana.png new file mode 100644 index 00000000000..f4987279580 Binary files /dev/null and b/app/assets/images/emoji/banana.png differ diff --git a/app/assets/images/emoji/bangbang.png b/app/assets/images/emoji/bangbang.png new file mode 100644 index 00000000000..58a9c528fca Binary files /dev/null and b/app/assets/images/emoji/bangbang.png differ diff --git a/app/assets/images/emoji/bank.png b/app/assets/images/emoji/bank.png new file mode 100644 index 00000000000..dffdcef36a1 Binary files /dev/null and b/app/assets/images/emoji/bank.png differ diff --git a/app/assets/images/emoji/bar_chart.png b/app/assets/images/emoji/bar_chart.png new file mode 100644 index 00000000000..53c89455008 Binary files /dev/null and b/app/assets/images/emoji/bar_chart.png differ diff --git a/app/assets/images/emoji/barber.png b/app/assets/images/emoji/barber.png new file mode 100644 index 00000000000..896f4d716cf Binary files /dev/null and b/app/assets/images/emoji/barber.png differ diff --git a/app/assets/images/emoji/baseball.png b/app/assets/images/emoji/baseball.png new file mode 100644 index 00000000000..f8463f1538b Binary files /dev/null and b/app/assets/images/emoji/baseball.png differ diff --git a/app/assets/images/emoji/basketball.png b/app/assets/images/emoji/basketball.png new file mode 100644 index 00000000000..64c76b79c6d Binary files /dev/null and b/app/assets/images/emoji/basketball.png differ diff --git a/app/assets/images/emoji/basketball_player.png b/app/assets/images/emoji/basketball_player.png new file mode 100644 index 00000000000..8ce90c5cad6 Binary files /dev/null and b/app/assets/images/emoji/basketball_player.png differ diff --git a/app/assets/images/emoji/basketball_player_tone1.png b/app/assets/images/emoji/basketball_player_tone1.png new file mode 100644 index 00000000000..cd12c7ab9bf Binary files /dev/null and b/app/assets/images/emoji/basketball_player_tone1.png differ diff --git a/app/assets/images/emoji/basketball_player_tone2.png b/app/assets/images/emoji/basketball_player_tone2.png new file mode 100644 index 00000000000..f892fd596da Binary files /dev/null and b/app/assets/images/emoji/basketball_player_tone2.png differ diff --git a/app/assets/images/emoji/basketball_player_tone3.png b/app/assets/images/emoji/basketball_player_tone3.png new file mode 100644 index 00000000000..e109997a91a Binary files /dev/null and b/app/assets/images/emoji/basketball_player_tone3.png differ diff --git a/app/assets/images/emoji/basketball_player_tone4.png b/app/assets/images/emoji/basketball_player_tone4.png new file mode 100644 index 00000000000..3b90b946af4 Binary files /dev/null and b/app/assets/images/emoji/basketball_player_tone4.png differ diff --git a/app/assets/images/emoji/basketball_player_tone5.png b/app/assets/images/emoji/basketball_player_tone5.png new file mode 100644 index 00000000000..bafed7828a7 Binary files /dev/null and b/app/assets/images/emoji/basketball_player_tone5.png differ diff --git a/app/assets/images/emoji/bat.png b/app/assets/images/emoji/bat.png new file mode 100644 index 00000000000..3152c047e00 Binary files /dev/null and b/app/assets/images/emoji/bat.png differ diff --git a/app/assets/images/emoji/bath.png b/app/assets/images/emoji/bath.png new file mode 100644 index 00000000000..43fba5c8a28 Binary files /dev/null and b/app/assets/images/emoji/bath.png differ diff --git a/app/assets/images/emoji/bath_tone1.png b/app/assets/images/emoji/bath_tone1.png new file mode 100644 index 00000000000..2152eabf2f5 Binary files /dev/null and b/app/assets/images/emoji/bath_tone1.png differ diff --git a/app/assets/images/emoji/bath_tone2.png b/app/assets/images/emoji/bath_tone2.png new file mode 100644 index 00000000000..2102e6133e3 Binary files /dev/null and b/app/assets/images/emoji/bath_tone2.png differ diff --git a/app/assets/images/emoji/bath_tone3.png b/app/assets/images/emoji/bath_tone3.png new file mode 100644 index 00000000000..fae66181e9f Binary files /dev/null and b/app/assets/images/emoji/bath_tone3.png differ diff --git a/app/assets/images/emoji/bath_tone4.png b/app/assets/images/emoji/bath_tone4.png new file mode 100644 index 00000000000..1f8959d0d99 Binary files /dev/null and b/app/assets/images/emoji/bath_tone4.png differ diff --git a/app/assets/images/emoji/bath_tone5.png b/app/assets/images/emoji/bath_tone5.png new file mode 100644 index 00000000000..c8a08e84f25 Binary files /dev/null and b/app/assets/images/emoji/bath_tone5.png differ diff --git a/app/assets/images/emoji/bathtub.png b/app/assets/images/emoji/bathtub.png new file mode 100644 index 00000000000..9a5f09361eb Binary files /dev/null and b/app/assets/images/emoji/bathtub.png differ diff --git a/app/assets/images/emoji/battery.png b/app/assets/images/emoji/battery.png new file mode 100644 index 00000000000..f593e2bdb65 Binary files /dev/null and b/app/assets/images/emoji/battery.png differ diff --git a/app/assets/images/emoji/beach.png b/app/assets/images/emoji/beach.png new file mode 100644 index 00000000000..69108c8ea10 Binary files /dev/null and b/app/assets/images/emoji/beach.png differ diff --git a/app/assets/images/emoji/beach_umbrella.png b/app/assets/images/emoji/beach_umbrella.png new file mode 100644 index 00000000000..220a74f8132 Binary files /dev/null and b/app/assets/images/emoji/beach_umbrella.png differ diff --git a/app/assets/images/emoji/bear.png b/app/assets/images/emoji/bear.png new file mode 100644 index 00000000000..272d56bbbcc Binary files /dev/null and b/app/assets/images/emoji/bear.png differ diff --git a/app/assets/images/emoji/bed.png b/app/assets/images/emoji/bed.png new file mode 100644 index 00000000000..86f964e245d Binary files /dev/null and b/app/assets/images/emoji/bed.png differ diff --git a/app/assets/images/emoji/bee.png b/app/assets/images/emoji/bee.png new file mode 100644 index 00000000000..46156060096 Binary files /dev/null and b/app/assets/images/emoji/bee.png differ diff --git a/app/assets/images/emoji/beer.png b/app/assets/images/emoji/beer.png new file mode 100644 index 00000000000..b6d73dc0b7a Binary files /dev/null and b/app/assets/images/emoji/beer.png differ diff --git a/app/assets/images/emoji/beers.png b/app/assets/images/emoji/beers.png new file mode 100644 index 00000000000..b55deb66b41 Binary files /dev/null and b/app/assets/images/emoji/beers.png differ diff --git a/app/assets/images/emoji/beetle.png b/app/assets/images/emoji/beetle.png new file mode 100644 index 00000000000..3d93174d7fc Binary files /dev/null and b/app/assets/images/emoji/beetle.png differ diff --git a/app/assets/images/emoji/beginner.png b/app/assets/images/emoji/beginner.png new file mode 100644 index 00000000000..bc434fb7cb5 Binary files /dev/null and b/app/assets/images/emoji/beginner.png differ diff --git a/app/assets/images/emoji/bell.png b/app/assets/images/emoji/bell.png new file mode 100644 index 00000000000..5b3b0461999 Binary files /dev/null and b/app/assets/images/emoji/bell.png differ diff --git a/app/assets/images/emoji/bellhop.png b/app/assets/images/emoji/bellhop.png new file mode 100644 index 00000000000..6b3297ceaf7 Binary files /dev/null and b/app/assets/images/emoji/bellhop.png differ diff --git a/app/assets/images/emoji/bento.png b/app/assets/images/emoji/bento.png new file mode 100644 index 00000000000..83d41ca7eb9 Binary files /dev/null and b/app/assets/images/emoji/bento.png differ diff --git a/app/assets/images/emoji/bicyclist.png b/app/assets/images/emoji/bicyclist.png new file mode 100644 index 00000000000..9274da11048 Binary files /dev/null and b/app/assets/images/emoji/bicyclist.png differ diff --git a/app/assets/images/emoji/bicyclist_tone1.png b/app/assets/images/emoji/bicyclist_tone1.png new file mode 100644 index 00000000000..decc2f728fe Binary files /dev/null and b/app/assets/images/emoji/bicyclist_tone1.png differ diff --git a/app/assets/images/emoji/bicyclist_tone2.png b/app/assets/images/emoji/bicyclist_tone2.png new file mode 100644 index 00000000000..0067717b80a Binary files /dev/null and b/app/assets/images/emoji/bicyclist_tone2.png differ diff --git a/app/assets/images/emoji/bicyclist_tone3.png b/app/assets/images/emoji/bicyclist_tone3.png new file mode 100644 index 00000000000..a4f7b5e2776 Binary files /dev/null and b/app/assets/images/emoji/bicyclist_tone3.png differ diff --git a/app/assets/images/emoji/bicyclist_tone4.png b/app/assets/images/emoji/bicyclist_tone4.png new file mode 100644 index 00000000000..a3c8a797db4 Binary files /dev/null and b/app/assets/images/emoji/bicyclist_tone4.png differ diff --git a/app/assets/images/emoji/bicyclist_tone5.png b/app/assets/images/emoji/bicyclist_tone5.png new file mode 100644 index 00000000000..1606a874051 Binary files /dev/null and b/app/assets/images/emoji/bicyclist_tone5.png differ diff --git a/app/assets/images/emoji/bike.png b/app/assets/images/emoji/bike.png new file mode 100644 index 00000000000..556ed70f1a7 Binary files /dev/null and b/app/assets/images/emoji/bike.png differ diff --git a/app/assets/images/emoji/bikini.png b/app/assets/images/emoji/bikini.png new file mode 100644 index 00000000000..77a8a0aae5b Binary files /dev/null and b/app/assets/images/emoji/bikini.png differ diff --git a/app/assets/images/emoji/biohazard.png b/app/assets/images/emoji/biohazard.png new file mode 100644 index 00000000000..007b4fc2d85 Binary files /dev/null and b/app/assets/images/emoji/biohazard.png differ diff --git a/app/assets/images/emoji/bird.png b/app/assets/images/emoji/bird.png new file mode 100644 index 00000000000..e201c22be33 Binary files /dev/null and b/app/assets/images/emoji/bird.png differ diff --git a/app/assets/images/emoji/birthday.png b/app/assets/images/emoji/birthday.png new file mode 100644 index 00000000000..317e9a41949 Binary files /dev/null and b/app/assets/images/emoji/birthday.png differ diff --git a/app/assets/images/emoji/black_circle.png b/app/assets/images/emoji/black_circle.png new file mode 100644 index 00000000000..b62b87170e8 Binary files /dev/null and b/app/assets/images/emoji/black_circle.png differ diff --git a/app/assets/images/emoji/black_heart.png b/app/assets/images/emoji/black_heart.png new file mode 100644 index 00000000000..b4068c3e6e8 Binary files /dev/null and b/app/assets/images/emoji/black_heart.png differ diff --git a/app/assets/images/emoji/black_joker.png b/app/assets/images/emoji/black_joker.png new file mode 100644 index 00000000000..3d0924b68aa Binary files /dev/null and b/app/assets/images/emoji/black_joker.png differ diff --git a/app/assets/images/emoji/black_large_square.png b/app/assets/images/emoji/black_large_square.png new file mode 100644 index 00000000000..162f2bb4290 Binary files /dev/null and b/app/assets/images/emoji/black_large_square.png differ diff --git a/app/assets/images/emoji/black_medium_small_square.png b/app/assets/images/emoji/black_medium_small_square.png new file mode 100644 index 00000000000..39765bba610 Binary files /dev/null and b/app/assets/images/emoji/black_medium_small_square.png differ diff --git a/app/assets/images/emoji/black_medium_square.png b/app/assets/images/emoji/black_medium_square.png new file mode 100644 index 00000000000..05a30a6aa2d Binary files /dev/null and b/app/assets/images/emoji/black_medium_square.png differ diff --git a/app/assets/images/emoji/black_nib.png b/app/assets/images/emoji/black_nib.png new file mode 100644 index 00000000000..872d0ae1598 Binary files /dev/null and b/app/assets/images/emoji/black_nib.png differ diff --git a/app/assets/images/emoji/black_small_square.png b/app/assets/images/emoji/black_small_square.png new file mode 100644 index 00000000000..48595d3e1a9 Binary files /dev/null and b/app/assets/images/emoji/black_small_square.png differ diff --git a/app/assets/images/emoji/black_square_button.png b/app/assets/images/emoji/black_square_button.png new file mode 100644 index 00000000000..a78fc2f6b63 Binary files /dev/null and b/app/assets/images/emoji/black_square_button.png differ diff --git a/app/assets/images/emoji/blossom.png b/app/assets/images/emoji/blossom.png new file mode 100644 index 00000000000..4083026c157 Binary files /dev/null and b/app/assets/images/emoji/blossom.png differ diff --git a/app/assets/images/emoji/blowfish.png b/app/assets/images/emoji/blowfish.png new file mode 100644 index 00000000000..a10f4f84e35 Binary files /dev/null and b/app/assets/images/emoji/blowfish.png differ diff --git a/app/assets/images/emoji/blue_book.png b/app/assets/images/emoji/blue_book.png new file mode 100644 index 00000000000..e1e455401cc Binary files /dev/null and b/app/assets/images/emoji/blue_book.png differ diff --git a/app/assets/images/emoji/blue_car.png b/app/assets/images/emoji/blue_car.png new file mode 100644 index 00000000000..e8ba817d393 Binary files /dev/null and b/app/assets/images/emoji/blue_car.png differ diff --git a/app/assets/images/emoji/blue_heart.png b/app/assets/images/emoji/blue_heart.png new file mode 100644 index 00000000000..bdf1287e55e Binary files /dev/null and b/app/assets/images/emoji/blue_heart.png differ diff --git a/app/assets/images/emoji/blush.png b/app/assets/images/emoji/blush.png new file mode 100644 index 00000000000..aac1a424ad4 Binary files /dev/null and b/app/assets/images/emoji/blush.png differ diff --git a/app/assets/images/emoji/boar.png b/app/assets/images/emoji/boar.png new file mode 100644 index 00000000000..fead972633c Binary files /dev/null and b/app/assets/images/emoji/boar.png differ diff --git a/app/assets/images/emoji/bomb.png b/app/assets/images/emoji/bomb.png new file mode 100644 index 00000000000..c7f8f81c939 Binary files /dev/null and b/app/assets/images/emoji/bomb.png differ diff --git a/app/assets/images/emoji/book.png b/app/assets/images/emoji/book.png new file mode 100644 index 00000000000..0f4447ed396 Binary files /dev/null and b/app/assets/images/emoji/book.png differ diff --git a/app/assets/images/emoji/bookmark.png b/app/assets/images/emoji/bookmark.png new file mode 100644 index 00000000000..bbb444611f0 Binary files /dev/null and b/app/assets/images/emoji/bookmark.png differ diff --git a/app/assets/images/emoji/bookmark_tabs.png b/app/assets/images/emoji/bookmark_tabs.png new file mode 100644 index 00000000000..f8d9e01b428 Binary files /dev/null and b/app/assets/images/emoji/bookmark_tabs.png differ diff --git a/app/assets/images/emoji/books.png b/app/assets/images/emoji/books.png new file mode 100644 index 00000000000..59a8bafeb0d Binary files /dev/null and b/app/assets/images/emoji/books.png differ diff --git a/app/assets/images/emoji/boom.png b/app/assets/images/emoji/boom.png new file mode 100644 index 00000000000..9b0f027b1a8 Binary files /dev/null and b/app/assets/images/emoji/boom.png differ diff --git a/app/assets/images/emoji/boot.png b/app/assets/images/emoji/boot.png new file mode 100644 index 00000000000..11f1065ed07 Binary files /dev/null and b/app/assets/images/emoji/boot.png differ diff --git a/app/assets/images/emoji/bouquet.png b/app/assets/images/emoji/bouquet.png new file mode 100644 index 00000000000..11455af6df4 Binary files /dev/null and b/app/assets/images/emoji/bouquet.png differ diff --git a/app/assets/images/emoji/bow.png b/app/assets/images/emoji/bow.png new file mode 100644 index 00000000000..d8f793088dc Binary files /dev/null and b/app/assets/images/emoji/bow.png differ diff --git a/app/assets/images/emoji/bow_and_arrow.png b/app/assets/images/emoji/bow_and_arrow.png new file mode 100644 index 00000000000..6a538bf475f Binary files /dev/null and b/app/assets/images/emoji/bow_and_arrow.png differ diff --git a/app/assets/images/emoji/bow_tone1.png b/app/assets/images/emoji/bow_tone1.png new file mode 100644 index 00000000000..87afb7b54cf Binary files /dev/null and b/app/assets/images/emoji/bow_tone1.png differ diff --git a/app/assets/images/emoji/bow_tone2.png b/app/assets/images/emoji/bow_tone2.png new file mode 100644 index 00000000000..3ccf7dc0850 Binary files /dev/null and b/app/assets/images/emoji/bow_tone2.png differ diff --git a/app/assets/images/emoji/bow_tone3.png b/app/assets/images/emoji/bow_tone3.png new file mode 100644 index 00000000000..8b9eb64f926 Binary files /dev/null and b/app/assets/images/emoji/bow_tone3.png differ diff --git a/app/assets/images/emoji/bow_tone4.png b/app/assets/images/emoji/bow_tone4.png new file mode 100644 index 00000000000..683795ff40d Binary files /dev/null and b/app/assets/images/emoji/bow_tone4.png differ diff --git a/app/assets/images/emoji/bow_tone5.png b/app/assets/images/emoji/bow_tone5.png new file mode 100644 index 00000000000..7969d971752 Binary files /dev/null and b/app/assets/images/emoji/bow_tone5.png differ diff --git a/app/assets/images/emoji/bowling.png b/app/assets/images/emoji/bowling.png new file mode 100644 index 00000000000..63add89e53b Binary files /dev/null and b/app/assets/images/emoji/bowling.png differ diff --git a/app/assets/images/emoji/boxing_glove.png b/app/assets/images/emoji/boxing_glove.png new file mode 100644 index 00000000000..9838f24e51a Binary files /dev/null and b/app/assets/images/emoji/boxing_glove.png differ diff --git a/app/assets/images/emoji/boy.png b/app/assets/images/emoji/boy.png new file mode 100644 index 00000000000..8ecfb0a4e92 Binary files /dev/null and b/app/assets/images/emoji/boy.png differ diff --git a/app/assets/images/emoji/boy_tone1.png b/app/assets/images/emoji/boy_tone1.png new file mode 100644 index 00000000000..2fc436ea512 Binary files /dev/null and b/app/assets/images/emoji/boy_tone1.png differ diff --git a/app/assets/images/emoji/boy_tone2.png b/app/assets/images/emoji/boy_tone2.png new file mode 100644 index 00000000000..09a5f18d360 Binary files /dev/null and b/app/assets/images/emoji/boy_tone2.png differ diff --git a/app/assets/images/emoji/boy_tone3.png b/app/assets/images/emoji/boy_tone3.png new file mode 100644 index 00000000000..3cfe675dd3a Binary files /dev/null and b/app/assets/images/emoji/boy_tone3.png differ diff --git a/app/assets/images/emoji/boy_tone4.png b/app/assets/images/emoji/boy_tone4.png new file mode 100644 index 00000000000..780be0ace36 Binary files /dev/null and b/app/assets/images/emoji/boy_tone4.png differ diff --git a/app/assets/images/emoji/boy_tone5.png b/app/assets/images/emoji/boy_tone5.png new file mode 100644 index 00000000000..f32fe22e35c Binary files /dev/null and b/app/assets/images/emoji/boy_tone5.png differ diff --git a/app/assets/images/emoji/bread.png b/app/assets/images/emoji/bread.png new file mode 100644 index 00000000000..6676510aaa5 Binary files /dev/null and b/app/assets/images/emoji/bread.png differ diff --git a/app/assets/images/emoji/bride_with_veil.png b/app/assets/images/emoji/bride_with_veil.png new file mode 100644 index 00000000000..eaf4bd97890 Binary files /dev/null and b/app/assets/images/emoji/bride_with_veil.png differ diff --git a/app/assets/images/emoji/bride_with_veil_tone1.png b/app/assets/images/emoji/bride_with_veil_tone1.png new file mode 100644 index 00000000000..c4fb141ae8f Binary files /dev/null and b/app/assets/images/emoji/bride_with_veil_tone1.png differ diff --git a/app/assets/images/emoji/bride_with_veil_tone2.png b/app/assets/images/emoji/bride_with_veil_tone2.png new file mode 100644 index 00000000000..c248769fc06 Binary files /dev/null and b/app/assets/images/emoji/bride_with_veil_tone2.png differ diff --git a/app/assets/images/emoji/bride_with_veil_tone3.png b/app/assets/images/emoji/bride_with_veil_tone3.png new file mode 100644 index 00000000000..962c0a6eedb Binary files /dev/null and b/app/assets/images/emoji/bride_with_veil_tone3.png differ diff --git a/app/assets/images/emoji/bride_with_veil_tone4.png b/app/assets/images/emoji/bride_with_veil_tone4.png new file mode 100644 index 00000000000..740ca208cd4 Binary files /dev/null and b/app/assets/images/emoji/bride_with_veil_tone4.png differ diff --git a/app/assets/images/emoji/bride_with_veil_tone5.png b/app/assets/images/emoji/bride_with_veil_tone5.png new file mode 100644 index 00000000000..5cc5598587d Binary files /dev/null and b/app/assets/images/emoji/bride_with_veil_tone5.png differ diff --git a/app/assets/images/emoji/bridge_at_night.png b/app/assets/images/emoji/bridge_at_night.png new file mode 100644 index 00000000000..1d444e0be65 Binary files /dev/null and b/app/assets/images/emoji/bridge_at_night.png differ diff --git a/app/assets/images/emoji/briefcase.png b/app/assets/images/emoji/briefcase.png new file mode 100644 index 00000000000..b9912ba2148 Binary files /dev/null and b/app/assets/images/emoji/briefcase.png differ diff --git a/app/assets/images/emoji/broken_heart.png b/app/assets/images/emoji/broken_heart.png new file mode 100644 index 00000000000..718e26ee122 Binary files /dev/null and b/app/assets/images/emoji/broken_heart.png differ diff --git a/app/assets/images/emoji/bug.png b/app/assets/images/emoji/bug.png new file mode 100644 index 00000000000..e64e72f259a Binary files /dev/null and b/app/assets/images/emoji/bug.png differ diff --git a/app/assets/images/emoji/bulb.png b/app/assets/images/emoji/bulb.png new file mode 100644 index 00000000000..38e32e02d9f Binary files /dev/null and b/app/assets/images/emoji/bulb.png differ diff --git a/app/assets/images/emoji/bullettrain_front.png b/app/assets/images/emoji/bullettrain_front.png new file mode 100644 index 00000000000..4f698e056fa Binary files /dev/null and b/app/assets/images/emoji/bullettrain_front.png differ diff --git a/app/assets/images/emoji/bullettrain_side.png b/app/assets/images/emoji/bullettrain_side.png new file mode 100644 index 00000000000..ed61c67bf07 Binary files /dev/null and b/app/assets/images/emoji/bullettrain_side.png differ diff --git a/app/assets/images/emoji/burrito.png b/app/assets/images/emoji/burrito.png new file mode 100644 index 00000000000..02bd5601df7 Binary files /dev/null and b/app/assets/images/emoji/burrito.png differ diff --git a/app/assets/images/emoji/bus.png b/app/assets/images/emoji/bus.png new file mode 100644 index 00000000000..641ddc56ca7 Binary files /dev/null and b/app/assets/images/emoji/bus.png differ diff --git a/app/assets/images/emoji/busstop.png b/app/assets/images/emoji/busstop.png new file mode 100644 index 00000000000..b2b62208bfd Binary files /dev/null and b/app/assets/images/emoji/busstop.png differ diff --git a/app/assets/images/emoji/bust_in_silhouette.png b/app/assets/images/emoji/bust_in_silhouette.png new file mode 100644 index 00000000000..123b2cbe1fb Binary files /dev/null and b/app/assets/images/emoji/bust_in_silhouette.png differ diff --git a/app/assets/images/emoji/busts_in_silhouette.png b/app/assets/images/emoji/busts_in_silhouette.png new file mode 100644 index 00000000000..d7656860a1c Binary files /dev/null and b/app/assets/images/emoji/busts_in_silhouette.png differ diff --git a/app/assets/images/emoji/butterfly.png b/app/assets/images/emoji/butterfly.png new file mode 100644 index 00000000000..5631fe99226 Binary files /dev/null and b/app/assets/images/emoji/butterfly.png differ diff --git a/app/assets/images/emoji/cactus.png b/app/assets/images/emoji/cactus.png new file mode 100644 index 00000000000..9b48ccf3d0c Binary files /dev/null and b/app/assets/images/emoji/cactus.png differ diff --git a/app/assets/images/emoji/cake.png b/app/assets/images/emoji/cake.png new file mode 100644 index 00000000000..4368177be9a Binary files /dev/null and b/app/assets/images/emoji/cake.png differ diff --git a/app/assets/images/emoji/calendar.png b/app/assets/images/emoji/calendar.png new file mode 100644 index 00000000000..47353b74447 Binary files /dev/null and b/app/assets/images/emoji/calendar.png differ diff --git a/app/assets/images/emoji/calendar_spiral.png b/app/assets/images/emoji/calendar_spiral.png new file mode 100644 index 00000000000..dec8d49bfa8 Binary files /dev/null and b/app/assets/images/emoji/calendar_spiral.png differ diff --git a/app/assets/images/emoji/call_me.png b/app/assets/images/emoji/call_me.png new file mode 100644 index 00000000000..a10c59ba711 Binary files /dev/null and b/app/assets/images/emoji/call_me.png differ diff --git a/app/assets/images/emoji/call_me_tone1.png b/app/assets/images/emoji/call_me_tone1.png new file mode 100644 index 00000000000..2c93201181a Binary files /dev/null and b/app/assets/images/emoji/call_me_tone1.png differ diff --git a/app/assets/images/emoji/call_me_tone2.png b/app/assets/images/emoji/call_me_tone2.png new file mode 100644 index 00000000000..c39f45a41ed Binary files /dev/null and b/app/assets/images/emoji/call_me_tone2.png differ diff --git a/app/assets/images/emoji/call_me_tone3.png b/app/assets/images/emoji/call_me_tone3.png new file mode 100644 index 00000000000..83a57f63c29 Binary files /dev/null and b/app/assets/images/emoji/call_me_tone3.png differ diff --git a/app/assets/images/emoji/call_me_tone4.png b/app/assets/images/emoji/call_me_tone4.png new file mode 100644 index 00000000000..65b3468fe44 Binary files /dev/null and b/app/assets/images/emoji/call_me_tone4.png differ diff --git a/app/assets/images/emoji/call_me_tone5.png b/app/assets/images/emoji/call_me_tone5.png new file mode 100644 index 00000000000..94ef68ff3b3 Binary files /dev/null and b/app/assets/images/emoji/call_me_tone5.png differ diff --git a/app/assets/images/emoji/calling.png b/app/assets/images/emoji/calling.png new file mode 100644 index 00000000000..e2f308f8e46 Binary files /dev/null and b/app/assets/images/emoji/calling.png differ diff --git a/app/assets/images/emoji/camel.png b/app/assets/images/emoji/camel.png new file mode 100644 index 00000000000..b421d07a805 Binary files /dev/null and b/app/assets/images/emoji/camel.png differ diff --git a/app/assets/images/emoji/camera.png b/app/assets/images/emoji/camera.png new file mode 100644 index 00000000000..0a3429f72ef Binary files /dev/null and b/app/assets/images/emoji/camera.png differ diff --git a/app/assets/images/emoji/camera_with_flash.png b/app/assets/images/emoji/camera_with_flash.png new file mode 100644 index 00000000000..27471da2029 Binary files /dev/null and b/app/assets/images/emoji/camera_with_flash.png differ diff --git a/app/assets/images/emoji/camping.png b/app/assets/images/emoji/camping.png new file mode 100644 index 00000000000..d589cc1f44b Binary files /dev/null and b/app/assets/images/emoji/camping.png differ diff --git a/app/assets/images/emoji/cancer.png b/app/assets/images/emoji/cancer.png new file mode 100644 index 00000000000..a64af07cb5f Binary files /dev/null and b/app/assets/images/emoji/cancer.png differ diff --git a/app/assets/images/emoji/candle.png b/app/assets/images/emoji/candle.png new file mode 100644 index 00000000000..0b56444e355 Binary files /dev/null and b/app/assets/images/emoji/candle.png differ diff --git a/app/assets/images/emoji/candy.png b/app/assets/images/emoji/candy.png new file mode 100644 index 00000000000..8c67ace3a35 Binary files /dev/null and b/app/assets/images/emoji/candy.png differ diff --git a/app/assets/images/emoji/canoe.png b/app/assets/images/emoji/canoe.png new file mode 100644 index 00000000000..e26cdb9da69 Binary files /dev/null and b/app/assets/images/emoji/canoe.png differ diff --git a/app/assets/images/emoji/capital_abcd.png b/app/assets/images/emoji/capital_abcd.png new file mode 100644 index 00000000000..fe9482d2d8a Binary files /dev/null and b/app/assets/images/emoji/capital_abcd.png differ diff --git a/app/assets/images/emoji/capricorn.png b/app/assets/images/emoji/capricorn.png new file mode 100644 index 00000000000..6293d31d4b1 Binary files /dev/null and b/app/assets/images/emoji/capricorn.png differ diff --git a/app/assets/images/emoji/card_box.png b/app/assets/images/emoji/card_box.png new file mode 100644 index 00000000000..f2e764ce59d Binary files /dev/null and b/app/assets/images/emoji/card_box.png differ diff --git a/app/assets/images/emoji/card_index.png b/app/assets/images/emoji/card_index.png new file mode 100644 index 00000000000..151e11cb3b4 Binary files /dev/null and b/app/assets/images/emoji/card_index.png differ diff --git a/app/assets/images/emoji/carousel_horse.png b/app/assets/images/emoji/carousel_horse.png new file mode 100644 index 00000000000..a17074edf05 Binary files /dev/null and b/app/assets/images/emoji/carousel_horse.png differ diff --git a/app/assets/images/emoji/carrot.png b/app/assets/images/emoji/carrot.png new file mode 100644 index 00000000000..c68829b58e7 Binary files /dev/null and b/app/assets/images/emoji/carrot.png differ diff --git a/app/assets/images/emoji/cartwheel.png b/app/assets/images/emoji/cartwheel.png new file mode 100644 index 00000000000..cbcaa578253 Binary files /dev/null and b/app/assets/images/emoji/cartwheel.png differ diff --git a/app/assets/images/emoji/cartwheel_tone1.png b/app/assets/images/emoji/cartwheel_tone1.png new file mode 100644 index 00000000000..db6d65895fb Binary files /dev/null and b/app/assets/images/emoji/cartwheel_tone1.png differ diff --git a/app/assets/images/emoji/cartwheel_tone2.png b/app/assets/images/emoji/cartwheel_tone2.png new file mode 100644 index 00000000000..e00ffbc27a8 Binary files /dev/null and b/app/assets/images/emoji/cartwheel_tone2.png differ diff --git a/app/assets/images/emoji/cartwheel_tone3.png b/app/assets/images/emoji/cartwheel_tone3.png new file mode 100644 index 00000000000..49321be391f Binary files /dev/null and b/app/assets/images/emoji/cartwheel_tone3.png differ diff --git a/app/assets/images/emoji/cartwheel_tone4.png b/app/assets/images/emoji/cartwheel_tone4.png new file mode 100644 index 00000000000..d4562b5e3dd Binary files /dev/null and b/app/assets/images/emoji/cartwheel_tone4.png differ diff --git a/app/assets/images/emoji/cartwheel_tone5.png b/app/assets/images/emoji/cartwheel_tone5.png new file mode 100644 index 00000000000..6e09a870767 Binary files /dev/null and b/app/assets/images/emoji/cartwheel_tone5.png differ diff --git a/app/assets/images/emoji/cat.png b/app/assets/images/emoji/cat.png new file mode 100644 index 00000000000..efd82c2abf3 Binary files /dev/null and b/app/assets/images/emoji/cat.png differ diff --git a/app/assets/images/emoji/cat2.png b/app/assets/images/emoji/cat2.png new file mode 100644 index 00000000000..46abe8cbc14 Binary files /dev/null and b/app/assets/images/emoji/cat2.png differ diff --git a/app/assets/images/emoji/cd.png b/app/assets/images/emoji/cd.png new file mode 100644 index 00000000000..e6b01449cd9 Binary files /dev/null and b/app/assets/images/emoji/cd.png differ diff --git a/app/assets/images/emoji/chains.png b/app/assets/images/emoji/chains.png new file mode 100644 index 00000000000..57f46139a06 Binary files /dev/null and b/app/assets/images/emoji/chains.png differ diff --git a/app/assets/images/emoji/champagne.png b/app/assets/images/emoji/champagne.png new file mode 100644 index 00000000000..285a79a93d0 Binary files /dev/null and b/app/assets/images/emoji/champagne.png differ diff --git a/app/assets/images/emoji/champagne_glass.png b/app/assets/images/emoji/champagne_glass.png new file mode 100644 index 00000000000..31937ae9392 Binary files /dev/null and b/app/assets/images/emoji/champagne_glass.png differ diff --git a/app/assets/images/emoji/chart.png b/app/assets/images/emoji/chart.png new file mode 100644 index 00000000000..9773f03be22 Binary files /dev/null and b/app/assets/images/emoji/chart.png differ diff --git a/app/assets/images/emoji/chart_with_downwards_trend.png b/app/assets/images/emoji/chart_with_downwards_trend.png new file mode 100644 index 00000000000..5222ec72d85 Binary files /dev/null and b/app/assets/images/emoji/chart_with_downwards_trend.png differ diff --git a/app/assets/images/emoji/chart_with_upwards_trend.png b/app/assets/images/emoji/chart_with_upwards_trend.png new file mode 100644 index 00000000000..f13cfcf9956 Binary files /dev/null and b/app/assets/images/emoji/chart_with_upwards_trend.png differ diff --git a/app/assets/images/emoji/checkered_flag.png b/app/assets/images/emoji/checkered_flag.png new file mode 100644 index 00000000000..5a71eecb89b Binary files /dev/null and b/app/assets/images/emoji/checkered_flag.png differ diff --git a/app/assets/images/emoji/cheese.png b/app/assets/images/emoji/cheese.png new file mode 100644 index 00000000000..00e99762286 Binary files /dev/null and b/app/assets/images/emoji/cheese.png differ diff --git a/app/assets/images/emoji/cherries.png b/app/assets/images/emoji/cherries.png new file mode 100644 index 00000000000..9b10cbaac5e Binary files /dev/null and b/app/assets/images/emoji/cherries.png differ diff --git a/app/assets/images/emoji/cherry_blossom.png b/app/assets/images/emoji/cherry_blossom.png new file mode 100644 index 00000000000..282f3e7bc81 Binary files /dev/null and b/app/assets/images/emoji/cherry_blossom.png differ diff --git a/app/assets/images/emoji/chestnut.png b/app/assets/images/emoji/chestnut.png new file mode 100644 index 00000000000..e9fb40468ed Binary files /dev/null and b/app/assets/images/emoji/chestnut.png differ diff --git a/app/assets/images/emoji/chicken.png b/app/assets/images/emoji/chicken.png new file mode 100644 index 00000000000..9a6992e55ba Binary files /dev/null and b/app/assets/images/emoji/chicken.png differ diff --git a/app/assets/images/emoji/children_crossing.png b/app/assets/images/emoji/children_crossing.png new file mode 100644 index 00000000000..fa4c091c7c3 Binary files /dev/null and b/app/assets/images/emoji/children_crossing.png differ diff --git a/app/assets/images/emoji/chipmunk.png b/app/assets/images/emoji/chipmunk.png new file mode 100644 index 00000000000..2aac560cb22 Binary files /dev/null and b/app/assets/images/emoji/chipmunk.png differ diff --git a/app/assets/images/emoji/chocolate_bar.png b/app/assets/images/emoji/chocolate_bar.png new file mode 100644 index 00000000000..318bbd40ef9 Binary files /dev/null and b/app/assets/images/emoji/chocolate_bar.png differ diff --git a/app/assets/images/emoji/christmas_tree.png b/app/assets/images/emoji/christmas_tree.png new file mode 100644 index 00000000000..4197d37a52b Binary files /dev/null and b/app/assets/images/emoji/christmas_tree.png differ diff --git a/app/assets/images/emoji/church.png b/app/assets/images/emoji/church.png new file mode 100644 index 00000000000..8242fd272b3 Binary files /dev/null and b/app/assets/images/emoji/church.png differ diff --git a/app/assets/images/emoji/cinema.png b/app/assets/images/emoji/cinema.png new file mode 100644 index 00000000000..65f27b386f2 Binary files /dev/null and b/app/assets/images/emoji/cinema.png differ diff --git a/app/assets/images/emoji/circus_tent.png b/app/assets/images/emoji/circus_tent.png new file mode 100644 index 00000000000..b0379775b12 Binary files /dev/null and b/app/assets/images/emoji/circus_tent.png differ diff --git a/app/assets/images/emoji/city_dusk.png b/app/assets/images/emoji/city_dusk.png new file mode 100644 index 00000000000..80cdff7cf5d Binary files /dev/null and b/app/assets/images/emoji/city_dusk.png differ diff --git a/app/assets/images/emoji/city_sunset.png b/app/assets/images/emoji/city_sunset.png new file mode 100644 index 00000000000..7cded0ba55b Binary files /dev/null and b/app/assets/images/emoji/city_sunset.png differ diff --git a/app/assets/images/emoji/cityscape.png b/app/assets/images/emoji/cityscape.png new file mode 100644 index 00000000000..d7b9844a0b4 Binary files /dev/null and b/app/assets/images/emoji/cityscape.png differ diff --git a/app/assets/images/emoji/cl.png b/app/assets/images/emoji/cl.png new file mode 100644 index 00000000000..8b01b4343e2 Binary files /dev/null and b/app/assets/images/emoji/cl.png differ diff --git a/app/assets/images/emoji/clap.png b/app/assets/images/emoji/clap.png new file mode 100644 index 00000000000..b0ffe928920 Binary files /dev/null and b/app/assets/images/emoji/clap.png differ diff --git a/app/assets/images/emoji/clap_tone1.png b/app/assets/images/emoji/clap_tone1.png new file mode 100644 index 00000000000..de4bc837b96 Binary files /dev/null and b/app/assets/images/emoji/clap_tone1.png differ diff --git a/app/assets/images/emoji/clap_tone2.png b/app/assets/images/emoji/clap_tone2.png new file mode 100644 index 00000000000..1323de775ba Binary files /dev/null and b/app/assets/images/emoji/clap_tone2.png differ diff --git a/app/assets/images/emoji/clap_tone3.png b/app/assets/images/emoji/clap_tone3.png new file mode 100644 index 00000000000..d448ca19dde Binary files /dev/null and b/app/assets/images/emoji/clap_tone3.png differ diff --git a/app/assets/images/emoji/clap_tone4.png b/app/assets/images/emoji/clap_tone4.png new file mode 100644 index 00000000000..c49f44ee91d Binary files /dev/null and b/app/assets/images/emoji/clap_tone4.png differ diff --git a/app/assets/images/emoji/clap_tone5.png b/app/assets/images/emoji/clap_tone5.png new file mode 100644 index 00000000000..29ee9bdf37c Binary files /dev/null and b/app/assets/images/emoji/clap_tone5.png differ diff --git a/app/assets/images/emoji/clapper.png b/app/assets/images/emoji/clapper.png new file mode 100644 index 00000000000..81390883111 Binary files /dev/null and b/app/assets/images/emoji/clapper.png differ diff --git a/app/assets/images/emoji/classical_building.png b/app/assets/images/emoji/classical_building.png new file mode 100644 index 00000000000..de7b559daaf Binary files /dev/null and b/app/assets/images/emoji/classical_building.png differ diff --git a/app/assets/images/emoji/clipboard.png b/app/assets/images/emoji/clipboard.png new file mode 100644 index 00000000000..7edcfc52509 Binary files /dev/null and b/app/assets/images/emoji/clipboard.png differ diff --git a/app/assets/images/emoji/clock.png b/app/assets/images/emoji/clock.png new file mode 100644 index 00000000000..ffdb451e3a8 Binary files /dev/null and b/app/assets/images/emoji/clock.png differ diff --git a/app/assets/images/emoji/clock1.png b/app/assets/images/emoji/clock1.png new file mode 100644 index 00000000000..d6e34941f23 Binary files /dev/null and b/app/assets/images/emoji/clock1.png differ diff --git a/app/assets/images/emoji/clock10.png b/app/assets/images/emoji/clock10.png new file mode 100644 index 00000000000..e62b245cdbe Binary files /dev/null and b/app/assets/images/emoji/clock10.png differ diff --git a/app/assets/images/emoji/clock1030.png b/app/assets/images/emoji/clock1030.png new file mode 100644 index 00000000000..0802b3c65b9 Binary files /dev/null and b/app/assets/images/emoji/clock1030.png differ diff --git a/app/assets/images/emoji/clock11.png b/app/assets/images/emoji/clock11.png new file mode 100644 index 00000000000..0983345273b Binary files /dev/null and b/app/assets/images/emoji/clock11.png differ diff --git a/app/assets/images/emoji/clock1130.png b/app/assets/images/emoji/clock1130.png new file mode 100644 index 00000000000..d970d03b809 Binary files /dev/null and b/app/assets/images/emoji/clock1130.png differ diff --git a/app/assets/images/emoji/clock12.png b/app/assets/images/emoji/clock12.png new file mode 100644 index 00000000000..e61caa4b3e2 Binary files /dev/null and b/app/assets/images/emoji/clock12.png differ diff --git a/app/assets/images/emoji/clock1230.png b/app/assets/images/emoji/clock1230.png new file mode 100644 index 00000000000..f2b1d261721 Binary files /dev/null and b/app/assets/images/emoji/clock1230.png differ diff --git a/app/assets/images/emoji/clock130.png b/app/assets/images/emoji/clock130.png new file mode 100644 index 00000000000..86b7689b84e Binary files /dev/null and b/app/assets/images/emoji/clock130.png differ diff --git a/app/assets/images/emoji/clock2.png b/app/assets/images/emoji/clock2.png new file mode 100644 index 00000000000..a54253d7d57 Binary files /dev/null and b/app/assets/images/emoji/clock2.png differ diff --git a/app/assets/images/emoji/clock230.png b/app/assets/images/emoji/clock230.png new file mode 100644 index 00000000000..7a787e018e6 Binary files /dev/null and b/app/assets/images/emoji/clock230.png differ diff --git a/app/assets/images/emoji/clock3.png b/app/assets/images/emoji/clock3.png new file mode 100644 index 00000000000..27ec4b1f514 Binary files /dev/null and b/app/assets/images/emoji/clock3.png differ diff --git a/app/assets/images/emoji/clock330.png b/app/assets/images/emoji/clock330.png new file mode 100644 index 00000000000..c6860395cec Binary files /dev/null and b/app/assets/images/emoji/clock330.png differ diff --git a/app/assets/images/emoji/clock4.png b/app/assets/images/emoji/clock4.png new file mode 100644 index 00000000000..60a1ef4cc13 Binary files /dev/null and b/app/assets/images/emoji/clock4.png differ diff --git a/app/assets/images/emoji/clock430.png b/app/assets/images/emoji/clock430.png new file mode 100644 index 00000000000..3c05b362122 Binary files /dev/null and b/app/assets/images/emoji/clock430.png differ diff --git a/app/assets/images/emoji/clock5.png b/app/assets/images/emoji/clock5.png new file mode 100644 index 00000000000..c9382d1e094 Binary files /dev/null and b/app/assets/images/emoji/clock5.png differ diff --git a/app/assets/images/emoji/clock530.png b/app/assets/images/emoji/clock530.png new file mode 100644 index 00000000000..c21fa926db2 Binary files /dev/null and b/app/assets/images/emoji/clock530.png differ diff --git a/app/assets/images/emoji/clock6.png b/app/assets/images/emoji/clock6.png new file mode 100644 index 00000000000..8fd5d3f5bd7 Binary files /dev/null and b/app/assets/images/emoji/clock6.png differ diff --git a/app/assets/images/emoji/clock630.png b/app/assets/images/emoji/clock630.png new file mode 100644 index 00000000000..2aec87fefcf Binary files /dev/null and b/app/assets/images/emoji/clock630.png differ diff --git a/app/assets/images/emoji/clock7.png b/app/assets/images/emoji/clock7.png new file mode 100644 index 00000000000..8c7084036f2 Binary files /dev/null and b/app/assets/images/emoji/clock7.png differ diff --git a/app/assets/images/emoji/clock730.png b/app/assets/images/emoji/clock730.png new file mode 100644 index 00000000000..f7a1135e03f Binary files /dev/null and b/app/assets/images/emoji/clock730.png differ diff --git a/app/assets/images/emoji/clock8.png b/app/assets/images/emoji/clock8.png new file mode 100644 index 00000000000..fcddf722e95 Binary files /dev/null and b/app/assets/images/emoji/clock8.png differ diff --git a/app/assets/images/emoji/clock830.png b/app/assets/images/emoji/clock830.png new file mode 100644 index 00000000000..799b4aebc08 Binary files /dev/null and b/app/assets/images/emoji/clock830.png differ diff --git a/app/assets/images/emoji/clock9.png b/app/assets/images/emoji/clock9.png new file mode 100644 index 00000000000..dfbe0117981 Binary files /dev/null and b/app/assets/images/emoji/clock9.png differ diff --git a/app/assets/images/emoji/clock930.png b/app/assets/images/emoji/clock930.png new file mode 100644 index 00000000000..4a2092ee6f0 Binary files /dev/null and b/app/assets/images/emoji/clock930.png differ diff --git a/app/assets/images/emoji/closed_book.png b/app/assets/images/emoji/closed_book.png new file mode 100644 index 00000000000..6395cf2151e Binary files /dev/null and b/app/assets/images/emoji/closed_book.png differ diff --git a/app/assets/images/emoji/closed_lock_with_key.png b/app/assets/images/emoji/closed_lock_with_key.png new file mode 100644 index 00000000000..1c1cd5d0741 Binary files /dev/null and b/app/assets/images/emoji/closed_lock_with_key.png differ diff --git a/app/assets/images/emoji/closed_umbrella.png b/app/assets/images/emoji/closed_umbrella.png new file mode 100644 index 00000000000..ecefba9e446 Binary files /dev/null and b/app/assets/images/emoji/closed_umbrella.png differ diff --git a/app/assets/images/emoji/cloud.png b/app/assets/images/emoji/cloud.png new file mode 100644 index 00000000000..5b4f57f77ba Binary files /dev/null and b/app/assets/images/emoji/cloud.png differ diff --git a/app/assets/images/emoji/cloud_lightning.png b/app/assets/images/emoji/cloud_lightning.png new file mode 100644 index 00000000000..0831e88aa31 Binary files /dev/null and b/app/assets/images/emoji/cloud_lightning.png differ diff --git a/app/assets/images/emoji/cloud_rain.png b/app/assets/images/emoji/cloud_rain.png new file mode 100644 index 00000000000..385685e0512 Binary files /dev/null and b/app/assets/images/emoji/cloud_rain.png differ diff --git a/app/assets/images/emoji/cloud_snow.png b/app/assets/images/emoji/cloud_snow.png new file mode 100644 index 00000000000..9720384eb99 Binary files /dev/null and b/app/assets/images/emoji/cloud_snow.png differ diff --git a/app/assets/images/emoji/cloud_tornado.png b/app/assets/images/emoji/cloud_tornado.png new file mode 100644 index 00000000000..4821c89da1e Binary files /dev/null and b/app/assets/images/emoji/cloud_tornado.png differ diff --git a/app/assets/images/emoji/clown.png b/app/assets/images/emoji/clown.png new file mode 100644 index 00000000000..02b7ff70049 Binary files /dev/null and b/app/assets/images/emoji/clown.png differ diff --git a/app/assets/images/emoji/clubs.png b/app/assets/images/emoji/clubs.png new file mode 100644 index 00000000000..4f2abf791ca Binary files /dev/null and b/app/assets/images/emoji/clubs.png differ diff --git a/app/assets/images/emoji/cocktail.png b/app/assets/images/emoji/cocktail.png new file mode 100644 index 00000000000..2e50c57e98d Binary files /dev/null and b/app/assets/images/emoji/cocktail.png differ diff --git a/app/assets/images/emoji/coffee.png b/app/assets/images/emoji/coffee.png new file mode 100644 index 00000000000..553061471b1 Binary files /dev/null and b/app/assets/images/emoji/coffee.png differ diff --git a/app/assets/images/emoji/coffin.png b/app/assets/images/emoji/coffin.png new file mode 100644 index 00000000000..fb2932aa5f6 Binary files /dev/null and b/app/assets/images/emoji/coffin.png differ diff --git a/app/assets/images/emoji/cold_sweat.png b/app/assets/images/emoji/cold_sweat.png new file mode 100644 index 00000000000..85b2231bbf6 Binary files /dev/null and b/app/assets/images/emoji/cold_sweat.png differ diff --git a/app/assets/images/emoji/comet.png b/app/assets/images/emoji/comet.png new file mode 100644 index 00000000000..a99751f79be Binary files /dev/null and b/app/assets/images/emoji/comet.png differ diff --git a/app/assets/images/emoji/compression.png b/app/assets/images/emoji/compression.png new file mode 100644 index 00000000000..d7eda7f362a Binary files /dev/null and b/app/assets/images/emoji/compression.png differ diff --git a/app/assets/images/emoji/computer.png b/app/assets/images/emoji/computer.png new file mode 100644 index 00000000000..c1fee27e3a9 Binary files /dev/null and b/app/assets/images/emoji/computer.png differ diff --git a/app/assets/images/emoji/confetti_ball.png b/app/assets/images/emoji/confetti_ball.png new file mode 100644 index 00000000000..ba4fd9b12be Binary files /dev/null and b/app/assets/images/emoji/confetti_ball.png differ diff --git a/app/assets/images/emoji/confounded.png b/app/assets/images/emoji/confounded.png new file mode 100644 index 00000000000..aa4b29e9375 Binary files /dev/null and b/app/assets/images/emoji/confounded.png differ diff --git a/app/assets/images/emoji/confused.png b/app/assets/images/emoji/confused.png new file mode 100644 index 00000000000..502b6bf0e0b Binary files /dev/null and b/app/assets/images/emoji/confused.png differ diff --git a/app/assets/images/emoji/congratulations.png b/app/assets/images/emoji/congratulations.png new file mode 100644 index 00000000000..ba8c89d95ee Binary files /dev/null and b/app/assets/images/emoji/congratulations.png differ diff --git a/app/assets/images/emoji/construction.png b/app/assets/images/emoji/construction.png new file mode 100644 index 00000000000..ef8db5f471c Binary files /dev/null and b/app/assets/images/emoji/construction.png differ diff --git a/app/assets/images/emoji/construction_site.png b/app/assets/images/emoji/construction_site.png new file mode 100644 index 00000000000..8206a20f63f Binary files /dev/null and b/app/assets/images/emoji/construction_site.png differ diff --git a/app/assets/images/emoji/construction_worker.png b/app/assets/images/emoji/construction_worker.png new file mode 100644 index 00000000000..a9970a89005 Binary files /dev/null and b/app/assets/images/emoji/construction_worker.png differ diff --git a/app/assets/images/emoji/construction_worker_tone1.png b/app/assets/images/emoji/construction_worker_tone1.png new file mode 100644 index 00000000000..2f24a2bab24 Binary files /dev/null and b/app/assets/images/emoji/construction_worker_tone1.png differ diff --git a/app/assets/images/emoji/construction_worker_tone2.png b/app/assets/images/emoji/construction_worker_tone2.png new file mode 100644 index 00000000000..93c8fec5a75 Binary files /dev/null and b/app/assets/images/emoji/construction_worker_tone2.png differ diff --git a/app/assets/images/emoji/construction_worker_tone3.png b/app/assets/images/emoji/construction_worker_tone3.png new file mode 100644 index 00000000000..abc1f2af2e0 Binary files /dev/null and b/app/assets/images/emoji/construction_worker_tone3.png differ diff --git a/app/assets/images/emoji/construction_worker_tone4.png b/app/assets/images/emoji/construction_worker_tone4.png new file mode 100644 index 00000000000..eed83289aeb Binary files /dev/null and b/app/assets/images/emoji/construction_worker_tone4.png differ diff --git a/app/assets/images/emoji/construction_worker_tone5.png b/app/assets/images/emoji/construction_worker_tone5.png new file mode 100644 index 00000000000..acbb220b8bb Binary files /dev/null and b/app/assets/images/emoji/construction_worker_tone5.png differ diff --git a/app/assets/images/emoji/control_knobs.png b/app/assets/images/emoji/control_knobs.png new file mode 100644 index 00000000000..6635ac93b50 Binary files /dev/null and b/app/assets/images/emoji/control_knobs.png differ diff --git a/app/assets/images/emoji/convenience_store.png b/app/assets/images/emoji/convenience_store.png new file mode 100644 index 00000000000..26b53b5669e Binary files /dev/null and b/app/assets/images/emoji/convenience_store.png differ diff --git a/app/assets/images/emoji/cookie.png b/app/assets/images/emoji/cookie.png new file mode 100644 index 00000000000..1b6bcb1554f Binary files /dev/null and b/app/assets/images/emoji/cookie.png differ diff --git a/app/assets/images/emoji/cooking.png b/app/assets/images/emoji/cooking.png new file mode 100644 index 00000000000..918c980577a Binary files /dev/null and b/app/assets/images/emoji/cooking.png differ diff --git a/app/assets/images/emoji/cool.png b/app/assets/images/emoji/cool.png new file mode 100644 index 00000000000..74674978d00 Binary files /dev/null and b/app/assets/images/emoji/cool.png differ diff --git a/app/assets/images/emoji/cop.png b/app/assets/images/emoji/cop.png new file mode 100644 index 00000000000..0b16d7c17b7 Binary files /dev/null and b/app/assets/images/emoji/cop.png differ diff --git a/app/assets/images/emoji/cop_tone1.png b/app/assets/images/emoji/cop_tone1.png new file mode 100644 index 00000000000..6ccba3879dc Binary files /dev/null and b/app/assets/images/emoji/cop_tone1.png differ diff --git a/app/assets/images/emoji/cop_tone2.png b/app/assets/images/emoji/cop_tone2.png new file mode 100644 index 00000000000..7814ea9f52d Binary files /dev/null and b/app/assets/images/emoji/cop_tone2.png differ diff --git a/app/assets/images/emoji/cop_tone3.png b/app/assets/images/emoji/cop_tone3.png new file mode 100644 index 00000000000..d78e88ec872 Binary files /dev/null and b/app/assets/images/emoji/cop_tone3.png differ diff --git a/app/assets/images/emoji/cop_tone4.png b/app/assets/images/emoji/cop_tone4.png new file mode 100644 index 00000000000..2e13c508315 Binary files /dev/null and b/app/assets/images/emoji/cop_tone4.png differ diff --git a/app/assets/images/emoji/cop_tone5.png b/app/assets/images/emoji/cop_tone5.png new file mode 100644 index 00000000000..2980d61cc2e Binary files /dev/null and b/app/assets/images/emoji/cop_tone5.png differ diff --git a/app/assets/images/emoji/copyright.png b/app/assets/images/emoji/copyright.png new file mode 100644 index 00000000000..6b9a6adbfd2 Binary files /dev/null and b/app/assets/images/emoji/copyright.png differ diff --git a/app/assets/images/emoji/corn.png b/app/assets/images/emoji/corn.png new file mode 100644 index 00000000000..36e20127931 Binary files /dev/null and b/app/assets/images/emoji/corn.png differ diff --git a/app/assets/images/emoji/couch.png b/app/assets/images/emoji/couch.png new file mode 100644 index 00000000000..27b19b13bb0 Binary files /dev/null and b/app/assets/images/emoji/couch.png differ diff --git a/app/assets/images/emoji/couple.png b/app/assets/images/emoji/couple.png new file mode 100644 index 00000000000..960323f3c16 Binary files /dev/null and b/app/assets/images/emoji/couple.png differ diff --git a/app/assets/images/emoji/couple_mm.png b/app/assets/images/emoji/couple_mm.png new file mode 100644 index 00000000000..8759fa5db87 Binary files /dev/null and b/app/assets/images/emoji/couple_mm.png differ diff --git a/app/assets/images/emoji/couple_with_heart.png b/app/assets/images/emoji/couple_with_heart.png new file mode 100644 index 00000000000..62111601b36 Binary files /dev/null and b/app/assets/images/emoji/couple_with_heart.png differ diff --git a/app/assets/images/emoji/couple_ww.png b/app/assets/images/emoji/couple_ww.png new file mode 100644 index 00000000000..08fdabcdc5c Binary files /dev/null and b/app/assets/images/emoji/couple_ww.png differ diff --git a/app/assets/images/emoji/couplekiss.png b/app/assets/images/emoji/couplekiss.png new file mode 100644 index 00000000000..9aa519da9e8 Binary files /dev/null and b/app/assets/images/emoji/couplekiss.png differ diff --git a/app/assets/images/emoji/cow.png b/app/assets/images/emoji/cow.png new file mode 100644 index 00000000000..718a3986d64 Binary files /dev/null and b/app/assets/images/emoji/cow.png differ diff --git a/app/assets/images/emoji/cow2.png b/app/assets/images/emoji/cow2.png new file mode 100644 index 00000000000..4d0ca534ff1 Binary files /dev/null and b/app/assets/images/emoji/cow2.png differ diff --git a/app/assets/images/emoji/cowboy.png b/app/assets/images/emoji/cowboy.png new file mode 100644 index 00000000000..70dd5d0d9d1 Binary files /dev/null and b/app/assets/images/emoji/cowboy.png differ diff --git a/app/assets/images/emoji/crab.png b/app/assets/images/emoji/crab.png new file mode 100644 index 00000000000..19f3047ab61 Binary files /dev/null and b/app/assets/images/emoji/crab.png differ diff --git a/app/assets/images/emoji/crayon.png b/app/assets/images/emoji/crayon.png new file mode 100644 index 00000000000..8d7b427aaa3 Binary files /dev/null and b/app/assets/images/emoji/crayon.png differ diff --git a/app/assets/images/emoji/credit_card.png b/app/assets/images/emoji/credit_card.png new file mode 100644 index 00000000000..372777d5c61 Binary files /dev/null and b/app/assets/images/emoji/credit_card.png differ diff --git a/app/assets/images/emoji/crescent_moon.png b/app/assets/images/emoji/crescent_moon.png new file mode 100644 index 00000000000..765420ecec7 Binary files /dev/null and b/app/assets/images/emoji/crescent_moon.png differ diff --git a/app/assets/images/emoji/cricket.png b/app/assets/images/emoji/cricket.png new file mode 100644 index 00000000000..d602294a2cd Binary files /dev/null and b/app/assets/images/emoji/cricket.png differ diff --git a/app/assets/images/emoji/crocodile.png b/app/assets/images/emoji/crocodile.png new file mode 100644 index 00000000000..3005c46f176 Binary files /dev/null and b/app/assets/images/emoji/crocodile.png differ diff --git a/app/assets/images/emoji/croissant.png b/app/assets/images/emoji/croissant.png new file mode 100644 index 00000000000..fb33feb1a38 Binary files /dev/null and b/app/assets/images/emoji/croissant.png differ diff --git a/app/assets/images/emoji/cross.png b/app/assets/images/emoji/cross.png new file mode 100644 index 00000000000..42b10e82257 Binary files /dev/null and b/app/assets/images/emoji/cross.png differ diff --git a/app/assets/images/emoji/crossed_flags.png b/app/assets/images/emoji/crossed_flags.png new file mode 100644 index 00000000000..273bd0f0fe5 Binary files /dev/null and b/app/assets/images/emoji/crossed_flags.png differ diff --git a/app/assets/images/emoji/crossed_swords.png b/app/assets/images/emoji/crossed_swords.png new file mode 100644 index 00000000000..907e9607134 Binary files /dev/null and b/app/assets/images/emoji/crossed_swords.png differ diff --git a/app/assets/images/emoji/crown.png b/app/assets/images/emoji/crown.png new file mode 100644 index 00000000000..93b82d92f04 Binary files /dev/null and b/app/assets/images/emoji/crown.png differ diff --git a/app/assets/images/emoji/cruise_ship.png b/app/assets/images/emoji/cruise_ship.png new file mode 100644 index 00000000000..19d4acbe40c Binary files /dev/null and b/app/assets/images/emoji/cruise_ship.png differ diff --git a/app/assets/images/emoji/cry.png b/app/assets/images/emoji/cry.png new file mode 100644 index 00000000000..b7877f8a173 Binary files /dev/null and b/app/assets/images/emoji/cry.png differ diff --git a/app/assets/images/emoji/crying_cat_face.png b/app/assets/images/emoji/crying_cat_face.png new file mode 100644 index 00000000000..b4f49715e00 Binary files /dev/null and b/app/assets/images/emoji/crying_cat_face.png differ diff --git a/app/assets/images/emoji/crystal_ball.png b/app/assets/images/emoji/crystal_ball.png new file mode 100644 index 00000000000..485d5c888f1 Binary files /dev/null and b/app/assets/images/emoji/crystal_ball.png differ diff --git a/app/assets/images/emoji/cucumber.png b/app/assets/images/emoji/cucumber.png new file mode 100644 index 00000000000..500807059d2 Binary files /dev/null and b/app/assets/images/emoji/cucumber.png differ diff --git a/app/assets/images/emoji/cupid.png b/app/assets/images/emoji/cupid.png new file mode 100644 index 00000000000..2df0078ddd1 Binary files /dev/null and b/app/assets/images/emoji/cupid.png differ diff --git a/app/assets/images/emoji/curly_loop.png b/app/assets/images/emoji/curly_loop.png new file mode 100644 index 00000000000..440aa56d50e Binary files /dev/null and b/app/assets/images/emoji/curly_loop.png differ diff --git a/app/assets/images/emoji/currency_exchange.png b/app/assets/images/emoji/currency_exchange.png new file mode 100644 index 00000000000..4d46c6050e7 Binary files /dev/null and b/app/assets/images/emoji/currency_exchange.png differ diff --git a/app/assets/images/emoji/curry.png b/app/assets/images/emoji/curry.png new file mode 100644 index 00000000000..69657ca8103 Binary files /dev/null and b/app/assets/images/emoji/curry.png differ diff --git a/app/assets/images/emoji/custard.png b/app/assets/images/emoji/custard.png new file mode 100644 index 00000000000..fa3df67b8f6 Binary files /dev/null and b/app/assets/images/emoji/custard.png differ diff --git a/app/assets/images/emoji/customs.png b/app/assets/images/emoji/customs.png new file mode 100644 index 00000000000..21b7ce2c69e Binary files /dev/null and b/app/assets/images/emoji/customs.png differ diff --git a/app/assets/images/emoji/cyclone.png b/app/assets/images/emoji/cyclone.png new file mode 100644 index 00000000000..ff00b1afe70 Binary files /dev/null and b/app/assets/images/emoji/cyclone.png differ diff --git a/app/assets/images/emoji/dagger.png b/app/assets/images/emoji/dagger.png new file mode 100644 index 00000000000..66e97b0aa25 Binary files /dev/null and b/app/assets/images/emoji/dagger.png differ diff --git a/app/assets/images/emoji/dancer.png b/app/assets/images/emoji/dancer.png new file mode 100644 index 00000000000..04b166991cb Binary files /dev/null and b/app/assets/images/emoji/dancer.png differ diff --git a/app/assets/images/emoji/dancer_tone1.png b/app/assets/images/emoji/dancer_tone1.png new file mode 100644 index 00000000000..2c7b11c3a6e Binary files /dev/null and b/app/assets/images/emoji/dancer_tone1.png differ diff --git a/app/assets/images/emoji/dancer_tone2.png b/app/assets/images/emoji/dancer_tone2.png new file mode 100644 index 00000000000..cb04b1f907e Binary files /dev/null and b/app/assets/images/emoji/dancer_tone2.png differ diff --git a/app/assets/images/emoji/dancer_tone3.png b/app/assets/images/emoji/dancer_tone3.png new file mode 100644 index 00000000000..98c5bca7b64 Binary files /dev/null and b/app/assets/images/emoji/dancer_tone3.png differ diff --git a/app/assets/images/emoji/dancer_tone4.png b/app/assets/images/emoji/dancer_tone4.png new file mode 100644 index 00000000000..fdb1e00cbba Binary files /dev/null and b/app/assets/images/emoji/dancer_tone4.png differ diff --git a/app/assets/images/emoji/dancer_tone5.png b/app/assets/images/emoji/dancer_tone5.png new file mode 100644 index 00000000000..0e34e0e23f0 Binary files /dev/null and b/app/assets/images/emoji/dancer_tone5.png differ diff --git a/app/assets/images/emoji/dancers.png b/app/assets/images/emoji/dancers.png new file mode 100644 index 00000000000..67e6ffacb76 Binary files /dev/null and b/app/assets/images/emoji/dancers.png differ diff --git a/app/assets/images/emoji/dango.png b/app/assets/images/emoji/dango.png new file mode 100644 index 00000000000..f73f37b01c7 Binary files /dev/null and b/app/assets/images/emoji/dango.png differ diff --git a/app/assets/images/emoji/dark_sunglasses.png b/app/assets/images/emoji/dark_sunglasses.png new file mode 100644 index 00000000000..b1b6db0acff Binary files /dev/null and b/app/assets/images/emoji/dark_sunglasses.png differ diff --git a/app/assets/images/emoji/dart.png b/app/assets/images/emoji/dart.png new file mode 100644 index 00000000000..f6704aeb8ba Binary files /dev/null and b/app/assets/images/emoji/dart.png differ diff --git a/app/assets/images/emoji/dash.png b/app/assets/images/emoji/dash.png new file mode 100644 index 00000000000..064b8525c12 Binary files /dev/null and b/app/assets/images/emoji/dash.png differ diff --git a/app/assets/images/emoji/date.png b/app/assets/images/emoji/date.png new file mode 100644 index 00000000000..f05b3da97b8 Binary files /dev/null and b/app/assets/images/emoji/date.png differ diff --git a/app/assets/images/emoji/deciduous_tree.png b/app/assets/images/emoji/deciduous_tree.png new file mode 100644 index 00000000000..785fc1c30ea Binary files /dev/null and b/app/assets/images/emoji/deciduous_tree.png differ diff --git a/app/assets/images/emoji/deer.png b/app/assets/images/emoji/deer.png new file mode 100644 index 00000000000..d8698195ff0 Binary files /dev/null and b/app/assets/images/emoji/deer.png differ diff --git a/app/assets/images/emoji/department_store.png b/app/assets/images/emoji/department_store.png new file mode 100644 index 00000000000..58867c7a6e1 Binary files /dev/null and b/app/assets/images/emoji/department_store.png differ diff --git a/app/assets/images/emoji/desert.png b/app/assets/images/emoji/desert.png new file mode 100644 index 00000000000..e9966ff8c65 Binary files /dev/null and b/app/assets/images/emoji/desert.png differ diff --git a/app/assets/images/emoji/desktop.png b/app/assets/images/emoji/desktop.png new file mode 100644 index 00000000000..909bd42b5e1 Binary files /dev/null and b/app/assets/images/emoji/desktop.png differ diff --git a/app/assets/images/emoji/diamond_shape_with_a_dot_inside.png b/app/assets/images/emoji/diamond_shape_with_a_dot_inside.png new file mode 100644 index 00000000000..2a22a26d1e2 Binary files /dev/null and b/app/assets/images/emoji/diamond_shape_with_a_dot_inside.png differ diff --git a/app/assets/images/emoji/diamonds.png b/app/assets/images/emoji/diamonds.png new file mode 100644 index 00000000000..1f25f51f97a Binary files /dev/null and b/app/assets/images/emoji/diamonds.png differ diff --git a/app/assets/images/emoji/disappointed.png b/app/assets/images/emoji/disappointed.png new file mode 100644 index 00000000000..efe4e67e23c Binary files /dev/null and b/app/assets/images/emoji/disappointed.png differ diff --git a/app/assets/images/emoji/disappointed_relieved.png b/app/assets/images/emoji/disappointed_relieved.png new file mode 100644 index 00000000000..aef864d2b3d Binary files /dev/null and b/app/assets/images/emoji/disappointed_relieved.png differ diff --git a/app/assets/images/emoji/dividers.png b/app/assets/images/emoji/dividers.png new file mode 100644 index 00000000000..46a7e403f9d Binary files /dev/null and b/app/assets/images/emoji/dividers.png differ diff --git a/app/assets/images/emoji/dizzy.png b/app/assets/images/emoji/dizzy.png new file mode 100644 index 00000000000..85f52efad24 Binary files /dev/null and b/app/assets/images/emoji/dizzy.png differ diff --git a/app/assets/images/emoji/dizzy_face.png b/app/assets/images/emoji/dizzy_face.png new file mode 100644 index 00000000000..3120316ab5e Binary files /dev/null and b/app/assets/images/emoji/dizzy_face.png differ diff --git a/app/assets/images/emoji/do_not_litter.png b/app/assets/images/emoji/do_not_litter.png new file mode 100644 index 00000000000..341d2575f4f Binary files /dev/null and b/app/assets/images/emoji/do_not_litter.png differ diff --git a/app/assets/images/emoji/dog.png b/app/assets/images/emoji/dog.png new file mode 100644 index 00000000000..281b81d58bd Binary files /dev/null and b/app/assets/images/emoji/dog.png differ diff --git a/app/assets/images/emoji/dog2.png b/app/assets/images/emoji/dog2.png new file mode 100644 index 00000000000..976143dbdbe Binary files /dev/null and b/app/assets/images/emoji/dog2.png differ diff --git a/app/assets/images/emoji/dollar.png b/app/assets/images/emoji/dollar.png new file mode 100644 index 00000000000..a9904c28293 Binary files /dev/null and b/app/assets/images/emoji/dollar.png differ diff --git a/app/assets/images/emoji/dolls.png b/app/assets/images/emoji/dolls.png new file mode 100644 index 00000000000..10955615110 Binary files /dev/null and b/app/assets/images/emoji/dolls.png differ diff --git a/app/assets/images/emoji/dolphin.png b/app/assets/images/emoji/dolphin.png new file mode 100644 index 00000000000..81434809003 Binary files /dev/null and b/app/assets/images/emoji/dolphin.png differ diff --git a/app/assets/images/emoji/door.png b/app/assets/images/emoji/door.png new file mode 100644 index 00000000000..36ae3e27494 Binary files /dev/null and b/app/assets/images/emoji/door.png differ diff --git a/app/assets/images/emoji/doughnut.png b/app/assets/images/emoji/doughnut.png new file mode 100644 index 00000000000..0ca4cd0bde8 Binary files /dev/null and b/app/assets/images/emoji/doughnut.png differ diff --git a/app/assets/images/emoji/dove.png b/app/assets/images/emoji/dove.png new file mode 100644 index 00000000000..9580c4917d7 Binary files /dev/null and b/app/assets/images/emoji/dove.png differ diff --git a/app/assets/images/emoji/dragon.png b/app/assets/images/emoji/dragon.png new file mode 100644 index 00000000000..d6311cf5429 Binary files /dev/null and b/app/assets/images/emoji/dragon.png differ diff --git a/app/assets/images/emoji/dragon_face.png b/app/assets/images/emoji/dragon_face.png new file mode 100644 index 00000000000..3c2720446c6 Binary files /dev/null and b/app/assets/images/emoji/dragon_face.png differ diff --git a/app/assets/images/emoji/dress.png b/app/assets/images/emoji/dress.png new file mode 100644 index 00000000000..a697ca5c57d Binary files /dev/null and b/app/assets/images/emoji/dress.png differ diff --git a/app/assets/images/emoji/dromedary_camel.png b/app/assets/images/emoji/dromedary_camel.png new file mode 100644 index 00000000000..5271637c7c4 Binary files /dev/null and b/app/assets/images/emoji/dromedary_camel.png differ diff --git a/app/assets/images/emoji/drooling_face.png b/app/assets/images/emoji/drooling_face.png new file mode 100644 index 00000000000..a5460532597 Binary files /dev/null and b/app/assets/images/emoji/drooling_face.png differ diff --git a/app/assets/images/emoji/droplet.png b/app/assets/images/emoji/droplet.png new file mode 100644 index 00000000000..71241ec3061 Binary files /dev/null and b/app/assets/images/emoji/droplet.png differ diff --git a/app/assets/images/emoji/drum.png b/app/assets/images/emoji/drum.png new file mode 100644 index 00000000000..b038727cc99 Binary files /dev/null and b/app/assets/images/emoji/drum.png differ diff --git a/app/assets/images/emoji/duck.png b/app/assets/images/emoji/duck.png new file mode 100644 index 00000000000..74330b77ca3 Binary files /dev/null and b/app/assets/images/emoji/duck.png differ diff --git a/app/assets/images/emoji/dvd.png b/app/assets/images/emoji/dvd.png new file mode 100644 index 00000000000..045a6f7a08d Binary files /dev/null and b/app/assets/images/emoji/dvd.png differ diff --git a/app/assets/images/emoji/e-mail.png b/app/assets/images/emoji/e-mail.png new file mode 100644 index 00000000000..d22e654a20b Binary files /dev/null and b/app/assets/images/emoji/e-mail.png differ diff --git a/app/assets/images/emoji/eagle.png b/app/assets/images/emoji/eagle.png new file mode 100644 index 00000000000..4f277debeef Binary files /dev/null and b/app/assets/images/emoji/eagle.png differ diff --git a/app/assets/images/emoji/ear.png b/app/assets/images/emoji/ear.png new file mode 100644 index 00000000000..f84f9ff154a Binary files /dev/null and b/app/assets/images/emoji/ear.png differ diff --git a/app/assets/images/emoji/ear_of_rice.png b/app/assets/images/emoji/ear_of_rice.png new file mode 100644 index 00000000000..3564d9d643a Binary files /dev/null and b/app/assets/images/emoji/ear_of_rice.png differ diff --git a/app/assets/images/emoji/ear_tone1.png b/app/assets/images/emoji/ear_tone1.png new file mode 100644 index 00000000000..d09e1e41996 Binary files /dev/null and b/app/assets/images/emoji/ear_tone1.png differ diff --git a/app/assets/images/emoji/ear_tone2.png b/app/assets/images/emoji/ear_tone2.png new file mode 100644 index 00000000000..300d60a9948 Binary files /dev/null and b/app/assets/images/emoji/ear_tone2.png differ diff --git a/app/assets/images/emoji/ear_tone3.png b/app/assets/images/emoji/ear_tone3.png new file mode 100644 index 00000000000..2a56eebe445 Binary files /dev/null and b/app/assets/images/emoji/ear_tone3.png differ diff --git a/app/assets/images/emoji/ear_tone4.png b/app/assets/images/emoji/ear_tone4.png new file mode 100644 index 00000000000..bd270f7763e Binary files /dev/null and b/app/assets/images/emoji/ear_tone4.png differ diff --git a/app/assets/images/emoji/ear_tone5.png b/app/assets/images/emoji/ear_tone5.png new file mode 100644 index 00000000000..b96bb441dff Binary files /dev/null and b/app/assets/images/emoji/ear_tone5.png differ diff --git a/app/assets/images/emoji/earth_africa.png b/app/assets/images/emoji/earth_africa.png new file mode 100644 index 00000000000..66c3348c23a Binary files /dev/null and b/app/assets/images/emoji/earth_africa.png differ diff --git a/app/assets/images/emoji/earth_americas.png b/app/assets/images/emoji/earth_americas.png new file mode 100644 index 00000000000..538c3cddd68 Binary files /dev/null and b/app/assets/images/emoji/earth_americas.png differ diff --git a/app/assets/images/emoji/earth_asia.png b/app/assets/images/emoji/earth_asia.png new file mode 100644 index 00000000000..d8df97fec3c Binary files /dev/null and b/app/assets/images/emoji/earth_asia.png differ diff --git a/app/assets/images/emoji/egg.png b/app/assets/images/emoji/egg.png new file mode 100644 index 00000000000..c171974d993 Binary files /dev/null and b/app/assets/images/emoji/egg.png differ diff --git a/app/assets/images/emoji/eggplant.png b/app/assets/images/emoji/eggplant.png new file mode 100644 index 00000000000..fafd7c1a14c Binary files /dev/null and b/app/assets/images/emoji/eggplant.png differ diff --git a/app/assets/images/emoji/eight.png b/app/assets/images/emoji/eight.png new file mode 100644 index 00000000000..8c95874d4c5 Binary files /dev/null and b/app/assets/images/emoji/eight.png differ diff --git a/app/assets/images/emoji/eight_pointed_black_star.png b/app/assets/images/emoji/eight_pointed_black_star.png new file mode 100644 index 00000000000..820179bda50 Binary files /dev/null and b/app/assets/images/emoji/eight_pointed_black_star.png differ diff --git a/app/assets/images/emoji/eight_spoked_asterisk.png b/app/assets/images/emoji/eight_spoked_asterisk.png new file mode 100644 index 00000000000..3307ffa62ee Binary files /dev/null and b/app/assets/images/emoji/eight_spoked_asterisk.png differ diff --git a/app/assets/images/emoji/eject.png b/app/assets/images/emoji/eject.png new file mode 100644 index 00000000000..ec5cfc48973 Binary files /dev/null and b/app/assets/images/emoji/eject.png differ diff --git a/app/assets/images/emoji/electric_plug.png b/app/assets/images/emoji/electric_plug.png new file mode 100644 index 00000000000..31d1eb215b4 Binary files /dev/null and b/app/assets/images/emoji/electric_plug.png differ diff --git a/app/assets/images/emoji/elephant.png b/app/assets/images/emoji/elephant.png new file mode 100644 index 00000000000..b8a6d140595 Binary files /dev/null and b/app/assets/images/emoji/elephant.png differ diff --git a/app/assets/images/emoji/end.png b/app/assets/images/emoji/end.png new file mode 100644 index 00000000000..ef3ccd5f367 Binary files /dev/null and b/app/assets/images/emoji/end.png differ diff --git a/app/assets/images/emoji/envelope.png b/app/assets/images/emoji/envelope.png new file mode 100644 index 00000000000..ec77ac375a4 Binary files /dev/null and b/app/assets/images/emoji/envelope.png differ diff --git a/app/assets/images/emoji/envelope_with_arrow.png b/app/assets/images/emoji/envelope_with_arrow.png new file mode 100644 index 00000000000..7448a6b7673 Binary files /dev/null and b/app/assets/images/emoji/envelope_with_arrow.png differ diff --git a/app/assets/images/emoji/euro.png b/app/assets/images/emoji/euro.png new file mode 100644 index 00000000000..a49020820e1 Binary files /dev/null and b/app/assets/images/emoji/euro.png differ diff --git a/app/assets/images/emoji/european_castle.png b/app/assets/images/emoji/european_castle.png new file mode 100644 index 00000000000..888d11332ce Binary files /dev/null and b/app/assets/images/emoji/european_castle.png differ diff --git a/app/assets/images/emoji/european_post_office.png b/app/assets/images/emoji/european_post_office.png new file mode 100644 index 00000000000..3745aff8dd2 Binary files /dev/null and b/app/assets/images/emoji/european_post_office.png differ diff --git a/app/assets/images/emoji/evergreen_tree.png b/app/assets/images/emoji/evergreen_tree.png new file mode 100644 index 00000000000..f679d8dd772 Binary files /dev/null and b/app/assets/images/emoji/evergreen_tree.png differ diff --git a/app/assets/images/emoji/exclamation.png b/app/assets/images/emoji/exclamation.png new file mode 100644 index 00000000000..2c14406422f Binary files /dev/null and b/app/assets/images/emoji/exclamation.png differ diff --git a/app/assets/images/emoji/expressionless.png b/app/assets/images/emoji/expressionless.png new file mode 100644 index 00000000000..2954017f6c2 Binary files /dev/null and b/app/assets/images/emoji/expressionless.png differ diff --git a/app/assets/images/emoji/eye.png b/app/assets/images/emoji/eye.png new file mode 100644 index 00000000000..9d989cdd375 Binary files /dev/null and b/app/assets/images/emoji/eye.png differ diff --git a/app/assets/images/emoji/eye_in_speech_bubble.png b/app/assets/images/emoji/eye_in_speech_bubble.png new file mode 100644 index 00000000000..21bd22bbcce Binary files /dev/null and b/app/assets/images/emoji/eye_in_speech_bubble.png differ diff --git a/app/assets/images/emoji/eyeglasses.png b/app/assets/images/emoji/eyeglasses.png new file mode 100644 index 00000000000..865d8274acf Binary files /dev/null and b/app/assets/images/emoji/eyeglasses.png differ diff --git a/app/assets/images/emoji/eyes.png b/app/assets/images/emoji/eyes.png new file mode 100644 index 00000000000..2102ada7e09 Binary files /dev/null and b/app/assets/images/emoji/eyes.png differ diff --git a/app/assets/images/emoji/face_palm.png b/app/assets/images/emoji/face_palm.png new file mode 100644 index 00000000000..defc796cf16 Binary files /dev/null and b/app/assets/images/emoji/face_palm.png differ diff --git a/app/assets/images/emoji/face_palm_tone1.png b/app/assets/images/emoji/face_palm_tone1.png new file mode 100644 index 00000000000..2f4b010bb40 Binary files /dev/null and b/app/assets/images/emoji/face_palm_tone1.png differ diff --git a/app/assets/images/emoji/face_palm_tone2.png b/app/assets/images/emoji/face_palm_tone2.png new file mode 100644 index 00000000000..97fb6831687 Binary files /dev/null and b/app/assets/images/emoji/face_palm_tone2.png differ diff --git a/app/assets/images/emoji/face_palm_tone3.png b/app/assets/images/emoji/face_palm_tone3.png new file mode 100644 index 00000000000..b5b5c1e5306 Binary files /dev/null and b/app/assets/images/emoji/face_palm_tone3.png differ diff --git a/app/assets/images/emoji/face_palm_tone4.png b/app/assets/images/emoji/face_palm_tone4.png new file mode 100644 index 00000000000..2840b113483 Binary files /dev/null and b/app/assets/images/emoji/face_palm_tone4.png differ diff --git a/app/assets/images/emoji/face_palm_tone5.png b/app/assets/images/emoji/face_palm_tone5.png new file mode 100644 index 00000000000..6f070db98be Binary files /dev/null and b/app/assets/images/emoji/face_palm_tone5.png differ diff --git a/app/assets/images/emoji/factory.png b/app/assets/images/emoji/factory.png new file mode 100644 index 00000000000..e1d2ddf4a27 Binary files /dev/null and b/app/assets/images/emoji/factory.png differ diff --git a/app/assets/images/emoji/fallen_leaf.png b/app/assets/images/emoji/fallen_leaf.png new file mode 100644 index 00000000000..0d60e7bdf2d Binary files /dev/null and b/app/assets/images/emoji/fallen_leaf.png differ diff --git a/app/assets/images/emoji/family.png b/app/assets/images/emoji/family.png new file mode 100644 index 00000000000..26421965791 Binary files /dev/null and b/app/assets/images/emoji/family.png differ diff --git a/app/assets/images/emoji/family_mmb.png b/app/assets/images/emoji/family_mmb.png new file mode 100644 index 00000000000..7a2e4e2c491 Binary files /dev/null and b/app/assets/images/emoji/family_mmb.png differ diff --git a/app/assets/images/emoji/family_mmbb.png b/app/assets/images/emoji/family_mmbb.png new file mode 100644 index 00000000000..81e6c0fc0ee Binary files /dev/null and b/app/assets/images/emoji/family_mmbb.png differ diff --git a/app/assets/images/emoji/family_mmg.png b/app/assets/images/emoji/family_mmg.png new file mode 100644 index 00000000000..932a85e1fe5 Binary files /dev/null and b/app/assets/images/emoji/family_mmg.png differ diff --git a/app/assets/images/emoji/family_mmgb.png b/app/assets/images/emoji/family_mmgb.png new file mode 100644 index 00000000000..41e35166670 Binary files /dev/null and b/app/assets/images/emoji/family_mmgb.png differ diff --git a/app/assets/images/emoji/family_mmgg.png b/app/assets/images/emoji/family_mmgg.png new file mode 100644 index 00000000000..8e8ccfe6c7f Binary files /dev/null and b/app/assets/images/emoji/family_mmgg.png differ diff --git a/app/assets/images/emoji/family_mwbb.png b/app/assets/images/emoji/family_mwbb.png new file mode 100644 index 00000000000..b544fbe573f Binary files /dev/null and b/app/assets/images/emoji/family_mwbb.png differ diff --git a/app/assets/images/emoji/family_mwg.png b/app/assets/images/emoji/family_mwg.png new file mode 100644 index 00000000000..71d2681c32a Binary files /dev/null and b/app/assets/images/emoji/family_mwg.png differ diff --git a/app/assets/images/emoji/family_mwgb.png b/app/assets/images/emoji/family_mwgb.png new file mode 100644 index 00000000000..40dbf1f7a18 Binary files /dev/null and b/app/assets/images/emoji/family_mwgb.png differ diff --git a/app/assets/images/emoji/family_mwgg.png b/app/assets/images/emoji/family_mwgg.png new file mode 100644 index 00000000000..bfefa4879cb Binary files /dev/null and b/app/assets/images/emoji/family_mwgg.png differ diff --git a/app/assets/images/emoji/family_wwb.png b/app/assets/images/emoji/family_wwb.png new file mode 100644 index 00000000000..836feae7c78 Binary files /dev/null and b/app/assets/images/emoji/family_wwb.png differ diff --git a/app/assets/images/emoji/family_wwbb.png b/app/assets/images/emoji/family_wwbb.png new file mode 100644 index 00000000000..6c6ba45e7bb Binary files /dev/null and b/app/assets/images/emoji/family_wwbb.png differ diff --git a/app/assets/images/emoji/family_wwg.png b/app/assets/images/emoji/family_wwg.png new file mode 100644 index 00000000000..41225c6fa5a Binary files /dev/null and b/app/assets/images/emoji/family_wwg.png differ diff --git a/app/assets/images/emoji/family_wwgb.png b/app/assets/images/emoji/family_wwgb.png new file mode 100644 index 00000000000..284d29ab5da Binary files /dev/null and b/app/assets/images/emoji/family_wwgb.png differ diff --git a/app/assets/images/emoji/family_wwgg.png b/app/assets/images/emoji/family_wwgg.png new file mode 100644 index 00000000000..d8d3f49b85f Binary files /dev/null and b/app/assets/images/emoji/family_wwgg.png differ diff --git a/app/assets/images/emoji/fast_forward.png b/app/assets/images/emoji/fast_forward.png new file mode 100644 index 00000000000..c406fedfdb1 Binary files /dev/null and b/app/assets/images/emoji/fast_forward.png differ diff --git a/app/assets/images/emoji/fax.png b/app/assets/images/emoji/fax.png new file mode 100644 index 00000000000..6f929e294c2 Binary files /dev/null and b/app/assets/images/emoji/fax.png differ diff --git a/app/assets/images/emoji/fearful.png b/app/assets/images/emoji/fearful.png new file mode 100644 index 00000000000..eb8b347cef9 Binary files /dev/null and b/app/assets/images/emoji/fearful.png differ diff --git a/app/assets/images/emoji/feet.png b/app/assets/images/emoji/feet.png new file mode 100644 index 00000000000..5fe568cee93 Binary files /dev/null and b/app/assets/images/emoji/feet.png differ diff --git a/app/assets/images/emoji/fencer.png b/app/assets/images/emoji/fencer.png new file mode 100644 index 00000000000..5288c920eb9 Binary files /dev/null and b/app/assets/images/emoji/fencer.png differ diff --git a/app/assets/images/emoji/ferris_wheel.png b/app/assets/images/emoji/ferris_wheel.png new file mode 100644 index 00000000000..55c8ff0475b Binary files /dev/null and b/app/assets/images/emoji/ferris_wheel.png differ diff --git a/app/assets/images/emoji/ferry.png b/app/assets/images/emoji/ferry.png new file mode 100644 index 00000000000..41816b3ae34 Binary files /dev/null and b/app/assets/images/emoji/ferry.png differ diff --git a/app/assets/images/emoji/field_hockey.png b/app/assets/images/emoji/field_hockey.png new file mode 100644 index 00000000000..839637716ee Binary files /dev/null and b/app/assets/images/emoji/field_hockey.png differ diff --git a/app/assets/images/emoji/file_cabinet.png b/app/assets/images/emoji/file_cabinet.png new file mode 100644 index 00000000000..fddc65dde96 Binary files /dev/null and b/app/assets/images/emoji/file_cabinet.png differ diff --git a/app/assets/images/emoji/file_folder.png b/app/assets/images/emoji/file_folder.png new file mode 100644 index 00000000000..addedaf0870 Binary files /dev/null and b/app/assets/images/emoji/file_folder.png differ diff --git a/app/assets/images/emoji/film_frames.png b/app/assets/images/emoji/film_frames.png new file mode 100644 index 00000000000..30143aedbe6 Binary files /dev/null and b/app/assets/images/emoji/film_frames.png differ diff --git a/app/assets/images/emoji/fingers_crossed.png b/app/assets/images/emoji/fingers_crossed.png new file mode 100644 index 00000000000..4cd18514ea3 Binary files /dev/null and b/app/assets/images/emoji/fingers_crossed.png differ diff --git a/app/assets/images/emoji/fingers_crossed_tone1.png b/app/assets/images/emoji/fingers_crossed_tone1.png new file mode 100644 index 00000000000..dd2384a6cd5 Binary files /dev/null and b/app/assets/images/emoji/fingers_crossed_tone1.png differ diff --git a/app/assets/images/emoji/fingers_crossed_tone2.png b/app/assets/images/emoji/fingers_crossed_tone2.png new file mode 100644 index 00000000000..6228401befe Binary files /dev/null and b/app/assets/images/emoji/fingers_crossed_tone2.png differ diff --git a/app/assets/images/emoji/fingers_crossed_tone3.png b/app/assets/images/emoji/fingers_crossed_tone3.png new file mode 100644 index 00000000000..b1074da15f5 Binary files /dev/null and b/app/assets/images/emoji/fingers_crossed_tone3.png differ diff --git a/app/assets/images/emoji/fingers_crossed_tone4.png b/app/assets/images/emoji/fingers_crossed_tone4.png new file mode 100644 index 00000000000..75e05e4d332 Binary files /dev/null and b/app/assets/images/emoji/fingers_crossed_tone4.png differ diff --git a/app/assets/images/emoji/fingers_crossed_tone5.png b/app/assets/images/emoji/fingers_crossed_tone5.png new file mode 100644 index 00000000000..761aebdc30f Binary files /dev/null and b/app/assets/images/emoji/fingers_crossed_tone5.png differ diff --git a/app/assets/images/emoji/fire.png b/app/assets/images/emoji/fire.png new file mode 100644 index 00000000000..bd3775a460b Binary files /dev/null and b/app/assets/images/emoji/fire.png differ diff --git a/app/assets/images/emoji/fire_engine.png b/app/assets/images/emoji/fire_engine.png new file mode 100644 index 00000000000..2cd45b7cf7e Binary files /dev/null and b/app/assets/images/emoji/fire_engine.png differ diff --git a/app/assets/images/emoji/fireworks.png b/app/assets/images/emoji/fireworks.png new file mode 100644 index 00000000000..176c8b58265 Binary files /dev/null and b/app/assets/images/emoji/fireworks.png differ diff --git a/app/assets/images/emoji/first_place.png b/app/assets/images/emoji/first_place.png new file mode 100644 index 00000000000..15612b66492 Binary files /dev/null and b/app/assets/images/emoji/first_place.png differ diff --git a/app/assets/images/emoji/first_quarter_moon.png b/app/assets/images/emoji/first_quarter_moon.png new file mode 100644 index 00000000000..5dccaf72a4f Binary files /dev/null and b/app/assets/images/emoji/first_quarter_moon.png differ diff --git a/app/assets/images/emoji/first_quarter_moon_with_face.png b/app/assets/images/emoji/first_quarter_moon_with_face.png new file mode 100644 index 00000000000..cd8a3d7acd8 Binary files /dev/null and b/app/assets/images/emoji/first_quarter_moon_with_face.png differ diff --git a/app/assets/images/emoji/fish.png b/app/assets/images/emoji/fish.png new file mode 100644 index 00000000000..c2d2faaacd4 Binary files /dev/null and b/app/assets/images/emoji/fish.png differ diff --git a/app/assets/images/emoji/fish_cake.png b/app/assets/images/emoji/fish_cake.png new file mode 100644 index 00000000000..157bded65db Binary files /dev/null and b/app/assets/images/emoji/fish_cake.png differ diff --git a/app/assets/images/emoji/fishing_pole_and_fish.png b/app/assets/images/emoji/fishing_pole_and_fish.png new file mode 100644 index 00000000000..dfcdf07eb50 Binary files /dev/null and b/app/assets/images/emoji/fishing_pole_and_fish.png differ diff --git a/app/assets/images/emoji/fist.png b/app/assets/images/emoji/fist.png new file mode 100644 index 00000000000..de33592bf98 Binary files /dev/null and b/app/assets/images/emoji/fist.png differ diff --git a/app/assets/images/emoji/fist_tone1.png b/app/assets/images/emoji/fist_tone1.png new file mode 100644 index 00000000000..02809e2dd68 Binary files /dev/null and b/app/assets/images/emoji/fist_tone1.png differ diff --git a/app/assets/images/emoji/fist_tone2.png b/app/assets/images/emoji/fist_tone2.png new file mode 100644 index 00000000000..5de34810383 Binary files /dev/null and b/app/assets/images/emoji/fist_tone2.png differ diff --git a/app/assets/images/emoji/fist_tone3.png b/app/assets/images/emoji/fist_tone3.png new file mode 100644 index 00000000000..0d5240129b1 Binary files /dev/null and b/app/assets/images/emoji/fist_tone3.png differ diff --git a/app/assets/images/emoji/fist_tone4.png b/app/assets/images/emoji/fist_tone4.png new file mode 100644 index 00000000000..a95c0dd634b Binary files /dev/null and b/app/assets/images/emoji/fist_tone4.png differ diff --git a/app/assets/images/emoji/fist_tone5.png b/app/assets/images/emoji/fist_tone5.png new file mode 100644 index 00000000000..a2f092fd8c7 Binary files /dev/null and b/app/assets/images/emoji/fist_tone5.png differ diff --git a/app/assets/images/emoji/five.png b/app/assets/images/emoji/five.png new file mode 100644 index 00000000000..d14371f3f27 Binary files /dev/null and b/app/assets/images/emoji/five.png differ diff --git a/app/assets/images/emoji/flag_ac.png b/app/assets/images/emoji/flag_ac.png new file mode 100644 index 00000000000..286239920c7 Binary files /dev/null and b/app/assets/images/emoji/flag_ac.png differ diff --git a/app/assets/images/emoji/flag_ad.png b/app/assets/images/emoji/flag_ad.png new file mode 100644 index 00000000000..20f4b14e8ad Binary files /dev/null and b/app/assets/images/emoji/flag_ad.png differ diff --git a/app/assets/images/emoji/flag_ae.png b/app/assets/images/emoji/flag_ae.png new file mode 100644 index 00000000000..d16ffe4b862 Binary files /dev/null and b/app/assets/images/emoji/flag_ae.png differ diff --git a/app/assets/images/emoji/flag_af.png b/app/assets/images/emoji/flag_af.png new file mode 100644 index 00000000000..a51533b554d Binary files /dev/null and b/app/assets/images/emoji/flag_af.png differ diff --git a/app/assets/images/emoji/flag_ag.png b/app/assets/images/emoji/flag_ag.png new file mode 100644 index 00000000000..07f2ce397d0 Binary files /dev/null and b/app/assets/images/emoji/flag_ag.png differ diff --git a/app/assets/images/emoji/flag_ai.png b/app/assets/images/emoji/flag_ai.png new file mode 100644 index 00000000000..500b5ab09fb Binary files /dev/null and b/app/assets/images/emoji/flag_ai.png differ diff --git a/app/assets/images/emoji/flag_al.png b/app/assets/images/emoji/flag_al.png new file mode 100644 index 00000000000..03a20132cc6 Binary files /dev/null and b/app/assets/images/emoji/flag_al.png differ diff --git a/app/assets/images/emoji/flag_am.png b/app/assets/images/emoji/flag_am.png new file mode 100644 index 00000000000..2ad60a273ec Binary files /dev/null and b/app/assets/images/emoji/flag_am.png differ diff --git a/app/assets/images/emoji/flag_ao.png b/app/assets/images/emoji/flag_ao.png new file mode 100644 index 00000000000..cb46c31f862 Binary files /dev/null and b/app/assets/images/emoji/flag_ao.png differ diff --git a/app/assets/images/emoji/flag_aq.png b/app/assets/images/emoji/flag_aq.png new file mode 100644 index 00000000000..b272021d375 Binary files /dev/null and b/app/assets/images/emoji/flag_aq.png differ diff --git a/app/assets/images/emoji/flag_ar.png b/app/assets/images/emoji/flag_ar.png new file mode 100644 index 00000000000..73136caf3b7 Binary files /dev/null and b/app/assets/images/emoji/flag_ar.png differ diff --git a/app/assets/images/emoji/flag_as.png b/app/assets/images/emoji/flag_as.png new file mode 100644 index 00000000000..3db45a0d9f3 Binary files /dev/null and b/app/assets/images/emoji/flag_as.png differ diff --git a/app/assets/images/emoji/flag_at.png b/app/assets/images/emoji/flag_at.png new file mode 100644 index 00000000000..c43769dcb19 Binary files /dev/null and b/app/assets/images/emoji/flag_at.png differ diff --git a/app/assets/images/emoji/flag_au.png b/app/assets/images/emoji/flag_au.png new file mode 100644 index 00000000000..7794309c78c Binary files /dev/null and b/app/assets/images/emoji/flag_au.png differ diff --git a/app/assets/images/emoji/flag_aw.png b/app/assets/images/emoji/flag_aw.png new file mode 100644 index 00000000000..02c840d12c9 Binary files /dev/null and b/app/assets/images/emoji/flag_aw.png differ diff --git a/app/assets/images/emoji/flag_ax.png b/app/assets/images/emoji/flag_ax.png new file mode 100644 index 00000000000..fc5466174bb Binary files /dev/null and b/app/assets/images/emoji/flag_ax.png differ diff --git a/app/assets/images/emoji/flag_az.png b/app/assets/images/emoji/flag_az.png new file mode 100644 index 00000000000..89d3d15fd9f Binary files /dev/null and b/app/assets/images/emoji/flag_az.png differ diff --git a/app/assets/images/emoji/flag_ba.png b/app/assets/images/emoji/flag_ba.png new file mode 100644 index 00000000000..25fe407e13c Binary files /dev/null and b/app/assets/images/emoji/flag_ba.png differ diff --git a/app/assets/images/emoji/flag_bb.png b/app/assets/images/emoji/flag_bb.png new file mode 100644 index 00000000000..bccd8c5c9b0 Binary files /dev/null and b/app/assets/images/emoji/flag_bb.png differ diff --git a/app/assets/images/emoji/flag_bd.png b/app/assets/images/emoji/flag_bd.png new file mode 100644 index 00000000000..b0597a3149b Binary files /dev/null and b/app/assets/images/emoji/flag_bd.png differ diff --git a/app/assets/images/emoji/flag_be.png b/app/assets/images/emoji/flag_be.png new file mode 100644 index 00000000000..551f086e3c4 Binary files /dev/null and b/app/assets/images/emoji/flag_be.png differ diff --git a/app/assets/images/emoji/flag_bf.png b/app/assets/images/emoji/flag_bf.png new file mode 100644 index 00000000000..444d4829f94 Binary files /dev/null and b/app/assets/images/emoji/flag_bf.png differ diff --git a/app/assets/images/emoji/flag_bg.png b/app/assets/images/emoji/flag_bg.png new file mode 100644 index 00000000000..821eee5e170 Binary files /dev/null and b/app/assets/images/emoji/flag_bg.png differ diff --git a/app/assets/images/emoji/flag_bh.png b/app/assets/images/emoji/flag_bh.png new file mode 100644 index 00000000000..f33724249f0 Binary files /dev/null and b/app/assets/images/emoji/flag_bh.png differ diff --git a/app/assets/images/emoji/flag_bi.png b/app/assets/images/emoji/flag_bi.png new file mode 100644 index 00000000000..ea20ac93211 Binary files /dev/null and b/app/assets/images/emoji/flag_bi.png differ diff --git a/app/assets/images/emoji/flag_bj.png b/app/assets/images/emoji/flag_bj.png new file mode 100644 index 00000000000..7cca4f80457 Binary files /dev/null and b/app/assets/images/emoji/flag_bj.png differ diff --git a/app/assets/images/emoji/flag_bl.png b/app/assets/images/emoji/flag_bl.png new file mode 100644 index 00000000000..1082e78999f Binary files /dev/null and b/app/assets/images/emoji/flag_bl.png differ diff --git a/app/assets/images/emoji/flag_black.png b/app/assets/images/emoji/flag_black.png new file mode 100644 index 00000000000..0e28d05d5ac Binary files /dev/null and b/app/assets/images/emoji/flag_black.png differ diff --git a/app/assets/images/emoji/flag_bm.png b/app/assets/images/emoji/flag_bm.png new file mode 100644 index 00000000000..ab8cafdac63 Binary files /dev/null and b/app/assets/images/emoji/flag_bm.png differ diff --git a/app/assets/images/emoji/flag_bn.png b/app/assets/images/emoji/flag_bn.png new file mode 100644 index 00000000000..caa9329a896 Binary files /dev/null and b/app/assets/images/emoji/flag_bn.png differ diff --git a/app/assets/images/emoji/flag_bo.png b/app/assets/images/emoji/flag_bo.png new file mode 100644 index 00000000000..98af62b3da7 Binary files /dev/null and b/app/assets/images/emoji/flag_bo.png differ diff --git a/app/assets/images/emoji/flag_bq.png b/app/assets/images/emoji/flag_bq.png new file mode 100644 index 00000000000..cb978ef9de9 Binary files /dev/null and b/app/assets/images/emoji/flag_bq.png differ diff --git a/app/assets/images/emoji/flag_br.png b/app/assets/images/emoji/flag_br.png new file mode 100644 index 00000000000..b139366a42b Binary files /dev/null and b/app/assets/images/emoji/flag_br.png differ diff --git a/app/assets/images/emoji/flag_bs.png b/app/assets/images/emoji/flag_bs.png new file mode 100644 index 00000000000..d36bcd2fb52 Binary files /dev/null and b/app/assets/images/emoji/flag_bs.png differ diff --git a/app/assets/images/emoji/flag_bt.png b/app/assets/images/emoji/flag_bt.png new file mode 100644 index 00000000000..ed57aa0360e Binary files /dev/null and b/app/assets/images/emoji/flag_bt.png differ diff --git a/app/assets/images/emoji/flag_bv.png b/app/assets/images/emoji/flag_bv.png new file mode 100644 index 00000000000..5884e648228 Binary files /dev/null and b/app/assets/images/emoji/flag_bv.png differ diff --git a/app/assets/images/emoji/flag_bw.png b/app/assets/images/emoji/flag_bw.png new file mode 100644 index 00000000000..cb12f34739d Binary files /dev/null and b/app/assets/images/emoji/flag_bw.png differ diff --git a/app/assets/images/emoji/flag_by.png b/app/assets/images/emoji/flag_by.png new file mode 100644 index 00000000000..859c05beb13 Binary files /dev/null and b/app/assets/images/emoji/flag_by.png differ diff --git a/app/assets/images/emoji/flag_bz.png b/app/assets/images/emoji/flag_bz.png new file mode 100644 index 00000000000..34761cd03d8 Binary files /dev/null and b/app/assets/images/emoji/flag_bz.png differ diff --git a/app/assets/images/emoji/flag_ca.png b/app/assets/images/emoji/flag_ca.png new file mode 100644 index 00000000000..7c5b390e85b Binary files /dev/null and b/app/assets/images/emoji/flag_ca.png differ diff --git a/app/assets/images/emoji/flag_cc.png b/app/assets/images/emoji/flag_cc.png new file mode 100644 index 00000000000..b6555a23d83 Binary files /dev/null and b/app/assets/images/emoji/flag_cc.png differ diff --git a/app/assets/images/emoji/flag_cd.png b/app/assets/images/emoji/flag_cd.png new file mode 100644 index 00000000000..fa92009771d Binary files /dev/null and b/app/assets/images/emoji/flag_cd.png differ diff --git a/app/assets/images/emoji/flag_cf.png b/app/assets/images/emoji/flag_cf.png new file mode 100644 index 00000000000..b969ae29ea9 Binary files /dev/null and b/app/assets/images/emoji/flag_cf.png differ diff --git a/app/assets/images/emoji/flag_cg.png b/app/assets/images/emoji/flag_cg.png new file mode 100644 index 00000000000..3a38a40a95e Binary files /dev/null and b/app/assets/images/emoji/flag_cg.png differ diff --git a/app/assets/images/emoji/flag_ch.png b/app/assets/images/emoji/flag_ch.png new file mode 100644 index 00000000000..5ff86b8a3b7 Binary files /dev/null and b/app/assets/images/emoji/flag_ch.png differ diff --git a/app/assets/images/emoji/flag_ci.png b/app/assets/images/emoji/flag_ci.png new file mode 100644 index 00000000000..e3b4d15c7f1 Binary files /dev/null and b/app/assets/images/emoji/flag_ci.png differ diff --git a/app/assets/images/emoji/flag_ck.png b/app/assets/images/emoji/flag_ck.png new file mode 100644 index 00000000000..b6b53dbc1c4 Binary files /dev/null and b/app/assets/images/emoji/flag_ck.png differ diff --git a/app/assets/images/emoji/flag_cl.png b/app/assets/images/emoji/flag_cl.png new file mode 100644 index 00000000000..c9390da5499 Binary files /dev/null and b/app/assets/images/emoji/flag_cl.png differ diff --git a/app/assets/images/emoji/flag_cm.png b/app/assets/images/emoji/flag_cm.png new file mode 100644 index 00000000000..2d3f6ec4518 Binary files /dev/null and b/app/assets/images/emoji/flag_cm.png differ diff --git a/app/assets/images/emoji/flag_cn.png b/app/assets/images/emoji/flag_cn.png new file mode 100644 index 00000000000..0a7f350a6d2 Binary files /dev/null and b/app/assets/images/emoji/flag_cn.png differ diff --git a/app/assets/images/emoji/flag_co.png b/app/assets/images/emoji/flag_co.png new file mode 100644 index 00000000000..7e0f5e0dc3c Binary files /dev/null and b/app/assets/images/emoji/flag_co.png differ diff --git a/app/assets/images/emoji/flag_cp.png b/app/assets/images/emoji/flag_cp.png new file mode 100644 index 00000000000..70c761036bd Binary files /dev/null and b/app/assets/images/emoji/flag_cp.png differ diff --git a/app/assets/images/emoji/flag_cr.png b/app/assets/images/emoji/flag_cr.png new file mode 100644 index 00000000000..a5fce126515 Binary files /dev/null and b/app/assets/images/emoji/flag_cr.png differ diff --git a/app/assets/images/emoji/flag_cu.png b/app/assets/images/emoji/flag_cu.png new file mode 100644 index 00000000000..447328f7dfd Binary files /dev/null and b/app/assets/images/emoji/flag_cu.png differ diff --git a/app/assets/images/emoji/flag_cv.png b/app/assets/images/emoji/flag_cv.png new file mode 100644 index 00000000000..43faf4d64d5 Binary files /dev/null and b/app/assets/images/emoji/flag_cv.png differ diff --git a/app/assets/images/emoji/flag_cw.png b/app/assets/images/emoji/flag_cw.png new file mode 100644 index 00000000000..eb39e8d0078 Binary files /dev/null and b/app/assets/images/emoji/flag_cw.png differ diff --git a/app/assets/images/emoji/flag_cx.png b/app/assets/images/emoji/flag_cx.png new file mode 100644 index 00000000000..09d21359f3a Binary files /dev/null and b/app/assets/images/emoji/flag_cx.png differ diff --git a/app/assets/images/emoji/flag_cy.png b/app/assets/images/emoji/flag_cy.png new file mode 100644 index 00000000000..154a7aa3176 Binary files /dev/null and b/app/assets/images/emoji/flag_cy.png differ diff --git a/app/assets/images/emoji/flag_cz.png b/app/assets/images/emoji/flag_cz.png new file mode 100644 index 00000000000..9737ca223c7 Binary files /dev/null and b/app/assets/images/emoji/flag_cz.png differ diff --git a/app/assets/images/emoji/flag_de.png b/app/assets/images/emoji/flag_de.png new file mode 100644 index 00000000000..98ed76b3bab Binary files /dev/null and b/app/assets/images/emoji/flag_de.png differ diff --git a/app/assets/images/emoji/flag_dg.png b/app/assets/images/emoji/flag_dg.png new file mode 100644 index 00000000000..aae927d14b8 Binary files /dev/null and b/app/assets/images/emoji/flag_dg.png differ diff --git a/app/assets/images/emoji/flag_dj.png b/app/assets/images/emoji/flag_dj.png new file mode 100644 index 00000000000..73c2a2acbd9 Binary files /dev/null and b/app/assets/images/emoji/flag_dj.png differ diff --git a/app/assets/images/emoji/flag_dk.png b/app/assets/images/emoji/flag_dk.png new file mode 100644 index 00000000000..e5a60b06256 Binary files /dev/null and b/app/assets/images/emoji/flag_dk.png differ diff --git a/app/assets/images/emoji/flag_dm.png b/app/assets/images/emoji/flag_dm.png new file mode 100644 index 00000000000..50f8a53981d Binary files /dev/null and b/app/assets/images/emoji/flag_dm.png differ diff --git a/app/assets/images/emoji/flag_do.png b/app/assets/images/emoji/flag_do.png new file mode 100644 index 00000000000..037a45d7c26 Binary files /dev/null and b/app/assets/images/emoji/flag_do.png differ diff --git a/app/assets/images/emoji/flag_dz.png b/app/assets/images/emoji/flag_dz.png new file mode 100644 index 00000000000..24945b10f2d Binary files /dev/null and b/app/assets/images/emoji/flag_dz.png differ diff --git a/app/assets/images/emoji/flag_ea.png b/app/assets/images/emoji/flag_ea.png new file mode 100644 index 00000000000..356ff347838 Binary files /dev/null and b/app/assets/images/emoji/flag_ea.png differ diff --git a/app/assets/images/emoji/flag_ec.png b/app/assets/images/emoji/flag_ec.png new file mode 100644 index 00000000000..13814594619 Binary files /dev/null and b/app/assets/images/emoji/flag_ec.png differ diff --git a/app/assets/images/emoji/flag_ee.png b/app/assets/images/emoji/flag_ee.png new file mode 100644 index 00000000000..84f317e7747 Binary files /dev/null and b/app/assets/images/emoji/flag_ee.png differ diff --git a/app/assets/images/emoji/flag_eg.png b/app/assets/images/emoji/flag_eg.png new file mode 100644 index 00000000000..57786064a95 Binary files /dev/null and b/app/assets/images/emoji/flag_eg.png differ diff --git a/app/assets/images/emoji/flag_eh.png b/app/assets/images/emoji/flag_eh.png new file mode 100644 index 00000000000..4d7a76687f6 Binary files /dev/null and b/app/assets/images/emoji/flag_eh.png differ diff --git a/app/assets/images/emoji/flag_er.png b/app/assets/images/emoji/flag_er.png new file mode 100644 index 00000000000..0c3c724c1fb Binary files /dev/null and b/app/assets/images/emoji/flag_er.png differ diff --git a/app/assets/images/emoji/flag_es.png b/app/assets/images/emoji/flag_es.png new file mode 100644 index 00000000000..3e73597a225 Binary files /dev/null and b/app/assets/images/emoji/flag_es.png differ diff --git a/app/assets/images/emoji/flag_et.png b/app/assets/images/emoji/flag_et.png new file mode 100644 index 00000000000..9560a134c97 Binary files /dev/null and b/app/assets/images/emoji/flag_et.png differ diff --git a/app/assets/images/emoji/flag_eu.png b/app/assets/images/emoji/flag_eu.png new file mode 100644 index 00000000000..0b456cf3330 Binary files /dev/null and b/app/assets/images/emoji/flag_eu.png differ diff --git a/app/assets/images/emoji/flag_fi.png b/app/assets/images/emoji/flag_fi.png new file mode 100644 index 00000000000..ebcf58abfc5 Binary files /dev/null and b/app/assets/images/emoji/flag_fi.png differ diff --git a/app/assets/images/emoji/flag_fj.png b/app/assets/images/emoji/flag_fj.png new file mode 100644 index 00000000000..9cc8c37fe37 Binary files /dev/null and b/app/assets/images/emoji/flag_fj.png differ diff --git a/app/assets/images/emoji/flag_fk.png b/app/assets/images/emoji/flag_fk.png new file mode 100644 index 00000000000..61372fd2549 Binary files /dev/null and b/app/assets/images/emoji/flag_fk.png differ diff --git a/app/assets/images/emoji/flag_fm.png b/app/assets/images/emoji/flag_fm.png new file mode 100644 index 00000000000..0889825c8e1 Binary files /dev/null and b/app/assets/images/emoji/flag_fm.png differ diff --git a/app/assets/images/emoji/flag_fo.png b/app/assets/images/emoji/flag_fo.png new file mode 100644 index 00000000000..9a4431b0831 Binary files /dev/null and b/app/assets/images/emoji/flag_fo.png differ diff --git a/app/assets/images/emoji/flag_fr.png b/app/assets/images/emoji/flag_fr.png new file mode 100644 index 00000000000..62ca19c3fcf Binary files /dev/null and b/app/assets/images/emoji/flag_fr.png differ diff --git a/app/assets/images/emoji/flag_ga.png b/app/assets/images/emoji/flag_ga.png new file mode 100644 index 00000000000..2e68e527a3e Binary files /dev/null and b/app/assets/images/emoji/flag_ga.png differ diff --git a/app/assets/images/emoji/flag_gb.png b/app/assets/images/emoji/flag_gb.png new file mode 100644 index 00000000000..3ed10f62347 Binary files /dev/null and b/app/assets/images/emoji/flag_gb.png differ diff --git a/app/assets/images/emoji/flag_gd.png b/app/assets/images/emoji/flag_gd.png new file mode 100644 index 00000000000..527aad33807 Binary files /dev/null and b/app/assets/images/emoji/flag_gd.png differ diff --git a/app/assets/images/emoji/flag_ge.png b/app/assets/images/emoji/flag_ge.png new file mode 100644 index 00000000000..a75d142480d Binary files /dev/null and b/app/assets/images/emoji/flag_ge.png differ diff --git a/app/assets/images/emoji/flag_gf.png b/app/assets/images/emoji/flag_gf.png new file mode 100644 index 00000000000..0cf96f327c0 Binary files /dev/null and b/app/assets/images/emoji/flag_gf.png differ diff --git a/app/assets/images/emoji/flag_gg.png b/app/assets/images/emoji/flag_gg.png new file mode 100644 index 00000000000..970002c7f76 Binary files /dev/null and b/app/assets/images/emoji/flag_gg.png differ diff --git a/app/assets/images/emoji/flag_gh.png b/app/assets/images/emoji/flag_gh.png new file mode 100644 index 00000000000..f31b5eb7b45 Binary files /dev/null and b/app/assets/images/emoji/flag_gh.png differ diff --git a/app/assets/images/emoji/flag_gi.png b/app/assets/images/emoji/flag_gi.png new file mode 100644 index 00000000000..e554a2a1d0c Binary files /dev/null and b/app/assets/images/emoji/flag_gi.png differ diff --git a/app/assets/images/emoji/flag_gl.png b/app/assets/images/emoji/flag_gl.png new file mode 100644 index 00000000000..2e795dd4e33 Binary files /dev/null and b/app/assets/images/emoji/flag_gl.png differ diff --git a/app/assets/images/emoji/flag_gm.png b/app/assets/images/emoji/flag_gm.png new file mode 100644 index 00000000000..bb69c0975a3 Binary files /dev/null and b/app/assets/images/emoji/flag_gm.png differ diff --git a/app/assets/images/emoji/flag_gn.png b/app/assets/images/emoji/flag_gn.png new file mode 100644 index 00000000000..1981f61dbf5 Binary files /dev/null and b/app/assets/images/emoji/flag_gn.png differ diff --git a/app/assets/images/emoji/flag_gp.png b/app/assets/images/emoji/flag_gp.png new file mode 100644 index 00000000000..10e42e672bd Binary files /dev/null and b/app/assets/images/emoji/flag_gp.png differ diff --git a/app/assets/images/emoji/flag_gq.png b/app/assets/images/emoji/flag_gq.png new file mode 100644 index 00000000000..11475e61eeb Binary files /dev/null and b/app/assets/images/emoji/flag_gq.png differ diff --git a/app/assets/images/emoji/flag_gr.png b/app/assets/images/emoji/flag_gr.png new file mode 100644 index 00000000000..0f6bb1b6b94 Binary files /dev/null and b/app/assets/images/emoji/flag_gr.png differ diff --git a/app/assets/images/emoji/flag_gs.png b/app/assets/images/emoji/flag_gs.png new file mode 100644 index 00000000000..6fc92780453 Binary files /dev/null and b/app/assets/images/emoji/flag_gs.png differ diff --git a/app/assets/images/emoji/flag_gt.png b/app/assets/images/emoji/flag_gt.png new file mode 100644 index 00000000000..7213d4139ed Binary files /dev/null and b/app/assets/images/emoji/flag_gt.png differ diff --git a/app/assets/images/emoji/flag_gu.png b/app/assets/images/emoji/flag_gu.png new file mode 100644 index 00000000000..4027549ca3c Binary files /dev/null and b/app/assets/images/emoji/flag_gu.png differ diff --git a/app/assets/images/emoji/flag_gw.png b/app/assets/images/emoji/flag_gw.png new file mode 100644 index 00000000000..6357f6225f4 Binary files /dev/null and b/app/assets/images/emoji/flag_gw.png differ diff --git a/app/assets/images/emoji/flag_gy.png b/app/assets/images/emoji/flag_gy.png new file mode 100644 index 00000000000..746e2fb7e44 Binary files /dev/null and b/app/assets/images/emoji/flag_gy.png differ diff --git a/app/assets/images/emoji/flag_hk.png b/app/assets/images/emoji/flag_hk.png new file mode 100644 index 00000000000..cf0c7151b56 Binary files /dev/null and b/app/assets/images/emoji/flag_hk.png differ diff --git a/app/assets/images/emoji/flag_hm.png b/app/assets/images/emoji/flag_hm.png new file mode 100644 index 00000000000..b613509e466 Binary files /dev/null and b/app/assets/images/emoji/flag_hm.png differ diff --git a/app/assets/images/emoji/flag_hn.png b/app/assets/images/emoji/flag_hn.png new file mode 100644 index 00000000000..402cdcefdf8 Binary files /dev/null and b/app/assets/images/emoji/flag_hn.png differ diff --git a/app/assets/images/emoji/flag_hr.png b/app/assets/images/emoji/flag_hr.png new file mode 100644 index 00000000000..46f4f06b4f2 Binary files /dev/null and b/app/assets/images/emoji/flag_hr.png differ diff --git a/app/assets/images/emoji/flag_ht.png b/app/assets/images/emoji/flag_ht.png new file mode 100644 index 00000000000..d8d0c888498 Binary files /dev/null and b/app/assets/images/emoji/flag_ht.png differ diff --git a/app/assets/images/emoji/flag_hu.png b/app/assets/images/emoji/flag_hu.png new file mode 100644 index 00000000000..a898de636a5 Binary files /dev/null and b/app/assets/images/emoji/flag_hu.png differ diff --git a/app/assets/images/emoji/flag_ic.png b/app/assets/images/emoji/flag_ic.png new file mode 100644 index 00000000000..69fd990aa95 Binary files /dev/null and b/app/assets/images/emoji/flag_ic.png differ diff --git a/app/assets/images/emoji/flag_id.png b/app/assets/images/emoji/flag_id.png new file mode 100644 index 00000000000..85b4c063a45 Binary files /dev/null and b/app/assets/images/emoji/flag_id.png differ diff --git a/app/assets/images/emoji/flag_ie.png b/app/assets/images/emoji/flag_ie.png new file mode 100644 index 00000000000..a28295838cc Binary files /dev/null and b/app/assets/images/emoji/flag_ie.png differ diff --git a/app/assets/images/emoji/flag_il.png b/app/assets/images/emoji/flag_il.png new file mode 100644 index 00000000000..85c410d45fb Binary files /dev/null and b/app/assets/images/emoji/flag_il.png differ diff --git a/app/assets/images/emoji/flag_im.png b/app/assets/images/emoji/flag_im.png new file mode 100644 index 00000000000..60a2458e38e Binary files /dev/null and b/app/assets/images/emoji/flag_im.png differ diff --git a/app/assets/images/emoji/flag_in.png b/app/assets/images/emoji/flag_in.png new file mode 100644 index 00000000000..feccc8952ce Binary files /dev/null and b/app/assets/images/emoji/flag_in.png differ diff --git a/app/assets/images/emoji/flag_io.png b/app/assets/images/emoji/flag_io.png new file mode 100644 index 00000000000..aae927d14b8 Binary files /dev/null and b/app/assets/images/emoji/flag_io.png differ diff --git a/app/assets/images/emoji/flag_iq.png b/app/assets/images/emoji/flag_iq.png new file mode 100644 index 00000000000..41fd1db6f86 Binary files /dev/null and b/app/assets/images/emoji/flag_iq.png differ diff --git a/app/assets/images/emoji/flag_ir.png b/app/assets/images/emoji/flag_ir.png new file mode 100644 index 00000000000..ff7aaf62ba6 Binary files /dev/null and b/app/assets/images/emoji/flag_ir.png differ diff --git a/app/assets/images/emoji/flag_is.png b/app/assets/images/emoji/flag_is.png new file mode 100644 index 00000000000..ad8d4131dd2 Binary files /dev/null and b/app/assets/images/emoji/flag_is.png differ diff --git a/app/assets/images/emoji/flag_it.png b/app/assets/images/emoji/flag_it.png new file mode 100644 index 00000000000..f21563ec533 Binary files /dev/null and b/app/assets/images/emoji/flag_it.png differ diff --git a/app/assets/images/emoji/flag_je.png b/app/assets/images/emoji/flag_je.png new file mode 100644 index 00000000000..198a918f6a4 Binary files /dev/null and b/app/assets/images/emoji/flag_je.png differ diff --git a/app/assets/images/emoji/flag_jm.png b/app/assets/images/emoji/flag_jm.png new file mode 100644 index 00000000000..f84e4f9e8db Binary files /dev/null and b/app/assets/images/emoji/flag_jm.png differ diff --git a/app/assets/images/emoji/flag_jo.png b/app/assets/images/emoji/flag_jo.png new file mode 100644 index 00000000000..20bfa147e3e Binary files /dev/null and b/app/assets/images/emoji/flag_jo.png differ diff --git a/app/assets/images/emoji/flag_jp.png b/app/assets/images/emoji/flag_jp.png new file mode 100644 index 00000000000..8d8838e4708 Binary files /dev/null and b/app/assets/images/emoji/flag_jp.png differ diff --git a/app/assets/images/emoji/flag_ke.png b/app/assets/images/emoji/flag_ke.png new file mode 100644 index 00000000000..9e417ab3009 Binary files /dev/null and b/app/assets/images/emoji/flag_ke.png differ diff --git a/app/assets/images/emoji/flag_kg.png b/app/assets/images/emoji/flag_kg.png new file mode 100644 index 00000000000..2f2d848fe58 Binary files /dev/null and b/app/assets/images/emoji/flag_kg.png differ diff --git a/app/assets/images/emoji/flag_kh.png b/app/assets/images/emoji/flag_kh.png new file mode 100644 index 00000000000..9a2877dd620 Binary files /dev/null and b/app/assets/images/emoji/flag_kh.png differ diff --git a/app/assets/images/emoji/flag_ki.png b/app/assets/images/emoji/flag_ki.png new file mode 100644 index 00000000000..10e507e3245 Binary files /dev/null and b/app/assets/images/emoji/flag_ki.png differ diff --git a/app/assets/images/emoji/flag_km.png b/app/assets/images/emoji/flag_km.png new file mode 100644 index 00000000000..bd5a0588e03 Binary files /dev/null and b/app/assets/images/emoji/flag_km.png differ diff --git a/app/assets/images/emoji/flag_kn.png b/app/assets/images/emoji/flag_kn.png new file mode 100644 index 00000000000..776207c9605 Binary files /dev/null and b/app/assets/images/emoji/flag_kn.png differ diff --git a/app/assets/images/emoji/flag_kp.png b/app/assets/images/emoji/flag_kp.png new file mode 100644 index 00000000000..6b3fd89eaaa Binary files /dev/null and b/app/assets/images/emoji/flag_kp.png differ diff --git a/app/assets/images/emoji/flag_kr.png b/app/assets/images/emoji/flag_kr.png new file mode 100644 index 00000000000..833a88116e1 Binary files /dev/null and b/app/assets/images/emoji/flag_kr.png differ diff --git a/app/assets/images/emoji/flag_kw.png b/app/assets/images/emoji/flag_kw.png new file mode 100644 index 00000000000..4d19bfa6ca7 Binary files /dev/null and b/app/assets/images/emoji/flag_kw.png differ diff --git a/app/assets/images/emoji/flag_ky.png b/app/assets/images/emoji/flag_ky.png new file mode 100644 index 00000000000..40daa4da597 Binary files /dev/null and b/app/assets/images/emoji/flag_ky.png differ diff --git a/app/assets/images/emoji/flag_kz.png b/app/assets/images/emoji/flag_kz.png new file mode 100644 index 00000000000..2f97a8fd3c6 Binary files /dev/null and b/app/assets/images/emoji/flag_kz.png differ diff --git a/app/assets/images/emoji/flag_la.png b/app/assets/images/emoji/flag_la.png new file mode 100644 index 00000000000..4d4179f34f6 Binary files /dev/null and b/app/assets/images/emoji/flag_la.png differ diff --git a/app/assets/images/emoji/flag_lb.png b/app/assets/images/emoji/flag_lb.png new file mode 100644 index 00000000000..3d594467011 Binary files /dev/null and b/app/assets/images/emoji/flag_lb.png differ diff --git a/app/assets/images/emoji/flag_lc.png b/app/assets/images/emoji/flag_lc.png new file mode 100644 index 00000000000..45547b1e439 Binary files /dev/null and b/app/assets/images/emoji/flag_lc.png differ diff --git a/app/assets/images/emoji/flag_li.png b/app/assets/images/emoji/flag_li.png new file mode 100644 index 00000000000..0eafa6a2215 Binary files /dev/null and b/app/assets/images/emoji/flag_li.png differ diff --git a/app/assets/images/emoji/flag_lk.png b/app/assets/images/emoji/flag_lk.png new file mode 100644 index 00000000000..ab4fe10c40c Binary files /dev/null and b/app/assets/images/emoji/flag_lk.png differ diff --git a/app/assets/images/emoji/flag_lr.png b/app/assets/images/emoji/flag_lr.png new file mode 100644 index 00000000000..f66f267fea2 Binary files /dev/null and b/app/assets/images/emoji/flag_lr.png differ diff --git a/app/assets/images/emoji/flag_ls.png b/app/assets/images/emoji/flag_ls.png new file mode 100644 index 00000000000..24745631e3c Binary files /dev/null and b/app/assets/images/emoji/flag_ls.png differ diff --git a/app/assets/images/emoji/flag_lt.png b/app/assets/images/emoji/flag_lt.png new file mode 100644 index 00000000000..d644b56d62a Binary files /dev/null and b/app/assets/images/emoji/flag_lt.png differ diff --git a/app/assets/images/emoji/flag_lu.png b/app/assets/images/emoji/flag_lu.png new file mode 100644 index 00000000000..a2df9c92994 Binary files /dev/null and b/app/assets/images/emoji/flag_lu.png differ diff --git a/app/assets/images/emoji/flag_lv.png b/app/assets/images/emoji/flag_lv.png new file mode 100644 index 00000000000..ae680d5f0e3 Binary files /dev/null and b/app/assets/images/emoji/flag_lv.png differ diff --git a/app/assets/images/emoji/flag_ly.png b/app/assets/images/emoji/flag_ly.png new file mode 100644 index 00000000000..f6e77b0f3ba Binary files /dev/null and b/app/assets/images/emoji/flag_ly.png differ diff --git a/app/assets/images/emoji/flag_ma.png b/app/assets/images/emoji/flag_ma.png new file mode 100644 index 00000000000..c4a056722cd Binary files /dev/null and b/app/assets/images/emoji/flag_ma.png differ diff --git a/app/assets/images/emoji/flag_mc.png b/app/assets/images/emoji/flag_mc.png new file mode 100644 index 00000000000..d479eab98cb Binary files /dev/null and b/app/assets/images/emoji/flag_mc.png differ diff --git a/app/assets/images/emoji/flag_md.png b/app/assets/images/emoji/flag_md.png new file mode 100644 index 00000000000..a7a72539872 Binary files /dev/null and b/app/assets/images/emoji/flag_md.png differ diff --git a/app/assets/images/emoji/flag_me.png b/app/assets/images/emoji/flag_me.png new file mode 100644 index 00000000000..7c771e7e120 Binary files /dev/null and b/app/assets/images/emoji/flag_me.png differ diff --git a/app/assets/images/emoji/flag_mf.png b/app/assets/images/emoji/flag_mf.png new file mode 100644 index 00000000000..70c761036bd Binary files /dev/null and b/app/assets/images/emoji/flag_mf.png differ diff --git a/app/assets/images/emoji/flag_mg.png b/app/assets/images/emoji/flag_mg.png new file mode 100644 index 00000000000..2f3ccdda76f Binary files /dev/null and b/app/assets/images/emoji/flag_mg.png differ diff --git a/app/assets/images/emoji/flag_mh.png b/app/assets/images/emoji/flag_mh.png new file mode 100644 index 00000000000..598016481c1 Binary files /dev/null and b/app/assets/images/emoji/flag_mh.png differ diff --git a/app/assets/images/emoji/flag_mk.png b/app/assets/images/emoji/flag_mk.png new file mode 100644 index 00000000000..7ba775ee75c Binary files /dev/null and b/app/assets/images/emoji/flag_mk.png differ diff --git a/app/assets/images/emoji/flag_ml.png b/app/assets/images/emoji/flag_ml.png new file mode 100644 index 00000000000..68343785468 Binary files /dev/null and b/app/assets/images/emoji/flag_ml.png differ diff --git a/app/assets/images/emoji/flag_mm.png b/app/assets/images/emoji/flag_mm.png new file mode 100644 index 00000000000..37dc7d71591 Binary files /dev/null and b/app/assets/images/emoji/flag_mm.png differ diff --git a/app/assets/images/emoji/flag_mn.png b/app/assets/images/emoji/flag_mn.png new file mode 100644 index 00000000000..1f146bbcd1a Binary files /dev/null and b/app/assets/images/emoji/flag_mn.png differ diff --git a/app/assets/images/emoji/flag_mo.png b/app/assets/images/emoji/flag_mo.png new file mode 100644 index 00000000000..7edde31f64b Binary files /dev/null and b/app/assets/images/emoji/flag_mo.png differ diff --git a/app/assets/images/emoji/flag_mp.png b/app/assets/images/emoji/flag_mp.png new file mode 100644 index 00000000000..17ec1c441ed Binary files /dev/null and b/app/assets/images/emoji/flag_mp.png differ diff --git a/app/assets/images/emoji/flag_mq.png b/app/assets/images/emoji/flag_mq.png new file mode 100644 index 00000000000..1e672dc9087 Binary files /dev/null and b/app/assets/images/emoji/flag_mq.png differ diff --git a/app/assets/images/emoji/flag_mr.png b/app/assets/images/emoji/flag_mr.png new file mode 100644 index 00000000000..f87de46effe Binary files /dev/null and b/app/assets/images/emoji/flag_mr.png differ diff --git a/app/assets/images/emoji/flag_ms.png b/app/assets/images/emoji/flag_ms.png new file mode 100644 index 00000000000..480b0d4ebda Binary files /dev/null and b/app/assets/images/emoji/flag_ms.png differ diff --git a/app/assets/images/emoji/flag_mt.png b/app/assets/images/emoji/flag_mt.png new file mode 100644 index 00000000000..c9e1dbdce82 Binary files /dev/null and b/app/assets/images/emoji/flag_mt.png differ diff --git a/app/assets/images/emoji/flag_mu.png b/app/assets/images/emoji/flag_mu.png new file mode 100644 index 00000000000..55b33cb7c33 Binary files /dev/null and b/app/assets/images/emoji/flag_mu.png differ diff --git a/app/assets/images/emoji/flag_mv.png b/app/assets/images/emoji/flag_mv.png new file mode 100644 index 00000000000..ce5867126ae Binary files /dev/null and b/app/assets/images/emoji/flag_mv.png differ diff --git a/app/assets/images/emoji/flag_mw.png b/app/assets/images/emoji/flag_mw.png new file mode 100644 index 00000000000..003d8548401 Binary files /dev/null and b/app/assets/images/emoji/flag_mw.png differ diff --git a/app/assets/images/emoji/flag_mx.png b/app/assets/images/emoji/flag_mx.png new file mode 100644 index 00000000000..42572bcd0ba Binary files /dev/null and b/app/assets/images/emoji/flag_mx.png differ diff --git a/app/assets/images/emoji/flag_my.png b/app/assets/images/emoji/flag_my.png new file mode 100644 index 00000000000..17526c26742 Binary files /dev/null and b/app/assets/images/emoji/flag_my.png differ diff --git a/app/assets/images/emoji/flag_mz.png b/app/assets/images/emoji/flag_mz.png new file mode 100644 index 00000000000..2352a78e786 Binary files /dev/null and b/app/assets/images/emoji/flag_mz.png differ diff --git a/app/assets/images/emoji/flag_na.png b/app/assets/images/emoji/flag_na.png new file mode 100644 index 00000000000..ed31c3df04d Binary files /dev/null and b/app/assets/images/emoji/flag_na.png differ diff --git a/app/assets/images/emoji/flag_nc.png b/app/assets/images/emoji/flag_nc.png new file mode 100644 index 00000000000..90b3afebfa3 Binary files /dev/null and b/app/assets/images/emoji/flag_nc.png differ diff --git a/app/assets/images/emoji/flag_ne.png b/app/assets/images/emoji/flag_ne.png new file mode 100644 index 00000000000..f98a1173c2a Binary files /dev/null and b/app/assets/images/emoji/flag_ne.png differ diff --git a/app/assets/images/emoji/flag_nf.png b/app/assets/images/emoji/flag_nf.png new file mode 100644 index 00000000000..9099e767420 Binary files /dev/null and b/app/assets/images/emoji/flag_nf.png differ diff --git a/app/assets/images/emoji/flag_ng.png b/app/assets/images/emoji/flag_ng.png new file mode 100644 index 00000000000..ea0abeff1a1 Binary files /dev/null and b/app/assets/images/emoji/flag_ng.png differ diff --git a/app/assets/images/emoji/flag_ni.png b/app/assets/images/emoji/flag_ni.png new file mode 100644 index 00000000000..772920dfa10 Binary files /dev/null and b/app/assets/images/emoji/flag_ni.png differ diff --git a/app/assets/images/emoji/flag_nl.png b/app/assets/images/emoji/flag_nl.png new file mode 100644 index 00000000000..83a0e817e41 Binary files /dev/null and b/app/assets/images/emoji/flag_nl.png differ diff --git a/app/assets/images/emoji/flag_no.png b/app/assets/images/emoji/flag_no.png new file mode 100644 index 00000000000..99d3142eb7b Binary files /dev/null and b/app/assets/images/emoji/flag_no.png differ diff --git a/app/assets/images/emoji/flag_np.png b/app/assets/images/emoji/flag_np.png new file mode 100644 index 00000000000..87425a8dfef Binary files /dev/null and b/app/assets/images/emoji/flag_np.png differ diff --git a/app/assets/images/emoji/flag_nr.png b/app/assets/images/emoji/flag_nr.png new file mode 100644 index 00000000000..b3e3a5d5621 Binary files /dev/null and b/app/assets/images/emoji/flag_nr.png differ diff --git a/app/assets/images/emoji/flag_nu.png b/app/assets/images/emoji/flag_nu.png new file mode 100644 index 00000000000..f03614443ee Binary files /dev/null and b/app/assets/images/emoji/flag_nu.png differ diff --git a/app/assets/images/emoji/flag_nz.png b/app/assets/images/emoji/flag_nz.png new file mode 100644 index 00000000000..a4eeeab9cd9 Binary files /dev/null and b/app/assets/images/emoji/flag_nz.png differ diff --git a/app/assets/images/emoji/flag_om.png b/app/assets/images/emoji/flag_om.png new file mode 100644 index 00000000000..ea824ba31e7 Binary files /dev/null and b/app/assets/images/emoji/flag_om.png differ diff --git a/app/assets/images/emoji/flag_pa.png b/app/assets/images/emoji/flag_pa.png new file mode 100644 index 00000000000..c3091d89889 Binary files /dev/null and b/app/assets/images/emoji/flag_pa.png differ diff --git a/app/assets/images/emoji/flag_pe.png b/app/assets/images/emoji/flag_pe.png new file mode 100644 index 00000000000..39223aa9dbb Binary files /dev/null and b/app/assets/images/emoji/flag_pe.png differ diff --git a/app/assets/images/emoji/flag_pf.png b/app/assets/images/emoji/flag_pf.png new file mode 100644 index 00000000000..113445f8f6e Binary files /dev/null and b/app/assets/images/emoji/flag_pf.png differ diff --git a/app/assets/images/emoji/flag_pg.png b/app/assets/images/emoji/flag_pg.png new file mode 100644 index 00000000000..825e9dcb762 Binary files /dev/null and b/app/assets/images/emoji/flag_pg.png differ diff --git a/app/assets/images/emoji/flag_ph.png b/app/assets/images/emoji/flag_ph.png new file mode 100644 index 00000000000..8260e15bd2c Binary files /dev/null and b/app/assets/images/emoji/flag_ph.png differ diff --git a/app/assets/images/emoji/flag_pk.png b/app/assets/images/emoji/flag_pk.png new file mode 100644 index 00000000000..a7b6a1c5074 Binary files /dev/null and b/app/assets/images/emoji/flag_pk.png differ diff --git a/app/assets/images/emoji/flag_pl.png b/app/assets/images/emoji/flag_pl.png new file mode 100644 index 00000000000..19de2edec11 Binary files /dev/null and b/app/assets/images/emoji/flag_pl.png differ diff --git a/app/assets/images/emoji/flag_pm.png b/app/assets/images/emoji/flag_pm.png new file mode 100644 index 00000000000..2ca60554193 Binary files /dev/null and b/app/assets/images/emoji/flag_pm.png differ diff --git a/app/assets/images/emoji/flag_pn.png b/app/assets/images/emoji/flag_pn.png new file mode 100644 index 00000000000..f2263b154bc Binary files /dev/null and b/app/assets/images/emoji/flag_pn.png differ diff --git a/app/assets/images/emoji/flag_pr.png b/app/assets/images/emoji/flag_pr.png new file mode 100644 index 00000000000..d0209cddb79 Binary files /dev/null and b/app/assets/images/emoji/flag_pr.png differ diff --git a/app/assets/images/emoji/flag_ps.png b/app/assets/images/emoji/flag_ps.png new file mode 100644 index 00000000000..7ccab09778b Binary files /dev/null and b/app/assets/images/emoji/flag_ps.png differ diff --git a/app/assets/images/emoji/flag_pt.png b/app/assets/images/emoji/flag_pt.png new file mode 100644 index 00000000000..cc93f27c64b Binary files /dev/null and b/app/assets/images/emoji/flag_pt.png differ diff --git a/app/assets/images/emoji/flag_pw.png b/app/assets/images/emoji/flag_pw.png new file mode 100644 index 00000000000..154b2f12d3c Binary files /dev/null and b/app/assets/images/emoji/flag_pw.png differ diff --git a/app/assets/images/emoji/flag_py.png b/app/assets/images/emoji/flag_py.png new file mode 100644 index 00000000000..662ad2f6ff1 Binary files /dev/null and b/app/assets/images/emoji/flag_py.png differ diff --git a/app/assets/images/emoji/flag_qa.png b/app/assets/images/emoji/flag_qa.png new file mode 100644 index 00000000000..a01d8b05cc7 Binary files /dev/null and b/app/assets/images/emoji/flag_qa.png differ diff --git a/app/assets/images/emoji/flag_re.png b/app/assets/images/emoji/flag_re.png new file mode 100644 index 00000000000..57f2bbe9df8 Binary files /dev/null and b/app/assets/images/emoji/flag_re.png differ diff --git a/app/assets/images/emoji/flag_ro.png b/app/assets/images/emoji/flag_ro.png new file mode 100644 index 00000000000..3e48c447706 Binary files /dev/null and b/app/assets/images/emoji/flag_ro.png differ diff --git a/app/assets/images/emoji/flag_rs.png b/app/assets/images/emoji/flag_rs.png new file mode 100644 index 00000000000..9df6c9a5235 Binary files /dev/null and b/app/assets/images/emoji/flag_rs.png differ diff --git a/app/assets/images/emoji/flag_ru.png b/app/assets/images/emoji/flag_ru.png new file mode 100644 index 00000000000..e50c9db90e7 Binary files /dev/null and b/app/assets/images/emoji/flag_ru.png differ diff --git a/app/assets/images/emoji/flag_rw.png b/app/assets/images/emoji/flag_rw.png new file mode 100644 index 00000000000..c238c874e1d Binary files /dev/null and b/app/assets/images/emoji/flag_rw.png differ diff --git a/app/assets/images/emoji/flag_sa.png b/app/assets/images/emoji/flag_sa.png new file mode 100644 index 00000000000..4941be7d198 Binary files /dev/null and b/app/assets/images/emoji/flag_sa.png differ diff --git a/app/assets/images/emoji/flag_sb.png b/app/assets/images/emoji/flag_sb.png new file mode 100644 index 00000000000..7d8f1ac6130 Binary files /dev/null and b/app/assets/images/emoji/flag_sb.png differ diff --git a/app/assets/images/emoji/flag_sc.png b/app/assets/images/emoji/flag_sc.png new file mode 100644 index 00000000000..6ae4d90765e Binary files /dev/null and b/app/assets/images/emoji/flag_sc.png differ diff --git a/app/assets/images/emoji/flag_sd.png b/app/assets/images/emoji/flag_sd.png new file mode 100644 index 00000000000..963be1b36fb Binary files /dev/null and b/app/assets/images/emoji/flag_sd.png differ diff --git a/app/assets/images/emoji/flag_se.png b/app/assets/images/emoji/flag_se.png new file mode 100644 index 00000000000..fc0d0e0ce89 Binary files /dev/null and b/app/assets/images/emoji/flag_se.png differ diff --git a/app/assets/images/emoji/flag_sg.png b/app/assets/images/emoji/flag_sg.png new file mode 100644 index 00000000000..de3c7737c42 Binary files /dev/null and b/app/assets/images/emoji/flag_sg.png differ diff --git a/app/assets/images/emoji/flag_sh.png b/app/assets/images/emoji/flag_sh.png new file mode 100644 index 00000000000..40cd9e44e96 Binary files /dev/null and b/app/assets/images/emoji/flag_sh.png differ diff --git a/app/assets/images/emoji/flag_si.png b/app/assets/images/emoji/flag_si.png new file mode 100644 index 00000000000..e308999dba2 Binary files /dev/null and b/app/assets/images/emoji/flag_si.png differ diff --git a/app/assets/images/emoji/flag_sj.png b/app/assets/images/emoji/flag_sj.png new file mode 100644 index 00000000000..5884e648228 Binary files /dev/null and b/app/assets/images/emoji/flag_sj.png differ diff --git a/app/assets/images/emoji/flag_sk.png b/app/assets/images/emoji/flag_sk.png new file mode 100644 index 00000000000..4259d0e1418 Binary files /dev/null and b/app/assets/images/emoji/flag_sk.png differ diff --git a/app/assets/images/emoji/flag_sl.png b/app/assets/images/emoji/flag_sl.png new file mode 100644 index 00000000000..d2cc68830ab Binary files /dev/null and b/app/assets/images/emoji/flag_sl.png differ diff --git a/app/assets/images/emoji/flag_sm.png b/app/assets/images/emoji/flag_sm.png new file mode 100644 index 00000000000..03b8708754e Binary files /dev/null and b/app/assets/images/emoji/flag_sm.png differ diff --git a/app/assets/images/emoji/flag_sn.png b/app/assets/images/emoji/flag_sn.png new file mode 100644 index 00000000000..5368bbe93df Binary files /dev/null and b/app/assets/images/emoji/flag_sn.png differ diff --git a/app/assets/images/emoji/flag_so.png b/app/assets/images/emoji/flag_so.png new file mode 100644 index 00000000000..68a0597365a Binary files /dev/null and b/app/assets/images/emoji/flag_so.png differ diff --git a/app/assets/images/emoji/flag_sr.png b/app/assets/images/emoji/flag_sr.png new file mode 100644 index 00000000000..d3251327035 Binary files /dev/null and b/app/assets/images/emoji/flag_sr.png differ diff --git a/app/assets/images/emoji/flag_ss.png b/app/assets/images/emoji/flag_ss.png new file mode 100644 index 00000000000..122977e798f Binary files /dev/null and b/app/assets/images/emoji/flag_ss.png differ diff --git a/app/assets/images/emoji/flag_st.png b/app/assets/images/emoji/flag_st.png new file mode 100644 index 00000000000..f83a863d612 Binary files /dev/null and b/app/assets/images/emoji/flag_st.png differ diff --git a/app/assets/images/emoji/flag_sv.png b/app/assets/images/emoji/flag_sv.png new file mode 100644 index 00000000000..efb83e2f253 Binary files /dev/null and b/app/assets/images/emoji/flag_sv.png differ diff --git a/app/assets/images/emoji/flag_sx.png b/app/assets/images/emoji/flag_sx.png new file mode 100644 index 00000000000..94b760fbedf Binary files /dev/null and b/app/assets/images/emoji/flag_sx.png differ diff --git a/app/assets/images/emoji/flag_sy.png b/app/assets/images/emoji/flag_sy.png new file mode 100644 index 00000000000..09a8ee8f78c Binary files /dev/null and b/app/assets/images/emoji/flag_sy.png differ diff --git a/app/assets/images/emoji/flag_sz.png b/app/assets/images/emoji/flag_sz.png new file mode 100644 index 00000000000..f74e82ea1fd Binary files /dev/null and b/app/assets/images/emoji/flag_sz.png differ diff --git a/app/assets/images/emoji/flag_ta.png b/app/assets/images/emoji/flag_ta.png new file mode 100644 index 00000000000..b44283e90e2 Binary files /dev/null and b/app/assets/images/emoji/flag_ta.png differ diff --git a/app/assets/images/emoji/flag_tc.png b/app/assets/images/emoji/flag_tc.png new file mode 100644 index 00000000000..156b33d1ba6 Binary files /dev/null and b/app/assets/images/emoji/flag_tc.png differ diff --git a/app/assets/images/emoji/flag_td.png b/app/assets/images/emoji/flag_td.png new file mode 100644 index 00000000000..ebe7f592828 Binary files /dev/null and b/app/assets/images/emoji/flag_td.png differ diff --git a/app/assets/images/emoji/flag_tf.png b/app/assets/images/emoji/flag_tf.png new file mode 100644 index 00000000000..a1a3ad68ee2 Binary files /dev/null and b/app/assets/images/emoji/flag_tf.png differ diff --git a/app/assets/images/emoji/flag_tg.png b/app/assets/images/emoji/flag_tg.png new file mode 100644 index 00000000000..826b73c9ac5 Binary files /dev/null and b/app/assets/images/emoji/flag_tg.png differ diff --git a/app/assets/images/emoji/flag_th.png b/app/assets/images/emoji/flag_th.png new file mode 100644 index 00000000000..93ff542c5a6 Binary files /dev/null and b/app/assets/images/emoji/flag_th.png differ diff --git a/app/assets/images/emoji/flag_tj.png b/app/assets/images/emoji/flag_tj.png new file mode 100644 index 00000000000..7a8a0b6190a Binary files /dev/null and b/app/assets/images/emoji/flag_tj.png differ diff --git a/app/assets/images/emoji/flag_tk.png b/app/assets/images/emoji/flag_tk.png new file mode 100644 index 00000000000..2fa5a21b1bb Binary files /dev/null and b/app/assets/images/emoji/flag_tk.png differ diff --git a/app/assets/images/emoji/flag_tl.png b/app/assets/images/emoji/flag_tl.png new file mode 100644 index 00000000000..5b120eccc6f Binary files /dev/null and b/app/assets/images/emoji/flag_tl.png differ diff --git a/app/assets/images/emoji/flag_tm.png b/app/assets/images/emoji/flag_tm.png new file mode 100644 index 00000000000..c3c4f532302 Binary files /dev/null and b/app/assets/images/emoji/flag_tm.png differ diff --git a/app/assets/images/emoji/flag_tn.png b/app/assets/images/emoji/flag_tn.png new file mode 100644 index 00000000000..58ef161229f Binary files /dev/null and b/app/assets/images/emoji/flag_tn.png differ diff --git a/app/assets/images/emoji/flag_to.png b/app/assets/images/emoji/flag_to.png new file mode 100644 index 00000000000..1ffa7bb9d19 Binary files /dev/null and b/app/assets/images/emoji/flag_to.png differ diff --git a/app/assets/images/emoji/flag_tr.png b/app/assets/images/emoji/flag_tr.png new file mode 100644 index 00000000000..325251fae88 Binary files /dev/null and b/app/assets/images/emoji/flag_tr.png differ diff --git a/app/assets/images/emoji/flag_tt.png b/app/assets/images/emoji/flag_tt.png new file mode 100644 index 00000000000..ed3bb39a300 Binary files /dev/null and b/app/assets/images/emoji/flag_tt.png differ diff --git a/app/assets/images/emoji/flag_tv.png b/app/assets/images/emoji/flag_tv.png new file mode 100644 index 00000000000..e82c65c7bb9 Binary files /dev/null and b/app/assets/images/emoji/flag_tv.png differ diff --git a/app/assets/images/emoji/flag_tw.png b/app/assets/images/emoji/flag_tw.png new file mode 100644 index 00000000000..3a8f00b5928 Binary files /dev/null and b/app/assets/images/emoji/flag_tw.png differ diff --git a/app/assets/images/emoji/flag_tz.png b/app/assets/images/emoji/flag_tz.png new file mode 100644 index 00000000000..2a020853d4e Binary files /dev/null and b/app/assets/images/emoji/flag_tz.png differ diff --git a/app/assets/images/emoji/flag_ua.png b/app/assets/images/emoji/flag_ua.png new file mode 100644 index 00000000000..cd84d1bbd36 Binary files /dev/null and b/app/assets/images/emoji/flag_ua.png differ diff --git a/app/assets/images/emoji/flag_ug.png b/app/assets/images/emoji/flag_ug.png new file mode 100644 index 00000000000..dc97690eb55 Binary files /dev/null and b/app/assets/images/emoji/flag_ug.png differ diff --git a/app/assets/images/emoji/flag_um.png b/app/assets/images/emoji/flag_um.png new file mode 100644 index 00000000000..4a7ee3cdf13 Binary files /dev/null and b/app/assets/images/emoji/flag_um.png differ diff --git a/app/assets/images/emoji/flag_us.png b/app/assets/images/emoji/flag_us.png new file mode 100644 index 00000000000..9f730305860 Binary files /dev/null and b/app/assets/images/emoji/flag_us.png differ diff --git a/app/assets/images/emoji/flag_uy.png b/app/assets/images/emoji/flag_uy.png new file mode 100644 index 00000000000..b8002a697a6 Binary files /dev/null and b/app/assets/images/emoji/flag_uy.png differ diff --git a/app/assets/images/emoji/flag_uz.png b/app/assets/images/emoji/flag_uz.png new file mode 100644 index 00000000000..d56ca9bc424 Binary files /dev/null and b/app/assets/images/emoji/flag_uz.png differ diff --git a/app/assets/images/emoji/flag_va.png b/app/assets/images/emoji/flag_va.png new file mode 100644 index 00000000000..ddaf5e3141b Binary files /dev/null and b/app/assets/images/emoji/flag_va.png differ diff --git a/app/assets/images/emoji/flag_vc.png b/app/assets/images/emoji/flag_vc.png new file mode 100644 index 00000000000..43703c62a71 Binary files /dev/null and b/app/assets/images/emoji/flag_vc.png differ diff --git a/app/assets/images/emoji/flag_ve.png b/app/assets/images/emoji/flag_ve.png new file mode 100644 index 00000000000..1b62796824e Binary files /dev/null and b/app/assets/images/emoji/flag_ve.png differ diff --git a/app/assets/images/emoji/flag_vg.png b/app/assets/images/emoji/flag_vg.png new file mode 100644 index 00000000000..536f780f1c0 Binary files /dev/null and b/app/assets/images/emoji/flag_vg.png differ diff --git a/app/assets/images/emoji/flag_vi.png b/app/assets/images/emoji/flag_vi.png new file mode 100644 index 00000000000..64102012cfe Binary files /dev/null and b/app/assets/images/emoji/flag_vi.png differ diff --git a/app/assets/images/emoji/flag_vn.png b/app/assets/images/emoji/flag_vn.png new file mode 100644 index 00000000000..427036046b6 Binary files /dev/null and b/app/assets/images/emoji/flag_vn.png differ diff --git a/app/assets/images/emoji/flag_vu.png b/app/assets/images/emoji/flag_vu.png new file mode 100644 index 00000000000..706eba44070 Binary files /dev/null and b/app/assets/images/emoji/flag_vu.png differ diff --git a/app/assets/images/emoji/flag_wf.png b/app/assets/images/emoji/flag_wf.png new file mode 100644 index 00000000000..70c761036bd Binary files /dev/null and b/app/assets/images/emoji/flag_wf.png differ diff --git a/app/assets/images/emoji/flag_white.png b/app/assets/images/emoji/flag_white.png new file mode 100644 index 00000000000..86d6e96d5e9 Binary files /dev/null and b/app/assets/images/emoji/flag_white.png differ diff --git a/app/assets/images/emoji/flag_ws.png b/app/assets/images/emoji/flag_ws.png new file mode 100644 index 00000000000..a1ea0703141 Binary files /dev/null and b/app/assets/images/emoji/flag_ws.png differ diff --git a/app/assets/images/emoji/flag_xk.png b/app/assets/images/emoji/flag_xk.png new file mode 100644 index 00000000000..e587a446632 Binary files /dev/null and b/app/assets/images/emoji/flag_xk.png differ diff --git a/app/assets/images/emoji/flag_ye.png b/app/assets/images/emoji/flag_ye.png new file mode 100644 index 00000000000..eadfebd5f67 Binary files /dev/null and b/app/assets/images/emoji/flag_ye.png differ diff --git a/app/assets/images/emoji/flag_yt.png b/app/assets/images/emoji/flag_yt.png new file mode 100644 index 00000000000..c81fa6d886e Binary files /dev/null and b/app/assets/images/emoji/flag_yt.png differ diff --git a/app/assets/images/emoji/flag_za.png b/app/assets/images/emoji/flag_za.png new file mode 100644 index 00000000000..f397ef5072f Binary files /dev/null and b/app/assets/images/emoji/flag_za.png differ diff --git a/app/assets/images/emoji/flag_zm.png b/app/assets/images/emoji/flag_zm.png new file mode 100644 index 00000000000..2494a31f662 Binary files /dev/null and b/app/assets/images/emoji/flag_zm.png differ diff --git a/app/assets/images/emoji/flag_zw.png b/app/assets/images/emoji/flag_zw.png new file mode 100644 index 00000000000..e09b9652be6 Binary files /dev/null and b/app/assets/images/emoji/flag_zw.png differ diff --git a/app/assets/images/emoji/flags.png b/app/assets/images/emoji/flags.png new file mode 100644 index 00000000000..3b451035a3a Binary files /dev/null and b/app/assets/images/emoji/flags.png differ diff --git a/app/assets/images/emoji/flashlight.png b/app/assets/images/emoji/flashlight.png new file mode 100644 index 00000000000..eee36c25067 Binary files /dev/null and b/app/assets/images/emoji/flashlight.png differ diff --git a/app/assets/images/emoji/fleur-de-lis.png b/app/assets/images/emoji/fleur-de-lis.png new file mode 100644 index 00000000000..c9250d27fa7 Binary files /dev/null and b/app/assets/images/emoji/fleur-de-lis.png differ diff --git a/app/assets/images/emoji/floppy_disk.png b/app/assets/images/emoji/floppy_disk.png new file mode 100644 index 00000000000..072a76d3c13 Binary files /dev/null and b/app/assets/images/emoji/floppy_disk.png differ diff --git a/app/assets/images/emoji/flower_playing_cards.png b/app/assets/images/emoji/flower_playing_cards.png new file mode 100644 index 00000000000..6766b044d95 Binary files /dev/null and b/app/assets/images/emoji/flower_playing_cards.png differ diff --git a/app/assets/images/emoji/flushed.png b/app/assets/images/emoji/flushed.png new file mode 100644 index 00000000000..829220bc470 Binary files /dev/null and b/app/assets/images/emoji/flushed.png differ diff --git a/app/assets/images/emoji/fog.png b/app/assets/images/emoji/fog.png new file mode 100644 index 00000000000..4e73c2de272 Binary files /dev/null and b/app/assets/images/emoji/fog.png differ diff --git a/app/assets/images/emoji/foggy.png b/app/assets/images/emoji/foggy.png new file mode 100644 index 00000000000..57702d8d3ac Binary files /dev/null and b/app/assets/images/emoji/foggy.png differ diff --git a/app/assets/images/emoji/football.png b/app/assets/images/emoji/football.png new file mode 100644 index 00000000000..10366f41fce Binary files /dev/null and b/app/assets/images/emoji/football.png differ diff --git a/app/assets/images/emoji/footprints.png b/app/assets/images/emoji/footprints.png new file mode 100644 index 00000000000..b2673c5a1a8 Binary files /dev/null and b/app/assets/images/emoji/footprints.png differ diff --git a/app/assets/images/emoji/fork_and_knife.png b/app/assets/images/emoji/fork_and_knife.png new file mode 100644 index 00000000000..09f1feaea1c Binary files /dev/null and b/app/assets/images/emoji/fork_and_knife.png differ diff --git a/app/assets/images/emoji/fork_knife_plate.png b/app/assets/images/emoji/fork_knife_plate.png new file mode 100644 index 00000000000..7411755f708 Binary files /dev/null and b/app/assets/images/emoji/fork_knife_plate.png differ diff --git a/app/assets/images/emoji/fountain.png b/app/assets/images/emoji/fountain.png new file mode 100644 index 00000000000..293f5d91c0f Binary files /dev/null and b/app/assets/images/emoji/fountain.png differ diff --git a/app/assets/images/emoji/four.png b/app/assets/images/emoji/four.png new file mode 100644 index 00000000000..b0e914aac45 Binary files /dev/null and b/app/assets/images/emoji/four.png differ diff --git a/app/assets/images/emoji/four_leaf_clover.png b/app/assets/images/emoji/four_leaf_clover.png new file mode 100644 index 00000000000..fdedfcc2b4e Binary files /dev/null and b/app/assets/images/emoji/four_leaf_clover.png differ diff --git a/app/assets/images/emoji/fox.png b/app/assets/images/emoji/fox.png new file mode 100644 index 00000000000..1ab339bf054 Binary files /dev/null and b/app/assets/images/emoji/fox.png differ diff --git a/app/assets/images/emoji/frame_photo.png b/app/assets/images/emoji/frame_photo.png new file mode 100644 index 00000000000..9fe84607bfd Binary files /dev/null and b/app/assets/images/emoji/frame_photo.png differ diff --git a/app/assets/images/emoji/free.png b/app/assets/images/emoji/free.png new file mode 100644 index 00000000000..b71956eb48a Binary files /dev/null and b/app/assets/images/emoji/free.png differ diff --git a/app/assets/images/emoji/french_bread.png b/app/assets/images/emoji/french_bread.png new file mode 100644 index 00000000000..4c2c5639822 Binary files /dev/null and b/app/assets/images/emoji/french_bread.png differ diff --git a/app/assets/images/emoji/fried_shrimp.png b/app/assets/images/emoji/fried_shrimp.png new file mode 100644 index 00000000000..752ba7f1398 Binary files /dev/null and b/app/assets/images/emoji/fried_shrimp.png differ diff --git a/app/assets/images/emoji/fries.png b/app/assets/images/emoji/fries.png new file mode 100644 index 00000000000..4e2a4caacef Binary files /dev/null and b/app/assets/images/emoji/fries.png differ diff --git a/app/assets/images/emoji/frog.png b/app/assets/images/emoji/frog.png new file mode 100644 index 00000000000..8825d1ad577 Binary files /dev/null and b/app/assets/images/emoji/frog.png differ diff --git a/app/assets/images/emoji/frowning.png b/app/assets/images/emoji/frowning.png new file mode 100644 index 00000000000..43ab6b0a1c1 Binary files /dev/null and b/app/assets/images/emoji/frowning.png differ diff --git a/app/assets/images/emoji/frowning2.png b/app/assets/images/emoji/frowning2.png new file mode 100644 index 00000000000..6ae71f233b9 Binary files /dev/null and b/app/assets/images/emoji/frowning2.png differ diff --git a/app/assets/images/emoji/fuelpump.png b/app/assets/images/emoji/fuelpump.png new file mode 100644 index 00000000000..05b18794474 Binary files /dev/null and b/app/assets/images/emoji/fuelpump.png differ diff --git a/app/assets/images/emoji/full_moon.png b/app/assets/images/emoji/full_moon.png new file mode 100644 index 00000000000..c9a2d6aa7c9 Binary files /dev/null and b/app/assets/images/emoji/full_moon.png differ diff --git a/app/assets/images/emoji/full_moon_with_face.png b/app/assets/images/emoji/full_moon_with_face.png new file mode 100644 index 00000000000..a5c25bbaf64 Binary files /dev/null and b/app/assets/images/emoji/full_moon_with_face.png differ diff --git a/app/assets/images/emoji/game_die.png b/app/assets/images/emoji/game_die.png new file mode 100644 index 00000000000..ad3626fe5e5 Binary files /dev/null and b/app/assets/images/emoji/game_die.png differ diff --git a/app/assets/images/emoji/gear.png b/app/assets/images/emoji/gear.png new file mode 100644 index 00000000000..2a1cc2c0ff4 Binary files /dev/null and b/app/assets/images/emoji/gear.png differ diff --git a/app/assets/images/emoji/gem.png b/app/assets/images/emoji/gem.png new file mode 100644 index 00000000000..db122d26a19 Binary files /dev/null and b/app/assets/images/emoji/gem.png differ diff --git a/app/assets/images/emoji/gemini.png b/app/assets/images/emoji/gemini.png new file mode 100644 index 00000000000..1a09698cf00 Binary files /dev/null and b/app/assets/images/emoji/gemini.png differ diff --git a/app/assets/images/emoji/ghost.png b/app/assets/images/emoji/ghost.png new file mode 100644 index 00000000000..5650bc0ed18 Binary files /dev/null and b/app/assets/images/emoji/ghost.png differ diff --git a/app/assets/images/emoji/gift.png b/app/assets/images/emoji/gift.png new file mode 100644 index 00000000000..844e2164560 Binary files /dev/null and b/app/assets/images/emoji/gift.png differ diff --git a/app/assets/images/emoji/gift_heart.png b/app/assets/images/emoji/gift_heart.png new file mode 100644 index 00000000000..902ceafe4d1 Binary files /dev/null and b/app/assets/images/emoji/gift_heart.png differ diff --git a/app/assets/images/emoji/girl.png b/app/assets/images/emoji/girl.png new file mode 100644 index 00000000000..dc1d4d08b39 Binary files /dev/null and b/app/assets/images/emoji/girl.png differ diff --git a/app/assets/images/emoji/girl_tone1.png b/app/assets/images/emoji/girl_tone1.png new file mode 100644 index 00000000000..bb667e88651 Binary files /dev/null and b/app/assets/images/emoji/girl_tone1.png differ diff --git a/app/assets/images/emoji/girl_tone2.png b/app/assets/images/emoji/girl_tone2.png new file mode 100644 index 00000000000..a59ed4a3f0d Binary files /dev/null and b/app/assets/images/emoji/girl_tone2.png differ diff --git a/app/assets/images/emoji/girl_tone3.png b/app/assets/images/emoji/girl_tone3.png new file mode 100644 index 00000000000..517e7f2a7b0 Binary files /dev/null and b/app/assets/images/emoji/girl_tone3.png differ diff --git a/app/assets/images/emoji/girl_tone4.png b/app/assets/images/emoji/girl_tone4.png new file mode 100644 index 00000000000..542d96c8487 Binary files /dev/null and b/app/assets/images/emoji/girl_tone4.png differ diff --git a/app/assets/images/emoji/girl_tone5.png b/app/assets/images/emoji/girl_tone5.png new file mode 100644 index 00000000000..66b7c28c2df Binary files /dev/null and b/app/assets/images/emoji/girl_tone5.png differ diff --git a/app/assets/images/emoji/globe_with_meridians.png b/app/assets/images/emoji/globe_with_meridians.png new file mode 100644 index 00000000000..82450c1a4ba Binary files /dev/null and b/app/assets/images/emoji/globe_with_meridians.png differ diff --git a/app/assets/images/emoji/goal.png b/app/assets/images/emoji/goal.png new file mode 100644 index 00000000000..df3a53da0fb Binary files /dev/null and b/app/assets/images/emoji/goal.png differ diff --git a/app/assets/images/emoji/goat.png b/app/assets/images/emoji/goat.png new file mode 100644 index 00000000000..f9d9e38a128 Binary files /dev/null and b/app/assets/images/emoji/goat.png differ diff --git a/app/assets/images/emoji/golf.png b/app/assets/images/emoji/golf.png new file mode 100644 index 00000000000..f65a21d8a46 Binary files /dev/null and b/app/assets/images/emoji/golf.png differ diff --git a/app/assets/images/emoji/golfer.png b/app/assets/images/emoji/golfer.png new file mode 100644 index 00000000000..39c552de86d Binary files /dev/null and b/app/assets/images/emoji/golfer.png differ diff --git a/app/assets/images/emoji/gorilla.png b/app/assets/images/emoji/gorilla.png new file mode 100644 index 00000000000..acc51e13622 Binary files /dev/null and b/app/assets/images/emoji/gorilla.png differ diff --git a/app/assets/images/emoji/grapes.png b/app/assets/images/emoji/grapes.png new file mode 100644 index 00000000000..30d22218896 Binary files /dev/null and b/app/assets/images/emoji/grapes.png differ diff --git a/app/assets/images/emoji/green_apple.png b/app/assets/images/emoji/green_apple.png new file mode 100644 index 00000000000..5fd51bd3915 Binary files /dev/null and b/app/assets/images/emoji/green_apple.png differ diff --git a/app/assets/images/emoji/green_book.png b/app/assets/images/emoji/green_book.png new file mode 100644 index 00000000000..e5e411cf3b5 Binary files /dev/null and b/app/assets/images/emoji/green_book.png differ diff --git a/app/assets/images/emoji/green_heart.png b/app/assets/images/emoji/green_heart.png new file mode 100644 index 00000000000..c52d60a58be Binary files /dev/null and b/app/assets/images/emoji/green_heart.png differ diff --git a/app/assets/images/emoji/grey_exclamation.png b/app/assets/images/emoji/grey_exclamation.png new file mode 100644 index 00000000000..9b64da8bf7f Binary files /dev/null and b/app/assets/images/emoji/grey_exclamation.png differ diff --git a/app/assets/images/emoji/grey_question.png b/app/assets/images/emoji/grey_question.png new file mode 100644 index 00000000000..6e7824c75f6 Binary files /dev/null and b/app/assets/images/emoji/grey_question.png differ diff --git a/app/assets/images/emoji/grimacing.png b/app/assets/images/emoji/grimacing.png new file mode 100644 index 00000000000..871b2f071c9 Binary files /dev/null and b/app/assets/images/emoji/grimacing.png differ diff --git a/app/assets/images/emoji/grin.png b/app/assets/images/emoji/grin.png new file mode 100644 index 00000000000..418d94c811b Binary files /dev/null and b/app/assets/images/emoji/grin.png differ diff --git a/app/assets/images/emoji/grinning.png b/app/assets/images/emoji/grinning.png new file mode 100644 index 00000000000..3e8e0dab78c Binary files /dev/null and b/app/assets/images/emoji/grinning.png differ diff --git a/app/assets/images/emoji/guardsman.png b/app/assets/images/emoji/guardsman.png new file mode 100644 index 00000000000..8d7ab3c473c Binary files /dev/null and b/app/assets/images/emoji/guardsman.png differ diff --git a/app/assets/images/emoji/guardsman_tone1.png b/app/assets/images/emoji/guardsman_tone1.png new file mode 100644 index 00000000000..cea9ba27468 Binary files /dev/null and b/app/assets/images/emoji/guardsman_tone1.png differ diff --git a/app/assets/images/emoji/guardsman_tone2.png b/app/assets/images/emoji/guardsman_tone2.png new file mode 100644 index 00000000000..037464e4028 Binary files /dev/null and b/app/assets/images/emoji/guardsman_tone2.png differ diff --git a/app/assets/images/emoji/guardsman_tone3.png b/app/assets/images/emoji/guardsman_tone3.png new file mode 100644 index 00000000000..0f6726fbe87 Binary files /dev/null and b/app/assets/images/emoji/guardsman_tone3.png differ diff --git a/app/assets/images/emoji/guardsman_tone4.png b/app/assets/images/emoji/guardsman_tone4.png new file mode 100644 index 00000000000..85fcf9a3b97 Binary files /dev/null and b/app/assets/images/emoji/guardsman_tone4.png differ diff --git a/app/assets/images/emoji/guardsman_tone5.png b/app/assets/images/emoji/guardsman_tone5.png new file mode 100644 index 00000000000..e5f9ca7d5a2 Binary files /dev/null and b/app/assets/images/emoji/guardsman_tone5.png differ diff --git a/app/assets/images/emoji/guitar.png b/app/assets/images/emoji/guitar.png new file mode 100644 index 00000000000..43d752f1e3d Binary files /dev/null and b/app/assets/images/emoji/guitar.png differ diff --git a/app/assets/images/emoji/gun.png b/app/assets/images/emoji/gun.png new file mode 100644 index 00000000000..89c5c244c7b Binary files /dev/null and b/app/assets/images/emoji/gun.png differ diff --git a/app/assets/images/emoji/haircut.png b/app/assets/images/emoji/haircut.png new file mode 100644 index 00000000000..91266b12930 Binary files /dev/null and b/app/assets/images/emoji/haircut.png differ diff --git a/app/assets/images/emoji/haircut_tone1.png b/app/assets/images/emoji/haircut_tone1.png new file mode 100644 index 00000000000..c743b74abeb Binary files /dev/null and b/app/assets/images/emoji/haircut_tone1.png differ diff --git a/app/assets/images/emoji/haircut_tone2.png b/app/assets/images/emoji/haircut_tone2.png new file mode 100644 index 00000000000..f144f8e55ce Binary files /dev/null and b/app/assets/images/emoji/haircut_tone2.png differ diff --git a/app/assets/images/emoji/haircut_tone3.png b/app/assets/images/emoji/haircut_tone3.png new file mode 100644 index 00000000000..d5ad19563ac Binary files /dev/null and b/app/assets/images/emoji/haircut_tone3.png differ diff --git a/app/assets/images/emoji/haircut_tone4.png b/app/assets/images/emoji/haircut_tone4.png new file mode 100644 index 00000000000..244fd3af008 Binary files /dev/null and b/app/assets/images/emoji/haircut_tone4.png differ diff --git a/app/assets/images/emoji/haircut_tone5.png b/app/assets/images/emoji/haircut_tone5.png new file mode 100644 index 00000000000..20a94a88623 Binary files /dev/null and b/app/assets/images/emoji/haircut_tone5.png differ diff --git a/app/assets/images/emoji/hamburger.png b/app/assets/images/emoji/hamburger.png new file mode 100644 index 00000000000..3573b28a1fd Binary files /dev/null and b/app/assets/images/emoji/hamburger.png differ diff --git a/app/assets/images/emoji/hammer.png b/app/assets/images/emoji/hammer.png new file mode 100644 index 00000000000..00736cce47d Binary files /dev/null and b/app/assets/images/emoji/hammer.png differ diff --git a/app/assets/images/emoji/hammer_pick.png b/app/assets/images/emoji/hammer_pick.png new file mode 100644 index 00000000000..3bee30ec588 Binary files /dev/null and b/app/assets/images/emoji/hammer_pick.png differ diff --git a/app/assets/images/emoji/hamster.png b/app/assets/images/emoji/hamster.png new file mode 100644 index 00000000000..9a04388e4e7 Binary files /dev/null and b/app/assets/images/emoji/hamster.png differ diff --git a/app/assets/images/emoji/hand_splayed.png b/app/assets/images/emoji/hand_splayed.png new file mode 100644 index 00000000000..fb5ae8ebb5a Binary files /dev/null and b/app/assets/images/emoji/hand_splayed.png differ diff --git a/app/assets/images/emoji/hand_splayed_tone1.png b/app/assets/images/emoji/hand_splayed_tone1.png new file mode 100644 index 00000000000..a7888e6bd23 Binary files /dev/null and b/app/assets/images/emoji/hand_splayed_tone1.png differ diff --git a/app/assets/images/emoji/hand_splayed_tone2.png b/app/assets/images/emoji/hand_splayed_tone2.png new file mode 100644 index 00000000000..cc10fbc272d Binary files /dev/null and b/app/assets/images/emoji/hand_splayed_tone2.png differ diff --git a/app/assets/images/emoji/hand_splayed_tone3.png b/app/assets/images/emoji/hand_splayed_tone3.png new file mode 100644 index 00000000000..707236ae8a4 Binary files /dev/null and b/app/assets/images/emoji/hand_splayed_tone3.png differ diff --git a/app/assets/images/emoji/hand_splayed_tone4.png b/app/assets/images/emoji/hand_splayed_tone4.png new file mode 100644 index 00000000000..1430df9c61f Binary files /dev/null and b/app/assets/images/emoji/hand_splayed_tone4.png differ diff --git a/app/assets/images/emoji/hand_splayed_tone5.png b/app/assets/images/emoji/hand_splayed_tone5.png new file mode 100644 index 00000000000..80bec971b6b Binary files /dev/null and b/app/assets/images/emoji/hand_splayed_tone5.png differ diff --git a/app/assets/images/emoji/handbag.png b/app/assets/images/emoji/handbag.png new file mode 100644 index 00000000000..cbf75c5d25e Binary files /dev/null and b/app/assets/images/emoji/handbag.png differ diff --git a/app/assets/images/emoji/handball.png b/app/assets/images/emoji/handball.png new file mode 100644 index 00000000000..1152f1344c7 Binary files /dev/null and b/app/assets/images/emoji/handball.png differ diff --git a/app/assets/images/emoji/handball_tone1.png b/app/assets/images/emoji/handball_tone1.png new file mode 100644 index 00000000000..c26cac2df98 Binary files /dev/null and b/app/assets/images/emoji/handball_tone1.png differ diff --git a/app/assets/images/emoji/handball_tone2.png b/app/assets/images/emoji/handball_tone2.png new file mode 100644 index 00000000000..7baaf95a9a2 Binary files /dev/null and b/app/assets/images/emoji/handball_tone2.png differ diff --git a/app/assets/images/emoji/handball_tone3.png b/app/assets/images/emoji/handball_tone3.png new file mode 100644 index 00000000000..0e3a37c3d40 Binary files /dev/null and b/app/assets/images/emoji/handball_tone3.png differ diff --git a/app/assets/images/emoji/handball_tone4.png b/app/assets/images/emoji/handball_tone4.png new file mode 100644 index 00000000000..e1233f38266 Binary files /dev/null and b/app/assets/images/emoji/handball_tone4.png differ diff --git a/app/assets/images/emoji/handball_tone5.png b/app/assets/images/emoji/handball_tone5.png new file mode 100644 index 00000000000..6b1eb9b64b0 Binary files /dev/null and b/app/assets/images/emoji/handball_tone5.png differ diff --git a/app/assets/images/emoji/handshake.png b/app/assets/images/emoji/handshake.png new file mode 100644 index 00000000000..c5d35fd8138 Binary files /dev/null and b/app/assets/images/emoji/handshake.png differ diff --git a/app/assets/images/emoji/handshake_tone1.png b/app/assets/images/emoji/handshake_tone1.png new file mode 100644 index 00000000000..8f8fbb9bdca Binary files /dev/null and b/app/assets/images/emoji/handshake_tone1.png differ diff --git a/app/assets/images/emoji/handshake_tone2.png b/app/assets/images/emoji/handshake_tone2.png new file mode 100644 index 00000000000..336a77a6d78 Binary files /dev/null and b/app/assets/images/emoji/handshake_tone2.png differ diff --git a/app/assets/images/emoji/handshake_tone3.png b/app/assets/images/emoji/handshake_tone3.png new file mode 100644 index 00000000000..95f62d4fecd Binary files /dev/null and b/app/assets/images/emoji/handshake_tone3.png differ diff --git a/app/assets/images/emoji/handshake_tone4.png b/app/assets/images/emoji/handshake_tone4.png new file mode 100644 index 00000000000..2b0a6433886 Binary files /dev/null and b/app/assets/images/emoji/handshake_tone4.png differ diff --git a/app/assets/images/emoji/handshake_tone5.png b/app/assets/images/emoji/handshake_tone5.png new file mode 100644 index 00000000000..40189ee68e4 Binary files /dev/null and b/app/assets/images/emoji/handshake_tone5.png differ diff --git a/app/assets/images/emoji/hash.png b/app/assets/images/emoji/hash.png new file mode 100644 index 00000000000..6e26f0070b0 Binary files /dev/null and b/app/assets/images/emoji/hash.png differ diff --git a/app/assets/images/emoji/hatched_chick.png b/app/assets/images/emoji/hatched_chick.png new file mode 100644 index 00000000000..31dfb511e0e Binary files /dev/null and b/app/assets/images/emoji/hatched_chick.png differ diff --git a/app/assets/images/emoji/hatching_chick.png b/app/assets/images/emoji/hatching_chick.png new file mode 100644 index 00000000000..c5b0e8f3bcc Binary files /dev/null and b/app/assets/images/emoji/hatching_chick.png differ diff --git a/app/assets/images/emoji/head_bandage.png b/app/assets/images/emoji/head_bandage.png new file mode 100644 index 00000000000..0be723085e0 Binary files /dev/null and b/app/assets/images/emoji/head_bandage.png differ diff --git a/app/assets/images/emoji/headphones.png b/app/assets/images/emoji/headphones.png new file mode 100644 index 00000000000..e9fd34041d8 Binary files /dev/null and b/app/assets/images/emoji/headphones.png differ diff --git a/app/assets/images/emoji/hear_no_evil.png b/app/assets/images/emoji/hear_no_evil.png new file mode 100644 index 00000000000..74b6be0c6c5 Binary files /dev/null and b/app/assets/images/emoji/hear_no_evil.png differ diff --git a/app/assets/images/emoji/heart.png b/app/assets/images/emoji/heart.png new file mode 100644 index 00000000000..638cb72dc4e Binary files /dev/null and b/app/assets/images/emoji/heart.png differ diff --git a/app/assets/images/emoji/heart_decoration.png b/app/assets/images/emoji/heart_decoration.png new file mode 100644 index 00000000000..5443f60bc63 Binary files /dev/null and b/app/assets/images/emoji/heart_decoration.png differ diff --git a/app/assets/images/emoji/heart_exclamation.png b/app/assets/images/emoji/heart_exclamation.png new file mode 100644 index 00000000000..91b520be40b Binary files /dev/null and b/app/assets/images/emoji/heart_exclamation.png differ diff --git a/app/assets/images/emoji/heart_eyes.png b/app/assets/images/emoji/heart_eyes.png new file mode 100644 index 00000000000..73fbee29d4e Binary files /dev/null and b/app/assets/images/emoji/heart_eyes.png differ diff --git a/app/assets/images/emoji/heart_eyes_cat.png b/app/assets/images/emoji/heart_eyes_cat.png new file mode 100644 index 00000000000..bc5a833f9a1 Binary files /dev/null and b/app/assets/images/emoji/heart_eyes_cat.png differ diff --git a/app/assets/images/emoji/heartbeat.png b/app/assets/images/emoji/heartbeat.png new file mode 100644 index 00000000000..0bcf2d1d567 Binary files /dev/null and b/app/assets/images/emoji/heartbeat.png differ diff --git a/app/assets/images/emoji/heartpulse.png b/app/assets/images/emoji/heartpulse.png new file mode 100644 index 00000000000..d6e694e972f Binary files /dev/null and b/app/assets/images/emoji/heartpulse.png differ diff --git a/app/assets/images/emoji/hearts.png b/app/assets/images/emoji/hearts.png new file mode 100644 index 00000000000..393c3ed5267 Binary files /dev/null and b/app/assets/images/emoji/hearts.png differ diff --git a/app/assets/images/emoji/heavy_check_mark.png b/app/assets/images/emoji/heavy_check_mark.png new file mode 100644 index 00000000000..03bd695377e Binary files /dev/null and b/app/assets/images/emoji/heavy_check_mark.png differ diff --git a/app/assets/images/emoji/heavy_division_sign.png b/app/assets/images/emoji/heavy_division_sign.png new file mode 100644 index 00000000000..df32ab21bea Binary files /dev/null and b/app/assets/images/emoji/heavy_division_sign.png differ diff --git a/app/assets/images/emoji/heavy_dollar_sign.png b/app/assets/images/emoji/heavy_dollar_sign.png new file mode 100644 index 00000000000..ef2c2e20590 Binary files /dev/null and b/app/assets/images/emoji/heavy_dollar_sign.png differ diff --git a/app/assets/images/emoji/heavy_minus_sign.png b/app/assets/images/emoji/heavy_minus_sign.png new file mode 100644 index 00000000000..054211caf12 Binary files /dev/null and b/app/assets/images/emoji/heavy_minus_sign.png differ diff --git a/app/assets/images/emoji/heavy_multiplication_x.png b/app/assets/images/emoji/heavy_multiplication_x.png new file mode 100644 index 00000000000..e47cc1b685d Binary files /dev/null and b/app/assets/images/emoji/heavy_multiplication_x.png differ diff --git a/app/assets/images/emoji/heavy_plus_sign.png b/app/assets/images/emoji/heavy_plus_sign.png new file mode 100644 index 00000000000..40799798aaf Binary files /dev/null and b/app/assets/images/emoji/heavy_plus_sign.png differ diff --git a/app/assets/images/emoji/helicopter.png b/app/assets/images/emoji/helicopter.png new file mode 100644 index 00000000000..7ec5f39a51a Binary files /dev/null and b/app/assets/images/emoji/helicopter.png differ diff --git a/app/assets/images/emoji/helmet_with_cross.png b/app/assets/images/emoji/helmet_with_cross.png new file mode 100644 index 00000000000..7140a676038 Binary files /dev/null and b/app/assets/images/emoji/helmet_with_cross.png differ diff --git a/app/assets/images/emoji/herb.png b/app/assets/images/emoji/herb.png new file mode 100644 index 00000000000..d984d1562bb Binary files /dev/null and b/app/assets/images/emoji/herb.png differ diff --git a/app/assets/images/emoji/hibiscus.png b/app/assets/images/emoji/hibiscus.png new file mode 100644 index 00000000000..39dd3524233 Binary files /dev/null and b/app/assets/images/emoji/hibiscus.png differ diff --git a/app/assets/images/emoji/high_brightness.png b/app/assets/images/emoji/high_brightness.png new file mode 100644 index 00000000000..c41f2d5fd50 Binary files /dev/null and b/app/assets/images/emoji/high_brightness.png differ diff --git a/app/assets/images/emoji/high_heel.png b/app/assets/images/emoji/high_heel.png new file mode 100644 index 00000000000..b331cbccc9d Binary files /dev/null and b/app/assets/images/emoji/high_heel.png differ diff --git a/app/assets/images/emoji/hockey.png b/app/assets/images/emoji/hockey.png new file mode 100644 index 00000000000..be94e9cbf73 Binary files /dev/null and b/app/assets/images/emoji/hockey.png differ diff --git a/app/assets/images/emoji/hole.png b/app/assets/images/emoji/hole.png new file mode 100644 index 00000000000..517d2ae0deb Binary files /dev/null and b/app/assets/images/emoji/hole.png differ diff --git a/app/assets/images/emoji/homes.png b/app/assets/images/emoji/homes.png new file mode 100644 index 00000000000..6ab4a2a2651 Binary files /dev/null and b/app/assets/images/emoji/homes.png differ diff --git a/app/assets/images/emoji/honey_pot.png b/app/assets/images/emoji/honey_pot.png new file mode 100644 index 00000000000..9d8f592955e Binary files /dev/null and b/app/assets/images/emoji/honey_pot.png differ diff --git a/app/assets/images/emoji/horse.png b/app/assets/images/emoji/horse.png new file mode 100644 index 00000000000..7cb1172f4e4 Binary files /dev/null and b/app/assets/images/emoji/horse.png differ diff --git a/app/assets/images/emoji/horse_racing.png b/app/assets/images/emoji/horse_racing.png new file mode 100644 index 00000000000..addf9edac56 Binary files /dev/null and b/app/assets/images/emoji/horse_racing.png differ diff --git a/app/assets/images/emoji/horse_racing_tone1.png b/app/assets/images/emoji/horse_racing_tone1.png new file mode 100644 index 00000000000..e9bf4092e98 Binary files /dev/null and b/app/assets/images/emoji/horse_racing_tone1.png differ diff --git a/app/assets/images/emoji/horse_racing_tone2.png b/app/assets/images/emoji/horse_racing_tone2.png new file mode 100644 index 00000000000..031bbc3d867 Binary files /dev/null and b/app/assets/images/emoji/horse_racing_tone2.png differ diff --git a/app/assets/images/emoji/horse_racing_tone3.png b/app/assets/images/emoji/horse_racing_tone3.png new file mode 100644 index 00000000000..b40ef891f9b Binary files /dev/null and b/app/assets/images/emoji/horse_racing_tone3.png differ diff --git a/app/assets/images/emoji/horse_racing_tone4.png b/app/assets/images/emoji/horse_racing_tone4.png new file mode 100644 index 00000000000..e286cb85065 Binary files /dev/null and b/app/assets/images/emoji/horse_racing_tone4.png differ diff --git a/app/assets/images/emoji/horse_racing_tone5.png b/app/assets/images/emoji/horse_racing_tone5.png new file mode 100644 index 00000000000..453c51c6007 Binary files /dev/null and b/app/assets/images/emoji/horse_racing_tone5.png differ diff --git a/app/assets/images/emoji/hospital.png b/app/assets/images/emoji/hospital.png new file mode 100644 index 00000000000..1cbce4ae767 Binary files /dev/null and b/app/assets/images/emoji/hospital.png differ diff --git a/app/assets/images/emoji/hot_pepper.png b/app/assets/images/emoji/hot_pepper.png new file mode 100644 index 00000000000..266675bd577 Binary files /dev/null and b/app/assets/images/emoji/hot_pepper.png differ diff --git a/app/assets/images/emoji/hotdog.png b/app/assets/images/emoji/hotdog.png new file mode 100644 index 00000000000..3c3354d94cb Binary files /dev/null and b/app/assets/images/emoji/hotdog.png differ diff --git a/app/assets/images/emoji/hotel.png b/app/assets/images/emoji/hotel.png new file mode 100644 index 00000000000..ea8f4c4979a Binary files /dev/null and b/app/assets/images/emoji/hotel.png differ diff --git a/app/assets/images/emoji/hotsprings.png b/app/assets/images/emoji/hotsprings.png new file mode 100644 index 00000000000..3d9df2d9475 Binary files /dev/null and b/app/assets/images/emoji/hotsprings.png differ diff --git a/app/assets/images/emoji/hourglass.png b/app/assets/images/emoji/hourglass.png new file mode 100644 index 00000000000..a5db2d1d3f4 Binary files /dev/null and b/app/assets/images/emoji/hourglass.png differ diff --git a/app/assets/images/emoji/hourglass_flowing_sand.png b/app/assets/images/emoji/hourglass_flowing_sand.png new file mode 100644 index 00000000000..b93b15ed6d8 Binary files /dev/null and b/app/assets/images/emoji/hourglass_flowing_sand.png differ diff --git a/app/assets/images/emoji/house.png b/app/assets/images/emoji/house.png new file mode 100644 index 00000000000..01c98a0ba92 Binary files /dev/null and b/app/assets/images/emoji/house.png differ diff --git a/app/assets/images/emoji/house_abandoned.png b/app/assets/images/emoji/house_abandoned.png new file mode 100644 index 00000000000..c55e81de990 Binary files /dev/null and b/app/assets/images/emoji/house_abandoned.png differ diff --git a/app/assets/images/emoji/house_with_garden.png b/app/assets/images/emoji/house_with_garden.png new file mode 100644 index 00000000000..0aae41598ef Binary files /dev/null and b/app/assets/images/emoji/house_with_garden.png differ diff --git a/app/assets/images/emoji/hugging.png b/app/assets/images/emoji/hugging.png new file mode 100644 index 00000000000..5bba6dc6d51 Binary files /dev/null and b/app/assets/images/emoji/hugging.png differ diff --git a/app/assets/images/emoji/hushed.png b/app/assets/images/emoji/hushed.png new file mode 100644 index 00000000000..cad0e23132e Binary files /dev/null and b/app/assets/images/emoji/hushed.png differ diff --git a/app/assets/images/emoji/ice_cream.png b/app/assets/images/emoji/ice_cream.png new file mode 100644 index 00000000000..94267b9c434 Binary files /dev/null and b/app/assets/images/emoji/ice_cream.png differ diff --git a/app/assets/images/emoji/ice_skate.png b/app/assets/images/emoji/ice_skate.png new file mode 100644 index 00000000000..8c449b0c039 Binary files /dev/null and b/app/assets/images/emoji/ice_skate.png differ diff --git a/app/assets/images/emoji/icecream.png b/app/assets/images/emoji/icecream.png new file mode 100644 index 00000000000..8f6546e31a5 Binary files /dev/null and b/app/assets/images/emoji/icecream.png differ diff --git a/app/assets/images/emoji/id.png b/app/assets/images/emoji/id.png new file mode 100644 index 00000000000..5bf69bf7ba8 Binary files /dev/null and b/app/assets/images/emoji/id.png differ diff --git a/app/assets/images/emoji/ideograph_advantage.png b/app/assets/images/emoji/ideograph_advantage.png new file mode 100644 index 00000000000..0c0d589caf0 Binary files /dev/null and b/app/assets/images/emoji/ideograph_advantage.png differ diff --git a/app/assets/images/emoji/imp.png b/app/assets/images/emoji/imp.png new file mode 100644 index 00000000000..9f9a9605539 Binary files /dev/null and b/app/assets/images/emoji/imp.png differ diff --git a/app/assets/images/emoji/inbox_tray.png b/app/assets/images/emoji/inbox_tray.png new file mode 100644 index 00000000000..41a6be2b0ee Binary files /dev/null and b/app/assets/images/emoji/inbox_tray.png differ diff --git a/app/assets/images/emoji/incoming_envelope.png b/app/assets/images/emoji/incoming_envelope.png new file mode 100644 index 00000000000..fd22e88182e Binary files /dev/null and b/app/assets/images/emoji/incoming_envelope.png differ diff --git a/app/assets/images/emoji/information_desk_person.png b/app/assets/images/emoji/information_desk_person.png new file mode 100644 index 00000000000..55fc6294d25 Binary files /dev/null and b/app/assets/images/emoji/information_desk_person.png differ diff --git a/app/assets/images/emoji/information_desk_person_tone1.png b/app/assets/images/emoji/information_desk_person_tone1.png new file mode 100644 index 00000000000..3d9e2247940 Binary files /dev/null and b/app/assets/images/emoji/information_desk_person_tone1.png differ diff --git a/app/assets/images/emoji/information_desk_person_tone2.png b/app/assets/images/emoji/information_desk_person_tone2.png new file mode 100644 index 00000000000..879e8b7966d Binary files /dev/null and b/app/assets/images/emoji/information_desk_person_tone2.png differ diff --git a/app/assets/images/emoji/information_desk_person_tone3.png b/app/assets/images/emoji/information_desk_person_tone3.png new file mode 100644 index 00000000000..307514eab67 Binary files /dev/null and b/app/assets/images/emoji/information_desk_person_tone3.png differ diff --git a/app/assets/images/emoji/information_desk_person_tone4.png b/app/assets/images/emoji/information_desk_person_tone4.png new file mode 100644 index 00000000000..297395dcb3f Binary files /dev/null and b/app/assets/images/emoji/information_desk_person_tone4.png differ diff --git a/app/assets/images/emoji/information_desk_person_tone5.png b/app/assets/images/emoji/information_desk_person_tone5.png new file mode 100644 index 00000000000..26f8f22b28b Binary files /dev/null and b/app/assets/images/emoji/information_desk_person_tone5.png differ diff --git a/app/assets/images/emoji/information_source.png b/app/assets/images/emoji/information_source.png new file mode 100644 index 00000000000..871f2db9314 Binary files /dev/null and b/app/assets/images/emoji/information_source.png differ diff --git a/app/assets/images/emoji/innocent.png b/app/assets/images/emoji/innocent.png new file mode 100644 index 00000000000..57f5151124f Binary files /dev/null and b/app/assets/images/emoji/innocent.png differ diff --git a/app/assets/images/emoji/interrobang.png b/app/assets/images/emoji/interrobang.png new file mode 100644 index 00000000000..509813e9bb2 Binary files /dev/null and b/app/assets/images/emoji/interrobang.png differ diff --git a/app/assets/images/emoji/iphone.png b/app/assets/images/emoji/iphone.png new file mode 100644 index 00000000000..fd377acf872 Binary files /dev/null and b/app/assets/images/emoji/iphone.png differ diff --git a/app/assets/images/emoji/island.png b/app/assets/images/emoji/island.png new file mode 100644 index 00000000000..7fd834389b7 Binary files /dev/null and b/app/assets/images/emoji/island.png differ diff --git a/app/assets/images/emoji/izakaya_lantern.png b/app/assets/images/emoji/izakaya_lantern.png new file mode 100644 index 00000000000..dfd933f6f36 Binary files /dev/null and b/app/assets/images/emoji/izakaya_lantern.png differ diff --git a/app/assets/images/emoji/jack_o_lantern.png b/app/assets/images/emoji/jack_o_lantern.png new file mode 100644 index 00000000000..44c3fc0aec9 Binary files /dev/null and b/app/assets/images/emoji/jack_o_lantern.png differ diff --git a/app/assets/images/emoji/japan.png b/app/assets/images/emoji/japan.png new file mode 100644 index 00000000000..d86d0a59e12 Binary files /dev/null and b/app/assets/images/emoji/japan.png differ diff --git a/app/assets/images/emoji/japanese_castle.png b/app/assets/images/emoji/japanese_castle.png new file mode 100644 index 00000000000..64b4e33a1ae Binary files /dev/null and b/app/assets/images/emoji/japanese_castle.png differ diff --git a/app/assets/images/emoji/japanese_goblin.png b/app/assets/images/emoji/japanese_goblin.png new file mode 100644 index 00000000000..515c6a2250e Binary files /dev/null and b/app/assets/images/emoji/japanese_goblin.png differ diff --git a/app/assets/images/emoji/japanese_ogre.png b/app/assets/images/emoji/japanese_ogre.png new file mode 100644 index 00000000000..fe8670fdaf1 Binary files /dev/null and b/app/assets/images/emoji/japanese_ogre.png differ diff --git a/app/assets/images/emoji/jeans.png b/app/assets/images/emoji/jeans.png new file mode 100644 index 00000000000..2a6869d674c Binary files /dev/null and b/app/assets/images/emoji/jeans.png differ diff --git a/app/assets/images/emoji/joy.png b/app/assets/images/emoji/joy.png new file mode 100644 index 00000000000..0ba3b1859d8 Binary files /dev/null and b/app/assets/images/emoji/joy.png differ diff --git a/app/assets/images/emoji/joy_cat.png b/app/assets/images/emoji/joy_cat.png new file mode 100644 index 00000000000..aac353179aa Binary files /dev/null and b/app/assets/images/emoji/joy_cat.png differ diff --git a/app/assets/images/emoji/joystick.png b/app/assets/images/emoji/joystick.png new file mode 100644 index 00000000000..1ee1905434e Binary files /dev/null and b/app/assets/images/emoji/joystick.png differ diff --git a/app/assets/images/emoji/juggling.png b/app/assets/images/emoji/juggling.png new file mode 100644 index 00000000000..a37f6224a42 Binary files /dev/null and b/app/assets/images/emoji/juggling.png differ diff --git a/app/assets/images/emoji/juggling_tone1.png b/app/assets/images/emoji/juggling_tone1.png new file mode 100644 index 00000000000..c18eda40031 Binary files /dev/null and b/app/assets/images/emoji/juggling_tone1.png differ diff --git a/app/assets/images/emoji/juggling_tone2.png b/app/assets/images/emoji/juggling_tone2.png new file mode 100644 index 00000000000..de3b7a555b6 Binary files /dev/null and b/app/assets/images/emoji/juggling_tone2.png differ diff --git a/app/assets/images/emoji/juggling_tone3.png b/app/assets/images/emoji/juggling_tone3.png new file mode 100644 index 00000000000..74ab6d85458 Binary files /dev/null and b/app/assets/images/emoji/juggling_tone3.png differ diff --git a/app/assets/images/emoji/juggling_tone4.png b/app/assets/images/emoji/juggling_tone4.png new file mode 100644 index 00000000000..1c57823203f Binary files /dev/null and b/app/assets/images/emoji/juggling_tone4.png differ diff --git a/app/assets/images/emoji/juggling_tone5.png b/app/assets/images/emoji/juggling_tone5.png new file mode 100644 index 00000000000..c343d6ee98a Binary files /dev/null and b/app/assets/images/emoji/juggling_tone5.png differ diff --git a/app/assets/images/emoji/kaaba.png b/app/assets/images/emoji/kaaba.png new file mode 100644 index 00000000000..1778c1138e4 Binary files /dev/null and b/app/assets/images/emoji/kaaba.png differ diff --git a/app/assets/images/emoji/key.png b/app/assets/images/emoji/key.png new file mode 100644 index 00000000000..319cd1b884c Binary files /dev/null and b/app/assets/images/emoji/key.png differ diff --git a/app/assets/images/emoji/key2.png b/app/assets/images/emoji/key2.png new file mode 100644 index 00000000000..e11d706c6c8 Binary files /dev/null and b/app/assets/images/emoji/key2.png differ diff --git a/app/assets/images/emoji/keyboard.png b/app/assets/images/emoji/keyboard.png new file mode 100644 index 00000000000..75027cb9af7 Binary files /dev/null and b/app/assets/images/emoji/keyboard.png differ diff --git a/app/assets/images/emoji/kimono.png b/app/assets/images/emoji/kimono.png new file mode 100644 index 00000000000..abe851115d1 Binary files /dev/null and b/app/assets/images/emoji/kimono.png differ diff --git a/app/assets/images/emoji/kiss.png b/app/assets/images/emoji/kiss.png new file mode 100644 index 00000000000..85e6dcfc4e8 Binary files /dev/null and b/app/assets/images/emoji/kiss.png differ diff --git a/app/assets/images/emoji/kiss_mm.png b/app/assets/images/emoji/kiss_mm.png new file mode 100644 index 00000000000..a9a0edae17c Binary files /dev/null and b/app/assets/images/emoji/kiss_mm.png differ diff --git a/app/assets/images/emoji/kiss_ww.png b/app/assets/images/emoji/kiss_ww.png new file mode 100644 index 00000000000..fdac73cbb1d Binary files /dev/null and b/app/assets/images/emoji/kiss_ww.png differ diff --git a/app/assets/images/emoji/kissing.png b/app/assets/images/emoji/kissing.png new file mode 100644 index 00000000000..39d325fd8e3 Binary files /dev/null and b/app/assets/images/emoji/kissing.png differ diff --git a/app/assets/images/emoji/kissing_cat.png b/app/assets/images/emoji/kissing_cat.png new file mode 100644 index 00000000000..6e0bcc77540 Binary files /dev/null and b/app/assets/images/emoji/kissing_cat.png differ diff --git a/app/assets/images/emoji/kissing_closed_eyes.png b/app/assets/images/emoji/kissing_closed_eyes.png new file mode 100644 index 00000000000..b684d7d4d6c Binary files /dev/null and b/app/assets/images/emoji/kissing_closed_eyes.png differ diff --git a/app/assets/images/emoji/kissing_heart.png b/app/assets/images/emoji/kissing_heart.png new file mode 100644 index 00000000000..0ff808fd614 Binary files /dev/null and b/app/assets/images/emoji/kissing_heart.png differ diff --git a/app/assets/images/emoji/kissing_smiling_eyes.png b/app/assets/images/emoji/kissing_smiling_eyes.png new file mode 100644 index 00000000000..e181f17099d Binary files /dev/null and b/app/assets/images/emoji/kissing_smiling_eyes.png differ diff --git a/app/assets/images/emoji/kiwi.png b/app/assets/images/emoji/kiwi.png new file mode 100644 index 00000000000..dfbd8258074 Binary files /dev/null and b/app/assets/images/emoji/kiwi.png differ diff --git a/app/assets/images/emoji/knife.png b/app/assets/images/emoji/knife.png new file mode 100644 index 00000000000..1acb9f3077b Binary files /dev/null and b/app/assets/images/emoji/knife.png differ diff --git a/app/assets/images/emoji/koala.png b/app/assets/images/emoji/koala.png new file mode 100644 index 00000000000..a0aa437a98c Binary files /dev/null and b/app/assets/images/emoji/koala.png differ diff --git a/app/assets/images/emoji/koko.png b/app/assets/images/emoji/koko.png new file mode 100644 index 00000000000..6450eb44d90 Binary files /dev/null and b/app/assets/images/emoji/koko.png differ diff --git a/app/assets/images/emoji/label.png b/app/assets/images/emoji/label.png new file mode 100644 index 00000000000..d41c9b4f1e1 Binary files /dev/null and b/app/assets/images/emoji/label.png differ diff --git a/app/assets/images/emoji/large_blue_circle.png b/app/assets/images/emoji/large_blue_circle.png new file mode 100644 index 00000000000..84078ef3127 Binary files /dev/null and b/app/assets/images/emoji/large_blue_circle.png differ diff --git a/app/assets/images/emoji/large_blue_diamond.png b/app/assets/images/emoji/large_blue_diamond.png new file mode 100644 index 00000000000..416a58bd5a8 Binary files /dev/null and b/app/assets/images/emoji/large_blue_diamond.png differ diff --git a/app/assets/images/emoji/large_orange_diamond.png b/app/assets/images/emoji/large_orange_diamond.png new file mode 100644 index 00000000000..73ff0ac36c8 Binary files /dev/null and b/app/assets/images/emoji/large_orange_diamond.png differ diff --git a/app/assets/images/emoji/last_quarter_moon.png b/app/assets/images/emoji/last_quarter_moon.png new file mode 100644 index 00000000000..0842a0dd408 Binary files /dev/null and b/app/assets/images/emoji/last_quarter_moon.png differ diff --git a/app/assets/images/emoji/last_quarter_moon_with_face.png b/app/assets/images/emoji/last_quarter_moon_with_face.png new file mode 100644 index 00000000000..94099343c5d Binary files /dev/null and b/app/assets/images/emoji/last_quarter_moon_with_face.png differ diff --git a/app/assets/images/emoji/laughing.png b/app/assets/images/emoji/laughing.png new file mode 100644 index 00000000000..d94e9505ba1 Binary files /dev/null and b/app/assets/images/emoji/laughing.png differ diff --git a/app/assets/images/emoji/leaves.png b/app/assets/images/emoji/leaves.png new file mode 100644 index 00000000000..1e43e1af820 Binary files /dev/null and b/app/assets/images/emoji/leaves.png differ diff --git a/app/assets/images/emoji/ledger.png b/app/assets/images/emoji/ledger.png new file mode 100644 index 00000000000..13e7561a4bd Binary files /dev/null and b/app/assets/images/emoji/ledger.png differ diff --git a/app/assets/images/emoji/left_facing_fist.png b/app/assets/images/emoji/left_facing_fist.png new file mode 100644 index 00000000000..a9d9fd8d59c Binary files /dev/null and b/app/assets/images/emoji/left_facing_fist.png differ diff --git a/app/assets/images/emoji/left_facing_fist_tone1.png b/app/assets/images/emoji/left_facing_fist_tone1.png new file mode 100644 index 00000000000..1262a6b4b69 Binary files /dev/null and b/app/assets/images/emoji/left_facing_fist_tone1.png differ diff --git a/app/assets/images/emoji/left_facing_fist_tone2.png b/app/assets/images/emoji/left_facing_fist_tone2.png new file mode 100644 index 00000000000..40bf70b82b2 Binary files /dev/null and b/app/assets/images/emoji/left_facing_fist_tone2.png differ diff --git a/app/assets/images/emoji/left_facing_fist_tone3.png b/app/assets/images/emoji/left_facing_fist_tone3.png new file mode 100644 index 00000000000..93f58145111 Binary files /dev/null and b/app/assets/images/emoji/left_facing_fist_tone3.png differ diff --git a/app/assets/images/emoji/left_facing_fist_tone4.png b/app/assets/images/emoji/left_facing_fist_tone4.png new file mode 100644 index 00000000000..d82b5ec91f0 Binary files /dev/null and b/app/assets/images/emoji/left_facing_fist_tone4.png differ diff --git a/app/assets/images/emoji/left_facing_fist_tone5.png b/app/assets/images/emoji/left_facing_fist_tone5.png new file mode 100644 index 00000000000..09ae4cd492b Binary files /dev/null and b/app/assets/images/emoji/left_facing_fist_tone5.png differ diff --git a/app/assets/images/emoji/left_luggage.png b/app/assets/images/emoji/left_luggage.png new file mode 100644 index 00000000000..887b23f3f25 Binary files /dev/null and b/app/assets/images/emoji/left_luggage.png differ diff --git a/app/assets/images/emoji/left_right_arrow.png b/app/assets/images/emoji/left_right_arrow.png new file mode 100644 index 00000000000..7937f24f2ac Binary files /dev/null and b/app/assets/images/emoji/left_right_arrow.png differ diff --git a/app/assets/images/emoji/leftwards_arrow_with_hook.png b/app/assets/images/emoji/leftwards_arrow_with_hook.png new file mode 100644 index 00000000000..ba45c2ad9e9 Binary files /dev/null and b/app/assets/images/emoji/leftwards_arrow_with_hook.png differ diff --git a/app/assets/images/emoji/lemon.png b/app/assets/images/emoji/lemon.png new file mode 100644 index 00000000000..9a7d95ca220 Binary files /dev/null and b/app/assets/images/emoji/lemon.png differ diff --git a/app/assets/images/emoji/leo.png b/app/assets/images/emoji/leo.png new file mode 100644 index 00000000000..30158d34de9 Binary files /dev/null and b/app/assets/images/emoji/leo.png differ diff --git a/app/assets/images/emoji/leopard.png b/app/assets/images/emoji/leopard.png new file mode 100644 index 00000000000..8aac3d49448 Binary files /dev/null and b/app/assets/images/emoji/leopard.png differ diff --git a/app/assets/images/emoji/level_slider.png b/app/assets/images/emoji/level_slider.png new file mode 100644 index 00000000000..720a3b34119 Binary files /dev/null and b/app/assets/images/emoji/level_slider.png differ diff --git a/app/assets/images/emoji/levitate.png b/app/assets/images/emoji/levitate.png new file mode 100644 index 00000000000..3dc315a3d91 Binary files /dev/null and b/app/assets/images/emoji/levitate.png differ diff --git a/app/assets/images/emoji/libra.png b/app/assets/images/emoji/libra.png new file mode 100644 index 00000000000..8fd133a357c Binary files /dev/null and b/app/assets/images/emoji/libra.png differ diff --git a/app/assets/images/emoji/lifter.png b/app/assets/images/emoji/lifter.png new file mode 100644 index 00000000000..afdeaa476af Binary files /dev/null and b/app/assets/images/emoji/lifter.png differ diff --git a/app/assets/images/emoji/lifter_tone1.png b/app/assets/images/emoji/lifter_tone1.png new file mode 100644 index 00000000000..febaad123ec Binary files /dev/null and b/app/assets/images/emoji/lifter_tone1.png differ diff --git a/app/assets/images/emoji/lifter_tone2.png b/app/assets/images/emoji/lifter_tone2.png new file mode 100644 index 00000000000..27ae794a18e Binary files /dev/null and b/app/assets/images/emoji/lifter_tone2.png differ diff --git a/app/assets/images/emoji/lifter_tone3.png b/app/assets/images/emoji/lifter_tone3.png new file mode 100644 index 00000000000..45c4c22c709 Binary files /dev/null and b/app/assets/images/emoji/lifter_tone3.png differ diff --git a/app/assets/images/emoji/lifter_tone4.png b/app/assets/images/emoji/lifter_tone4.png new file mode 100644 index 00000000000..67dd21d2464 Binary files /dev/null and b/app/assets/images/emoji/lifter_tone4.png differ diff --git a/app/assets/images/emoji/lifter_tone5.png b/app/assets/images/emoji/lifter_tone5.png new file mode 100644 index 00000000000..fa0152038b6 Binary files /dev/null and b/app/assets/images/emoji/lifter_tone5.png differ diff --git a/app/assets/images/emoji/light_rail.png b/app/assets/images/emoji/light_rail.png new file mode 100644 index 00000000000..a64829f5078 Binary files /dev/null and b/app/assets/images/emoji/light_rail.png differ diff --git a/app/assets/images/emoji/link.png b/app/assets/images/emoji/link.png new file mode 100644 index 00000000000..ae20f0f8eec Binary files /dev/null and b/app/assets/images/emoji/link.png differ diff --git a/app/assets/images/emoji/lion_face.png b/app/assets/images/emoji/lion_face.png new file mode 100644 index 00000000000..5062ab47ecf Binary files /dev/null and b/app/assets/images/emoji/lion_face.png differ diff --git a/app/assets/images/emoji/lips.png b/app/assets/images/emoji/lips.png new file mode 100644 index 00000000000..35f3cc2006f Binary files /dev/null and b/app/assets/images/emoji/lips.png differ diff --git a/app/assets/images/emoji/lipstick.png b/app/assets/images/emoji/lipstick.png new file mode 100644 index 00000000000..61a0c084c99 Binary files /dev/null and b/app/assets/images/emoji/lipstick.png differ diff --git a/app/assets/images/emoji/lizard.png b/app/assets/images/emoji/lizard.png new file mode 100644 index 00000000000..8363876050e Binary files /dev/null and b/app/assets/images/emoji/lizard.png differ diff --git a/app/assets/images/emoji/lock.png b/app/assets/images/emoji/lock.png new file mode 100644 index 00000000000..5a739c46644 Binary files /dev/null and b/app/assets/images/emoji/lock.png differ diff --git a/app/assets/images/emoji/lock_with_ink_pen.png b/app/assets/images/emoji/lock_with_ink_pen.png new file mode 100644 index 00000000000..19a07d162fb Binary files /dev/null and b/app/assets/images/emoji/lock_with_ink_pen.png differ diff --git a/app/assets/images/emoji/lollipop.png b/app/assets/images/emoji/lollipop.png new file mode 100644 index 00000000000..ad76d7bf916 Binary files /dev/null and b/app/assets/images/emoji/lollipop.png differ diff --git a/app/assets/images/emoji/loop.png b/app/assets/images/emoji/loop.png new file mode 100644 index 00000000000..0b82c8fe315 Binary files /dev/null and b/app/assets/images/emoji/loop.png differ diff --git a/app/assets/images/emoji/loud_sound.png b/app/assets/images/emoji/loud_sound.png new file mode 100644 index 00000000000..8370033a539 Binary files /dev/null and b/app/assets/images/emoji/loud_sound.png differ diff --git a/app/assets/images/emoji/loudspeaker.png b/app/assets/images/emoji/loudspeaker.png new file mode 100644 index 00000000000..5fd76a95b82 Binary files /dev/null and b/app/assets/images/emoji/loudspeaker.png differ diff --git a/app/assets/images/emoji/love_hotel.png b/app/assets/images/emoji/love_hotel.png new file mode 100644 index 00000000000..5e136be6f8b Binary files /dev/null and b/app/assets/images/emoji/love_hotel.png differ diff --git a/app/assets/images/emoji/love_letter.png b/app/assets/images/emoji/love_letter.png new file mode 100644 index 00000000000..3c3c767e784 Binary files /dev/null and b/app/assets/images/emoji/love_letter.png differ diff --git a/app/assets/images/emoji/low_brightness.png b/app/assets/images/emoji/low_brightness.png new file mode 100644 index 00000000000..543011d3961 Binary files /dev/null and b/app/assets/images/emoji/low_brightness.png differ diff --git a/app/assets/images/emoji/lying_face.png b/app/assets/images/emoji/lying_face.png new file mode 100644 index 00000000000..02827e2628b Binary files /dev/null and b/app/assets/images/emoji/lying_face.png differ diff --git a/app/assets/images/emoji/m.png b/app/assets/images/emoji/m.png new file mode 100644 index 00000000000..8a3506fc1d7 Binary files /dev/null and b/app/assets/images/emoji/m.png differ diff --git a/app/assets/images/emoji/mag.png b/app/assets/images/emoji/mag.png new file mode 100644 index 00000000000..55487156ac6 Binary files /dev/null and b/app/assets/images/emoji/mag.png differ diff --git a/app/assets/images/emoji/mag_right.png b/app/assets/images/emoji/mag_right.png new file mode 100644 index 00000000000..0f4b1bca876 Binary files /dev/null and b/app/assets/images/emoji/mag_right.png differ diff --git a/app/assets/images/emoji/mahjong.png b/app/assets/images/emoji/mahjong.png new file mode 100644 index 00000000000..66fd32025b2 Binary files /dev/null and b/app/assets/images/emoji/mahjong.png differ diff --git a/app/assets/images/emoji/mailbox.png b/app/assets/images/emoji/mailbox.png new file mode 100644 index 00000000000..ef5174e40dd Binary files /dev/null and b/app/assets/images/emoji/mailbox.png differ diff --git a/app/assets/images/emoji/mailbox_closed.png b/app/assets/images/emoji/mailbox_closed.png new file mode 100644 index 00000000000..ddc705db0d8 Binary files /dev/null and b/app/assets/images/emoji/mailbox_closed.png differ diff --git a/app/assets/images/emoji/mailbox_with_mail.png b/app/assets/images/emoji/mailbox_with_mail.png new file mode 100644 index 00000000000..5460616a5b1 Binary files /dev/null and b/app/assets/images/emoji/mailbox_with_mail.png differ diff --git a/app/assets/images/emoji/mailbox_with_no_mail.png b/app/assets/images/emoji/mailbox_with_no_mail.png new file mode 100644 index 00000000000..f9aeee6b15a Binary files /dev/null and b/app/assets/images/emoji/mailbox_with_no_mail.png differ diff --git a/app/assets/images/emoji/man.png b/app/assets/images/emoji/man.png new file mode 100644 index 00000000000..857a02e5146 Binary files /dev/null and b/app/assets/images/emoji/man.png differ diff --git a/app/assets/images/emoji/man_dancing.png b/app/assets/images/emoji/man_dancing.png new file mode 100644 index 00000000000..ccff3bede5a Binary files /dev/null and b/app/assets/images/emoji/man_dancing.png differ diff --git a/app/assets/images/emoji/man_dancing_tone1.png b/app/assets/images/emoji/man_dancing_tone1.png new file mode 100644 index 00000000000..e0b9f82d905 Binary files /dev/null and b/app/assets/images/emoji/man_dancing_tone1.png differ diff --git a/app/assets/images/emoji/man_dancing_tone2.png b/app/assets/images/emoji/man_dancing_tone2.png new file mode 100644 index 00000000000..a5beed56e2e Binary files /dev/null and b/app/assets/images/emoji/man_dancing_tone2.png differ diff --git a/app/assets/images/emoji/man_dancing_tone3.png b/app/assets/images/emoji/man_dancing_tone3.png new file mode 100644 index 00000000000..2fa20180a6e Binary files /dev/null and b/app/assets/images/emoji/man_dancing_tone3.png differ diff --git a/app/assets/images/emoji/man_dancing_tone4.png b/app/assets/images/emoji/man_dancing_tone4.png new file mode 100644 index 00000000000..bd3528c83ba Binary files /dev/null and b/app/assets/images/emoji/man_dancing_tone4.png differ diff --git a/app/assets/images/emoji/man_dancing_tone5.png b/app/assets/images/emoji/man_dancing_tone5.png new file mode 100644 index 00000000000..41fd4f880c9 Binary files /dev/null and b/app/assets/images/emoji/man_dancing_tone5.png differ diff --git a/app/assets/images/emoji/man_in_tuxedo.png b/app/assets/images/emoji/man_in_tuxedo.png new file mode 100644 index 00000000000..5f7e9303f89 Binary files /dev/null and b/app/assets/images/emoji/man_in_tuxedo.png differ diff --git a/app/assets/images/emoji/man_in_tuxedo_tone1.png b/app/assets/images/emoji/man_in_tuxedo_tone1.png new file mode 100644 index 00000000000..7b6b3acd99b Binary files /dev/null and b/app/assets/images/emoji/man_in_tuxedo_tone1.png differ diff --git a/app/assets/images/emoji/man_in_tuxedo_tone2.png b/app/assets/images/emoji/man_in_tuxedo_tone2.png new file mode 100644 index 00000000000..7975191b360 Binary files /dev/null and b/app/assets/images/emoji/man_in_tuxedo_tone2.png differ diff --git a/app/assets/images/emoji/man_in_tuxedo_tone3.png b/app/assets/images/emoji/man_in_tuxedo_tone3.png new file mode 100644 index 00000000000..a2816f600ae Binary files /dev/null and b/app/assets/images/emoji/man_in_tuxedo_tone3.png differ diff --git a/app/assets/images/emoji/man_in_tuxedo_tone4.png b/app/assets/images/emoji/man_in_tuxedo_tone4.png new file mode 100644 index 00000000000..ea8291760f9 Binary files /dev/null and b/app/assets/images/emoji/man_in_tuxedo_tone4.png differ diff --git a/app/assets/images/emoji/man_in_tuxedo_tone5.png b/app/assets/images/emoji/man_in_tuxedo_tone5.png new file mode 100644 index 00000000000..c743e05fc5e Binary files /dev/null and b/app/assets/images/emoji/man_in_tuxedo_tone5.png differ diff --git a/app/assets/images/emoji/man_tone1.png b/app/assets/images/emoji/man_tone1.png new file mode 100644 index 00000000000..bb86e963a80 Binary files /dev/null and b/app/assets/images/emoji/man_tone1.png differ diff --git a/app/assets/images/emoji/man_tone2.png b/app/assets/images/emoji/man_tone2.png new file mode 100644 index 00000000000..fdeeaff46f5 Binary files /dev/null and b/app/assets/images/emoji/man_tone2.png differ diff --git a/app/assets/images/emoji/man_tone3.png b/app/assets/images/emoji/man_tone3.png new file mode 100644 index 00000000000..7ae0b5df9cf Binary files /dev/null and b/app/assets/images/emoji/man_tone3.png differ diff --git a/app/assets/images/emoji/man_tone4.png b/app/assets/images/emoji/man_tone4.png new file mode 100644 index 00000000000..db14cde99b8 Binary files /dev/null and b/app/assets/images/emoji/man_tone4.png differ diff --git a/app/assets/images/emoji/man_tone5.png b/app/assets/images/emoji/man_tone5.png new file mode 100644 index 00000000000..7c67a70529c Binary files /dev/null and b/app/assets/images/emoji/man_tone5.png differ diff --git a/app/assets/images/emoji/man_with_gua_pi_mao.png b/app/assets/images/emoji/man_with_gua_pi_mao.png new file mode 100644 index 00000000000..7841e13608d Binary files /dev/null and b/app/assets/images/emoji/man_with_gua_pi_mao.png differ diff --git a/app/assets/images/emoji/man_with_gua_pi_mao_tone1.png b/app/assets/images/emoji/man_with_gua_pi_mao_tone1.png new file mode 100644 index 00000000000..5b7b3def19c Binary files /dev/null and b/app/assets/images/emoji/man_with_gua_pi_mao_tone1.png differ diff --git a/app/assets/images/emoji/man_with_gua_pi_mao_tone2.png b/app/assets/images/emoji/man_with_gua_pi_mao_tone2.png new file mode 100644 index 00000000000..c8b9cf87f4b Binary files /dev/null and b/app/assets/images/emoji/man_with_gua_pi_mao_tone2.png differ diff --git a/app/assets/images/emoji/man_with_gua_pi_mao_tone3.png b/app/assets/images/emoji/man_with_gua_pi_mao_tone3.png new file mode 100644 index 00000000000..effdd0c4c84 Binary files /dev/null and b/app/assets/images/emoji/man_with_gua_pi_mao_tone3.png differ diff --git a/app/assets/images/emoji/man_with_gua_pi_mao_tone4.png b/app/assets/images/emoji/man_with_gua_pi_mao_tone4.png new file mode 100644 index 00000000000..f885ff46fa1 Binary files /dev/null and b/app/assets/images/emoji/man_with_gua_pi_mao_tone4.png differ diff --git a/app/assets/images/emoji/man_with_gua_pi_mao_tone5.png b/app/assets/images/emoji/man_with_gua_pi_mao_tone5.png new file mode 100644 index 00000000000..a6d55ca1380 Binary files /dev/null and b/app/assets/images/emoji/man_with_gua_pi_mao_tone5.png differ diff --git a/app/assets/images/emoji/man_with_turban.png b/app/assets/images/emoji/man_with_turban.png new file mode 100644 index 00000000000..51cf047f966 Binary files /dev/null and b/app/assets/images/emoji/man_with_turban.png differ diff --git a/app/assets/images/emoji/man_with_turban_tone1.png b/app/assets/images/emoji/man_with_turban_tone1.png new file mode 100644 index 00000000000..1e12ee4b231 Binary files /dev/null and b/app/assets/images/emoji/man_with_turban_tone1.png differ diff --git a/app/assets/images/emoji/man_with_turban_tone2.png b/app/assets/images/emoji/man_with_turban_tone2.png new file mode 100644 index 00000000000..37de4cceb23 Binary files /dev/null and b/app/assets/images/emoji/man_with_turban_tone2.png differ diff --git a/app/assets/images/emoji/man_with_turban_tone3.png b/app/assets/images/emoji/man_with_turban_tone3.png new file mode 100644 index 00000000000..f607afd3450 Binary files /dev/null and b/app/assets/images/emoji/man_with_turban_tone3.png differ diff --git a/app/assets/images/emoji/man_with_turban_tone4.png b/app/assets/images/emoji/man_with_turban_tone4.png new file mode 100644 index 00000000000..c05695888af Binary files /dev/null and b/app/assets/images/emoji/man_with_turban_tone4.png differ diff --git a/app/assets/images/emoji/man_with_turban_tone5.png b/app/assets/images/emoji/man_with_turban_tone5.png new file mode 100644 index 00000000000..4b4ff64720b Binary files /dev/null and b/app/assets/images/emoji/man_with_turban_tone5.png differ diff --git a/app/assets/images/emoji/mans_shoe.png b/app/assets/images/emoji/mans_shoe.png new file mode 100644 index 00000000000..4bf7541032c Binary files /dev/null and b/app/assets/images/emoji/mans_shoe.png differ diff --git a/app/assets/images/emoji/map.png b/app/assets/images/emoji/map.png new file mode 100644 index 00000000000..15efe32c798 Binary files /dev/null and b/app/assets/images/emoji/map.png differ diff --git a/app/assets/images/emoji/maple_leaf.png b/app/assets/images/emoji/maple_leaf.png new file mode 100644 index 00000000000..c49acea67f7 Binary files /dev/null and b/app/assets/images/emoji/maple_leaf.png differ diff --git a/app/assets/images/emoji/martial_arts_uniform.png b/app/assets/images/emoji/martial_arts_uniform.png new file mode 100644 index 00000000000..8d6114761f6 Binary files /dev/null and b/app/assets/images/emoji/martial_arts_uniform.png differ diff --git a/app/assets/images/emoji/mask.png b/app/assets/images/emoji/mask.png new file mode 100644 index 00000000000..1e800acd1c0 Binary files /dev/null and b/app/assets/images/emoji/mask.png differ diff --git a/app/assets/images/emoji/massage.png b/app/assets/images/emoji/massage.png new file mode 100644 index 00000000000..b91d845e374 Binary files /dev/null and b/app/assets/images/emoji/massage.png differ diff --git a/app/assets/images/emoji/massage_tone1.png b/app/assets/images/emoji/massage_tone1.png new file mode 100644 index 00000000000..e0f415d3186 Binary files /dev/null and b/app/assets/images/emoji/massage_tone1.png differ diff --git a/app/assets/images/emoji/massage_tone2.png b/app/assets/images/emoji/massage_tone2.png new file mode 100644 index 00000000000..0bb244a270b Binary files /dev/null and b/app/assets/images/emoji/massage_tone2.png differ diff --git a/app/assets/images/emoji/massage_tone3.png b/app/assets/images/emoji/massage_tone3.png new file mode 100644 index 00000000000..a117ee81a22 Binary files /dev/null and b/app/assets/images/emoji/massage_tone3.png differ diff --git a/app/assets/images/emoji/massage_tone4.png b/app/assets/images/emoji/massage_tone4.png new file mode 100644 index 00000000000..6f42ab017f4 Binary files /dev/null and b/app/assets/images/emoji/massage_tone4.png differ diff --git a/app/assets/images/emoji/massage_tone5.png b/app/assets/images/emoji/massage_tone5.png new file mode 100644 index 00000000000..6a388c0d0b5 Binary files /dev/null and b/app/assets/images/emoji/massage_tone5.png differ diff --git a/app/assets/images/emoji/meat_on_bone.png b/app/assets/images/emoji/meat_on_bone.png new file mode 100644 index 00000000000..b20a59d1690 Binary files /dev/null and b/app/assets/images/emoji/meat_on_bone.png differ diff --git a/app/assets/images/emoji/medal.png b/app/assets/images/emoji/medal.png new file mode 100644 index 00000000000..b85896b14da Binary files /dev/null and b/app/assets/images/emoji/medal.png differ diff --git a/app/assets/images/emoji/mega.png b/app/assets/images/emoji/mega.png new file mode 100644 index 00000000000..4e6735188e3 Binary files /dev/null and b/app/assets/images/emoji/mega.png differ diff --git a/app/assets/images/emoji/melon.png b/app/assets/images/emoji/melon.png new file mode 100644 index 00000000000..c01232d419d Binary files /dev/null and b/app/assets/images/emoji/melon.png differ diff --git a/app/assets/images/emoji/menorah.png b/app/assets/images/emoji/menorah.png new file mode 100644 index 00000000000..b4297362869 Binary files /dev/null and b/app/assets/images/emoji/menorah.png differ diff --git a/app/assets/images/emoji/mens.png b/app/assets/images/emoji/mens.png new file mode 100644 index 00000000000..f5a1e1ba0cd Binary files /dev/null and b/app/assets/images/emoji/mens.png differ diff --git a/app/assets/images/emoji/metal.png b/app/assets/images/emoji/metal.png new file mode 100644 index 00000000000..4aa6e7e0a44 Binary files /dev/null and b/app/assets/images/emoji/metal.png differ diff --git a/app/assets/images/emoji/metal_tone1.png b/app/assets/images/emoji/metal_tone1.png new file mode 100644 index 00000000000..c080d2addbd Binary files /dev/null and b/app/assets/images/emoji/metal_tone1.png differ diff --git a/app/assets/images/emoji/metal_tone2.png b/app/assets/images/emoji/metal_tone2.png new file mode 100644 index 00000000000..12313529bcf Binary files /dev/null and b/app/assets/images/emoji/metal_tone2.png differ diff --git a/app/assets/images/emoji/metal_tone3.png b/app/assets/images/emoji/metal_tone3.png new file mode 100644 index 00000000000..ca9be6ae67b Binary files /dev/null and b/app/assets/images/emoji/metal_tone3.png differ diff --git a/app/assets/images/emoji/metal_tone4.png b/app/assets/images/emoji/metal_tone4.png new file mode 100644 index 00000000000..abe28cbf890 Binary files /dev/null and b/app/assets/images/emoji/metal_tone4.png differ diff --git a/app/assets/images/emoji/metal_tone5.png b/app/assets/images/emoji/metal_tone5.png new file mode 100644 index 00000000000..0c6b5dd34ed Binary files /dev/null and b/app/assets/images/emoji/metal_tone5.png differ diff --git a/app/assets/images/emoji/metro.png b/app/assets/images/emoji/metro.png new file mode 100644 index 00000000000..1de8f0551f3 Binary files /dev/null and b/app/assets/images/emoji/metro.png differ diff --git a/app/assets/images/emoji/microphone.png b/app/assets/images/emoji/microphone.png new file mode 100644 index 00000000000..d4e6b0def25 Binary files /dev/null and b/app/assets/images/emoji/microphone.png differ diff --git a/app/assets/images/emoji/microphone2.png b/app/assets/images/emoji/microphone2.png new file mode 100644 index 00000000000..cd9167654ff Binary files /dev/null and b/app/assets/images/emoji/microphone2.png differ diff --git a/app/assets/images/emoji/microscope.png b/app/assets/images/emoji/microscope.png new file mode 100644 index 00000000000..90f5acf6a78 Binary files /dev/null and b/app/assets/images/emoji/microscope.png differ diff --git a/app/assets/images/emoji/middle_finger.png b/app/assets/images/emoji/middle_finger.png new file mode 100644 index 00000000000..697f7a25eb2 Binary files /dev/null and b/app/assets/images/emoji/middle_finger.png differ diff --git a/app/assets/images/emoji/middle_finger_tone1.png b/app/assets/images/emoji/middle_finger_tone1.png new file mode 100644 index 00000000000..61ef12a1548 Binary files /dev/null and b/app/assets/images/emoji/middle_finger_tone1.png differ diff --git a/app/assets/images/emoji/middle_finger_tone2.png b/app/assets/images/emoji/middle_finger_tone2.png new file mode 100644 index 00000000000..c31a69be9af Binary files /dev/null and b/app/assets/images/emoji/middle_finger_tone2.png differ diff --git a/app/assets/images/emoji/middle_finger_tone3.png b/app/assets/images/emoji/middle_finger_tone3.png new file mode 100644 index 00000000000..73ac216ce63 Binary files /dev/null and b/app/assets/images/emoji/middle_finger_tone3.png differ diff --git a/app/assets/images/emoji/middle_finger_tone4.png b/app/assets/images/emoji/middle_finger_tone4.png new file mode 100644 index 00000000000..80b8ab7706d Binary files /dev/null and b/app/assets/images/emoji/middle_finger_tone4.png differ diff --git a/app/assets/images/emoji/middle_finger_tone5.png b/app/assets/images/emoji/middle_finger_tone5.png new file mode 100644 index 00000000000..a8826b196e8 Binary files /dev/null and b/app/assets/images/emoji/middle_finger_tone5.png differ diff --git a/app/assets/images/emoji/military_medal.png b/app/assets/images/emoji/military_medal.png new file mode 100644 index 00000000000..ecd3fb03584 Binary files /dev/null and b/app/assets/images/emoji/military_medal.png differ diff --git a/app/assets/images/emoji/milk.png b/app/assets/images/emoji/milk.png new file mode 100644 index 00000000000..e4fcf2e64f3 Binary files /dev/null and b/app/assets/images/emoji/milk.png differ diff --git a/app/assets/images/emoji/milky_way.png b/app/assets/images/emoji/milky_way.png new file mode 100644 index 00000000000..b2b8ac59c5e Binary files /dev/null and b/app/assets/images/emoji/milky_way.png differ diff --git a/app/assets/images/emoji/minibus.png b/app/assets/images/emoji/minibus.png new file mode 100644 index 00000000000..c60dd8f47ab Binary files /dev/null and b/app/assets/images/emoji/minibus.png differ diff --git a/app/assets/images/emoji/minidisc.png b/app/assets/images/emoji/minidisc.png new file mode 100644 index 00000000000..9fa94cfbe74 Binary files /dev/null and b/app/assets/images/emoji/minidisc.png differ diff --git a/app/assets/images/emoji/mobile_phone_off.png b/app/assets/images/emoji/mobile_phone_off.png new file mode 100644 index 00000000000..8b661ec1c94 Binary files /dev/null and b/app/assets/images/emoji/mobile_phone_off.png differ diff --git a/app/assets/images/emoji/money_mouth.png b/app/assets/images/emoji/money_mouth.png new file mode 100644 index 00000000000..75fd1e90cb0 Binary files /dev/null and b/app/assets/images/emoji/money_mouth.png differ diff --git a/app/assets/images/emoji/money_with_wings.png b/app/assets/images/emoji/money_with_wings.png new file mode 100644 index 00000000000..f022b04b3c2 Binary files /dev/null and b/app/assets/images/emoji/money_with_wings.png differ diff --git a/app/assets/images/emoji/moneybag.png b/app/assets/images/emoji/moneybag.png new file mode 100644 index 00000000000..b9296be0902 Binary files /dev/null and b/app/assets/images/emoji/moneybag.png differ diff --git a/app/assets/images/emoji/monkey.png b/app/assets/images/emoji/monkey.png new file mode 100644 index 00000000000..9fae29448e3 Binary files /dev/null and b/app/assets/images/emoji/monkey.png differ diff --git a/app/assets/images/emoji/monkey_face.png b/app/assets/images/emoji/monkey_face.png new file mode 100644 index 00000000000..7cab9b91a82 Binary files /dev/null and b/app/assets/images/emoji/monkey_face.png differ diff --git a/app/assets/images/emoji/monorail.png b/app/assets/images/emoji/monorail.png new file mode 100644 index 00000000000..11eb1f574bf Binary files /dev/null and b/app/assets/images/emoji/monorail.png differ diff --git a/app/assets/images/emoji/mortar_board.png b/app/assets/images/emoji/mortar_board.png new file mode 100644 index 00000000000..8b17ddd9d00 Binary files /dev/null and b/app/assets/images/emoji/mortar_board.png differ diff --git a/app/assets/images/emoji/mosque.png b/app/assets/images/emoji/mosque.png new file mode 100644 index 00000000000..ef770b26d96 Binary files /dev/null and b/app/assets/images/emoji/mosque.png differ diff --git a/app/assets/images/emoji/motor_scooter.png b/app/assets/images/emoji/motor_scooter.png new file mode 100644 index 00000000000..c5afa72d807 Binary files /dev/null and b/app/assets/images/emoji/motor_scooter.png differ diff --git a/app/assets/images/emoji/motorboat.png b/app/assets/images/emoji/motorboat.png new file mode 100644 index 00000000000..0506db1a40f Binary files /dev/null and b/app/assets/images/emoji/motorboat.png differ diff --git a/app/assets/images/emoji/motorcycle.png b/app/assets/images/emoji/motorcycle.png new file mode 100644 index 00000000000..3d1d567e8ec Binary files /dev/null and b/app/assets/images/emoji/motorcycle.png differ diff --git a/app/assets/images/emoji/motorway.png b/app/assets/images/emoji/motorway.png new file mode 100644 index 00000000000..8c3d3d03e3f Binary files /dev/null and b/app/assets/images/emoji/motorway.png differ diff --git a/app/assets/images/emoji/mount_fuji.png b/app/assets/images/emoji/mount_fuji.png new file mode 100644 index 00000000000..88a54752458 Binary files /dev/null and b/app/assets/images/emoji/mount_fuji.png differ diff --git a/app/assets/images/emoji/mountain.png b/app/assets/images/emoji/mountain.png new file mode 100644 index 00000000000..6722ebdd294 Binary files /dev/null and b/app/assets/images/emoji/mountain.png differ diff --git a/app/assets/images/emoji/mountain_bicyclist.png b/app/assets/images/emoji/mountain_bicyclist.png new file mode 100644 index 00000000000..41d3dc3ac6f Binary files /dev/null and b/app/assets/images/emoji/mountain_bicyclist.png differ diff --git a/app/assets/images/emoji/mountain_bicyclist_tone1.png b/app/assets/images/emoji/mountain_bicyclist_tone1.png new file mode 100644 index 00000000000..e9f1daf5e40 Binary files /dev/null and b/app/assets/images/emoji/mountain_bicyclist_tone1.png differ diff --git a/app/assets/images/emoji/mountain_bicyclist_tone2.png b/app/assets/images/emoji/mountain_bicyclist_tone2.png new file mode 100644 index 00000000000..555b9e29d4d Binary files /dev/null and b/app/assets/images/emoji/mountain_bicyclist_tone2.png differ diff --git a/app/assets/images/emoji/mountain_bicyclist_tone3.png b/app/assets/images/emoji/mountain_bicyclist_tone3.png new file mode 100644 index 00000000000..7df5508ec8c Binary files /dev/null and b/app/assets/images/emoji/mountain_bicyclist_tone3.png differ diff --git a/app/assets/images/emoji/mountain_bicyclist_tone4.png b/app/assets/images/emoji/mountain_bicyclist_tone4.png new file mode 100644 index 00000000000..f94b3450697 Binary files /dev/null and b/app/assets/images/emoji/mountain_bicyclist_tone4.png differ diff --git a/app/assets/images/emoji/mountain_bicyclist_tone5.png b/app/assets/images/emoji/mountain_bicyclist_tone5.png new file mode 100644 index 00000000000..16a45861e1f Binary files /dev/null and b/app/assets/images/emoji/mountain_bicyclist_tone5.png differ diff --git a/app/assets/images/emoji/mountain_cableway.png b/app/assets/images/emoji/mountain_cableway.png new file mode 100644 index 00000000000..1dea73ca53b Binary files /dev/null and b/app/assets/images/emoji/mountain_cableway.png differ diff --git a/app/assets/images/emoji/mountain_railway.png b/app/assets/images/emoji/mountain_railway.png new file mode 100644 index 00000000000..ade2218e469 Binary files /dev/null and b/app/assets/images/emoji/mountain_railway.png differ diff --git a/app/assets/images/emoji/mountain_snow.png b/app/assets/images/emoji/mountain_snow.png new file mode 100644 index 00000000000..76e1cfd8313 Binary files /dev/null and b/app/assets/images/emoji/mountain_snow.png differ diff --git a/app/assets/images/emoji/mouse.png b/app/assets/images/emoji/mouse.png new file mode 100644 index 00000000000..50afcd3262e Binary files /dev/null and b/app/assets/images/emoji/mouse.png differ diff --git a/app/assets/images/emoji/mouse2.png b/app/assets/images/emoji/mouse2.png new file mode 100644 index 00000000000..20fb041f09f Binary files /dev/null and b/app/assets/images/emoji/mouse2.png differ diff --git a/app/assets/images/emoji/mouse_three_button.png b/app/assets/images/emoji/mouse_three_button.png new file mode 100644 index 00000000000..e84e96ff6e8 Binary files /dev/null and b/app/assets/images/emoji/mouse_three_button.png differ diff --git a/app/assets/images/emoji/movie_camera.png b/app/assets/images/emoji/movie_camera.png new file mode 100644 index 00000000000..4e73b130155 Binary files /dev/null and b/app/assets/images/emoji/movie_camera.png differ diff --git a/app/assets/images/emoji/moyai.png b/app/assets/images/emoji/moyai.png new file mode 100644 index 00000000000..e6a7779c45b Binary files /dev/null and b/app/assets/images/emoji/moyai.png differ diff --git a/app/assets/images/emoji/mrs_claus.png b/app/assets/images/emoji/mrs_claus.png new file mode 100644 index 00000000000..078f0657f95 Binary files /dev/null and b/app/assets/images/emoji/mrs_claus.png differ diff --git a/app/assets/images/emoji/mrs_claus_tone1.png b/app/assets/images/emoji/mrs_claus_tone1.png new file mode 100644 index 00000000000..d8a695d7035 Binary files /dev/null and b/app/assets/images/emoji/mrs_claus_tone1.png differ diff --git a/app/assets/images/emoji/mrs_claus_tone2.png b/app/assets/images/emoji/mrs_claus_tone2.png new file mode 100644 index 00000000000..0e17e8c51f3 Binary files /dev/null and b/app/assets/images/emoji/mrs_claus_tone2.png differ diff --git a/app/assets/images/emoji/mrs_claus_tone3.png b/app/assets/images/emoji/mrs_claus_tone3.png new file mode 100644 index 00000000000..c3ee4d1dfae Binary files /dev/null and b/app/assets/images/emoji/mrs_claus_tone3.png differ diff --git a/app/assets/images/emoji/mrs_claus_tone4.png b/app/assets/images/emoji/mrs_claus_tone4.png new file mode 100644 index 00000000000..68a556da2fe Binary files /dev/null and b/app/assets/images/emoji/mrs_claus_tone4.png differ diff --git a/app/assets/images/emoji/mrs_claus_tone5.png b/app/assets/images/emoji/mrs_claus_tone5.png new file mode 100644 index 00000000000..ccab3c40ff2 Binary files /dev/null and b/app/assets/images/emoji/mrs_claus_tone5.png differ diff --git a/app/assets/images/emoji/muscle.png b/app/assets/images/emoji/muscle.png new file mode 100644 index 00000000000..7e67c1880f7 Binary files /dev/null and b/app/assets/images/emoji/muscle.png differ diff --git a/app/assets/images/emoji/muscle_tone1.png b/app/assets/images/emoji/muscle_tone1.png new file mode 100644 index 00000000000..1522942ce51 Binary files /dev/null and b/app/assets/images/emoji/muscle_tone1.png differ diff --git a/app/assets/images/emoji/muscle_tone2.png b/app/assets/images/emoji/muscle_tone2.png new file mode 100644 index 00000000000..569c6e832ca Binary files /dev/null and b/app/assets/images/emoji/muscle_tone2.png differ diff --git a/app/assets/images/emoji/muscle_tone3.png b/app/assets/images/emoji/muscle_tone3.png new file mode 100644 index 00000000000..0a76b00fa89 Binary files /dev/null and b/app/assets/images/emoji/muscle_tone3.png differ diff --git a/app/assets/images/emoji/muscle_tone4.png b/app/assets/images/emoji/muscle_tone4.png new file mode 100644 index 00000000000..f0cf31328e0 Binary files /dev/null and b/app/assets/images/emoji/muscle_tone4.png differ diff --git a/app/assets/images/emoji/muscle_tone5.png b/app/assets/images/emoji/muscle_tone5.png new file mode 100644 index 00000000000..4fda92460e8 Binary files /dev/null and b/app/assets/images/emoji/muscle_tone5.png differ diff --git a/app/assets/images/emoji/mushroom.png b/app/assets/images/emoji/mushroom.png new file mode 100644 index 00000000000..dd85742ba2c Binary files /dev/null and b/app/assets/images/emoji/mushroom.png differ diff --git a/app/assets/images/emoji/musical_keyboard.png b/app/assets/images/emoji/musical_keyboard.png new file mode 100644 index 00000000000..442b7456842 Binary files /dev/null and b/app/assets/images/emoji/musical_keyboard.png differ diff --git a/app/assets/images/emoji/musical_note.png b/app/assets/images/emoji/musical_note.png new file mode 100644 index 00000000000..06691ef61bb Binary files /dev/null and b/app/assets/images/emoji/musical_note.png differ diff --git a/app/assets/images/emoji/musical_score.png b/app/assets/images/emoji/musical_score.png new file mode 100644 index 00000000000..47dc05a8ef5 Binary files /dev/null and b/app/assets/images/emoji/musical_score.png differ diff --git a/app/assets/images/emoji/mute.png b/app/assets/images/emoji/mute.png new file mode 100644 index 00000000000..7c1788e5075 Binary files /dev/null and b/app/assets/images/emoji/mute.png differ diff --git a/app/assets/images/emoji/nail_care.png b/app/assets/images/emoji/nail_care.png new file mode 100644 index 00000000000..aa52af7050d Binary files /dev/null and b/app/assets/images/emoji/nail_care.png differ diff --git a/app/assets/images/emoji/nail_care_tone1.png b/app/assets/images/emoji/nail_care_tone1.png new file mode 100644 index 00000000000..26e883dd244 Binary files /dev/null and b/app/assets/images/emoji/nail_care_tone1.png differ diff --git a/app/assets/images/emoji/nail_care_tone2.png b/app/assets/images/emoji/nail_care_tone2.png new file mode 100644 index 00000000000..61257b47ea3 Binary files /dev/null and b/app/assets/images/emoji/nail_care_tone2.png differ diff --git a/app/assets/images/emoji/nail_care_tone3.png b/app/assets/images/emoji/nail_care_tone3.png new file mode 100644 index 00000000000..29871b05f62 Binary files /dev/null and b/app/assets/images/emoji/nail_care_tone3.png differ diff --git a/app/assets/images/emoji/nail_care_tone4.png b/app/assets/images/emoji/nail_care_tone4.png new file mode 100644 index 00000000000..2881de0b17d Binary files /dev/null and b/app/assets/images/emoji/nail_care_tone4.png differ diff --git a/app/assets/images/emoji/nail_care_tone5.png b/app/assets/images/emoji/nail_care_tone5.png new file mode 100644 index 00000000000..a0b7c0a45a6 Binary files /dev/null and b/app/assets/images/emoji/nail_care_tone5.png differ diff --git a/app/assets/images/emoji/name_badge.png b/app/assets/images/emoji/name_badge.png new file mode 100644 index 00000000000..ec5ee213e20 Binary files /dev/null and b/app/assets/images/emoji/name_badge.png differ diff --git a/app/assets/images/emoji/nauseated_face.png b/app/assets/images/emoji/nauseated_face.png new file mode 100644 index 00000000000..a566c109c28 Binary files /dev/null and b/app/assets/images/emoji/nauseated_face.png differ diff --git a/app/assets/images/emoji/necktie.png b/app/assets/images/emoji/necktie.png new file mode 100644 index 00000000000..1804e7f3ff3 Binary files /dev/null and b/app/assets/images/emoji/necktie.png differ diff --git a/app/assets/images/emoji/negative_squared_cross_mark.png b/app/assets/images/emoji/negative_squared_cross_mark.png new file mode 100644 index 00000000000..dae487f1f98 Binary files /dev/null and b/app/assets/images/emoji/negative_squared_cross_mark.png differ diff --git a/app/assets/images/emoji/nerd.png b/app/assets/images/emoji/nerd.png new file mode 100644 index 00000000000..7820bd581dc Binary files /dev/null and b/app/assets/images/emoji/nerd.png differ diff --git a/app/assets/images/emoji/neutral_face.png b/app/assets/images/emoji/neutral_face.png new file mode 100644 index 00000000000..065d193afe4 Binary files /dev/null and b/app/assets/images/emoji/neutral_face.png differ diff --git a/app/assets/images/emoji/new.png b/app/assets/images/emoji/new.png new file mode 100644 index 00000000000..b4f85488d1a Binary files /dev/null and b/app/assets/images/emoji/new.png differ diff --git a/app/assets/images/emoji/new_moon.png b/app/assets/images/emoji/new_moon.png new file mode 100644 index 00000000000..ecff72caa42 Binary files /dev/null and b/app/assets/images/emoji/new_moon.png differ diff --git a/app/assets/images/emoji/new_moon_with_face.png b/app/assets/images/emoji/new_moon_with_face.png new file mode 100644 index 00000000000..150dd12400c Binary files /dev/null and b/app/assets/images/emoji/new_moon_with_face.png differ diff --git a/app/assets/images/emoji/newspaper.png b/app/assets/images/emoji/newspaper.png new file mode 100644 index 00000000000..2aa8f060bde Binary files /dev/null and b/app/assets/images/emoji/newspaper.png differ diff --git a/app/assets/images/emoji/newspaper2.png b/app/assets/images/emoji/newspaper2.png new file mode 100644 index 00000000000..f64748df2b2 Binary files /dev/null and b/app/assets/images/emoji/newspaper2.png differ diff --git a/app/assets/images/emoji/ng.png b/app/assets/images/emoji/ng.png new file mode 100644 index 00000000000..ee8d20f5ebc Binary files /dev/null and b/app/assets/images/emoji/ng.png differ diff --git a/app/assets/images/emoji/night_with_stars.png b/app/assets/images/emoji/night_with_stars.png new file mode 100644 index 00000000000..ca2018f456d Binary files /dev/null and b/app/assets/images/emoji/night_with_stars.png differ diff --git a/app/assets/images/emoji/nine.png b/app/assets/images/emoji/nine.png new file mode 100644 index 00000000000..9fce3d1eca9 Binary files /dev/null and b/app/assets/images/emoji/nine.png differ diff --git a/app/assets/images/emoji/no_bell.png b/app/assets/images/emoji/no_bell.png new file mode 100644 index 00000000000..15cb38dd1e7 Binary files /dev/null and b/app/assets/images/emoji/no_bell.png differ diff --git a/app/assets/images/emoji/no_bicycles.png b/app/assets/images/emoji/no_bicycles.png new file mode 100644 index 00000000000..19c85421ce9 Binary files /dev/null and b/app/assets/images/emoji/no_bicycles.png differ diff --git a/app/assets/images/emoji/no_entry.png b/app/assets/images/emoji/no_entry.png new file mode 100644 index 00000000000..476800fc5c6 Binary files /dev/null and b/app/assets/images/emoji/no_entry.png differ diff --git a/app/assets/images/emoji/no_entry_sign.png b/app/assets/images/emoji/no_entry_sign.png new file mode 100644 index 00000000000..d2efd65e74b Binary files /dev/null and b/app/assets/images/emoji/no_entry_sign.png differ diff --git a/app/assets/images/emoji/no_good.png b/app/assets/images/emoji/no_good.png new file mode 100644 index 00000000000..ed577100322 Binary files /dev/null and b/app/assets/images/emoji/no_good.png differ diff --git a/app/assets/images/emoji/no_good_tone1.png b/app/assets/images/emoji/no_good_tone1.png new file mode 100644 index 00000000000..5c1a3cbb884 Binary files /dev/null and b/app/assets/images/emoji/no_good_tone1.png differ diff --git a/app/assets/images/emoji/no_good_tone2.png b/app/assets/images/emoji/no_good_tone2.png new file mode 100644 index 00000000000..80d8021f8fe Binary files /dev/null and b/app/assets/images/emoji/no_good_tone2.png differ diff --git a/app/assets/images/emoji/no_good_tone3.png b/app/assets/images/emoji/no_good_tone3.png new file mode 100644 index 00000000000..635e6a00815 Binary files /dev/null and b/app/assets/images/emoji/no_good_tone3.png differ diff --git a/app/assets/images/emoji/no_good_tone4.png b/app/assets/images/emoji/no_good_tone4.png new file mode 100644 index 00000000000..b96e412a374 Binary files /dev/null and b/app/assets/images/emoji/no_good_tone4.png differ diff --git a/app/assets/images/emoji/no_good_tone5.png b/app/assets/images/emoji/no_good_tone5.png new file mode 100644 index 00000000000..9a7084afa0a Binary files /dev/null and b/app/assets/images/emoji/no_good_tone5.png differ diff --git a/app/assets/images/emoji/no_mobile_phones.png b/app/assets/images/emoji/no_mobile_phones.png new file mode 100644 index 00000000000..7b1ae6ea579 Binary files /dev/null and b/app/assets/images/emoji/no_mobile_phones.png differ diff --git a/app/assets/images/emoji/no_mouth.png b/app/assets/images/emoji/no_mouth.png new file mode 100644 index 00000000000..b642f6c1172 Binary files /dev/null and b/app/assets/images/emoji/no_mouth.png differ diff --git a/app/assets/images/emoji/no_pedestrians.png b/app/assets/images/emoji/no_pedestrians.png new file mode 100644 index 00000000000..286aa577a23 Binary files /dev/null and b/app/assets/images/emoji/no_pedestrians.png differ diff --git a/app/assets/images/emoji/no_smoking.png b/app/assets/images/emoji/no_smoking.png new file mode 100644 index 00000000000..586b8d29d05 Binary files /dev/null and b/app/assets/images/emoji/no_smoking.png differ diff --git a/app/assets/images/emoji/non-potable_water.png b/app/assets/images/emoji/non-potable_water.png new file mode 100644 index 00000000000..827d4193f4e Binary files /dev/null and b/app/assets/images/emoji/non-potable_water.png differ diff --git a/app/assets/images/emoji/nose.png b/app/assets/images/emoji/nose.png new file mode 100644 index 00000000000..2f04ac5f98f Binary files /dev/null and b/app/assets/images/emoji/nose.png differ diff --git a/app/assets/images/emoji/nose_tone1.png b/app/assets/images/emoji/nose_tone1.png new file mode 100644 index 00000000000..8008d17506e Binary files /dev/null and b/app/assets/images/emoji/nose_tone1.png differ diff --git a/app/assets/images/emoji/nose_tone2.png b/app/assets/images/emoji/nose_tone2.png new file mode 100644 index 00000000000..ac17f26e827 Binary files /dev/null and b/app/assets/images/emoji/nose_tone2.png differ diff --git a/app/assets/images/emoji/nose_tone3.png b/app/assets/images/emoji/nose_tone3.png new file mode 100644 index 00000000000..d8b6cbe0f8e Binary files /dev/null and b/app/assets/images/emoji/nose_tone3.png differ diff --git a/app/assets/images/emoji/nose_tone4.png b/app/assets/images/emoji/nose_tone4.png new file mode 100644 index 00000000000..004b2631e2e Binary files /dev/null and b/app/assets/images/emoji/nose_tone4.png differ diff --git a/app/assets/images/emoji/nose_tone5.png b/app/assets/images/emoji/nose_tone5.png new file mode 100644 index 00000000000..7b33821f6c9 Binary files /dev/null and b/app/assets/images/emoji/nose_tone5.png differ diff --git a/app/assets/images/emoji/notebook.png b/app/assets/images/emoji/notebook.png new file mode 100644 index 00000000000..f6c28b4915d Binary files /dev/null and b/app/assets/images/emoji/notebook.png differ diff --git a/app/assets/images/emoji/notebook_with_decorative_cover.png b/app/assets/images/emoji/notebook_with_decorative_cover.png new file mode 100644 index 00000000000..03f566b6d2c Binary files /dev/null and b/app/assets/images/emoji/notebook_with_decorative_cover.png differ diff --git a/app/assets/images/emoji/notepad_spiral.png b/app/assets/images/emoji/notepad_spiral.png new file mode 100644 index 00000000000..85faa10d8ea Binary files /dev/null and b/app/assets/images/emoji/notepad_spiral.png differ diff --git a/app/assets/images/emoji/notes.png b/app/assets/images/emoji/notes.png new file mode 100644 index 00000000000..57d499aa181 Binary files /dev/null and b/app/assets/images/emoji/notes.png differ diff --git a/app/assets/images/emoji/nut_and_bolt.png b/app/assets/images/emoji/nut_and_bolt.png new file mode 100644 index 00000000000..4b9ae155319 Binary files /dev/null and b/app/assets/images/emoji/nut_and_bolt.png differ diff --git a/app/assets/images/emoji/o.png b/app/assets/images/emoji/o.png new file mode 100644 index 00000000000..3fe75ce4675 Binary files /dev/null and b/app/assets/images/emoji/o.png differ diff --git a/app/assets/images/emoji/o2.png b/app/assets/images/emoji/o2.png new file mode 100644 index 00000000000..73278ba194a Binary files /dev/null and b/app/assets/images/emoji/o2.png differ diff --git a/app/assets/images/emoji/ocean.png b/app/assets/images/emoji/ocean.png new file mode 100644 index 00000000000..45ff1e87703 Binary files /dev/null and b/app/assets/images/emoji/ocean.png differ diff --git a/app/assets/images/emoji/octagonal_sign.png b/app/assets/images/emoji/octagonal_sign.png new file mode 100644 index 00000000000..5ed61004045 Binary files /dev/null and b/app/assets/images/emoji/octagonal_sign.png differ diff --git a/app/assets/images/emoji/octopus.png b/app/assets/images/emoji/octopus.png new file mode 100644 index 00000000000..72c84074aac Binary files /dev/null and b/app/assets/images/emoji/octopus.png differ diff --git a/app/assets/images/emoji/oden.png b/app/assets/images/emoji/oden.png new file mode 100644 index 00000000000..d38a849fece Binary files /dev/null and b/app/assets/images/emoji/oden.png differ diff --git a/app/assets/images/emoji/office.png b/app/assets/images/emoji/office.png new file mode 100644 index 00000000000..7eee927d1b0 Binary files /dev/null and b/app/assets/images/emoji/office.png differ diff --git a/app/assets/images/emoji/oil.png b/app/assets/images/emoji/oil.png new file mode 100644 index 00000000000..c4c4d42da8b Binary files /dev/null and b/app/assets/images/emoji/oil.png differ diff --git a/app/assets/images/emoji/ok.png b/app/assets/images/emoji/ok.png new file mode 100644 index 00000000000..d0d775532ff Binary files /dev/null and b/app/assets/images/emoji/ok.png differ diff --git a/app/assets/images/emoji/ok_hand.png b/app/assets/images/emoji/ok_hand.png new file mode 100644 index 00000000000..028d69b0de3 Binary files /dev/null and b/app/assets/images/emoji/ok_hand.png differ diff --git a/app/assets/images/emoji/ok_hand_tone1.png b/app/assets/images/emoji/ok_hand_tone1.png new file mode 100644 index 00000000000..cecf7b2ab5a Binary files /dev/null and b/app/assets/images/emoji/ok_hand_tone1.png differ diff --git a/app/assets/images/emoji/ok_hand_tone2.png b/app/assets/images/emoji/ok_hand_tone2.png new file mode 100644 index 00000000000..c19239bcd3d Binary files /dev/null and b/app/assets/images/emoji/ok_hand_tone2.png differ diff --git a/app/assets/images/emoji/ok_hand_tone3.png b/app/assets/images/emoji/ok_hand_tone3.png new file mode 100644 index 00000000000..94b65b03ecd Binary files /dev/null and b/app/assets/images/emoji/ok_hand_tone3.png differ diff --git a/app/assets/images/emoji/ok_hand_tone4.png b/app/assets/images/emoji/ok_hand_tone4.png new file mode 100644 index 00000000000..03d26f08e6a Binary files /dev/null and b/app/assets/images/emoji/ok_hand_tone4.png differ diff --git a/app/assets/images/emoji/ok_hand_tone5.png b/app/assets/images/emoji/ok_hand_tone5.png new file mode 100644 index 00000000000..d4b24086364 Binary files /dev/null and b/app/assets/images/emoji/ok_hand_tone5.png differ diff --git a/app/assets/images/emoji/ok_woman.png b/app/assets/images/emoji/ok_woman.png new file mode 100644 index 00000000000..90a2c7469c4 Binary files /dev/null and b/app/assets/images/emoji/ok_woman.png differ diff --git a/app/assets/images/emoji/ok_woman_tone1.png b/app/assets/images/emoji/ok_woman_tone1.png new file mode 100644 index 00000000000..c99543e785b Binary files /dev/null and b/app/assets/images/emoji/ok_woman_tone1.png differ diff --git a/app/assets/images/emoji/ok_woman_tone2.png b/app/assets/images/emoji/ok_woman_tone2.png new file mode 100644 index 00000000000..ad5fae813db Binary files /dev/null and b/app/assets/images/emoji/ok_woman_tone2.png differ diff --git a/app/assets/images/emoji/ok_woman_tone3.png b/app/assets/images/emoji/ok_woman_tone3.png new file mode 100644 index 00000000000..51bf4fab406 Binary files /dev/null and b/app/assets/images/emoji/ok_woman_tone3.png differ diff --git a/app/assets/images/emoji/ok_woman_tone4.png b/app/assets/images/emoji/ok_woman_tone4.png new file mode 100644 index 00000000000..ee3f9dc640a Binary files /dev/null and b/app/assets/images/emoji/ok_woman_tone4.png differ diff --git a/app/assets/images/emoji/ok_woman_tone5.png b/app/assets/images/emoji/ok_woman_tone5.png new file mode 100644 index 00000000000..62a9d9237f7 Binary files /dev/null and b/app/assets/images/emoji/ok_woman_tone5.png differ diff --git a/app/assets/images/emoji/older_man.png b/app/assets/images/emoji/older_man.png new file mode 100644 index 00000000000..4ace4e6f308 Binary files /dev/null and b/app/assets/images/emoji/older_man.png differ diff --git a/app/assets/images/emoji/older_man_tone1.png b/app/assets/images/emoji/older_man_tone1.png new file mode 100644 index 00000000000..ab459baace8 Binary files /dev/null and b/app/assets/images/emoji/older_man_tone1.png differ diff --git a/app/assets/images/emoji/older_man_tone2.png b/app/assets/images/emoji/older_man_tone2.png new file mode 100644 index 00000000000..f4dfc7694ea Binary files /dev/null and b/app/assets/images/emoji/older_man_tone2.png differ diff --git a/app/assets/images/emoji/older_man_tone3.png b/app/assets/images/emoji/older_man_tone3.png new file mode 100644 index 00000000000..5ffd11792f4 Binary files /dev/null and b/app/assets/images/emoji/older_man_tone3.png differ diff --git a/app/assets/images/emoji/older_man_tone4.png b/app/assets/images/emoji/older_man_tone4.png new file mode 100644 index 00000000000..b350a764bfd Binary files /dev/null and b/app/assets/images/emoji/older_man_tone4.png differ diff --git a/app/assets/images/emoji/older_man_tone5.png b/app/assets/images/emoji/older_man_tone5.png new file mode 100644 index 00000000000..05fe24a1708 Binary files /dev/null and b/app/assets/images/emoji/older_man_tone5.png differ diff --git a/app/assets/images/emoji/older_woman.png b/app/assets/images/emoji/older_woman.png new file mode 100644 index 00000000000..52dc4987143 Binary files /dev/null and b/app/assets/images/emoji/older_woman.png differ diff --git a/app/assets/images/emoji/older_woman_tone1.png b/app/assets/images/emoji/older_woman_tone1.png new file mode 100644 index 00000000000..b49e821402c Binary files /dev/null and b/app/assets/images/emoji/older_woman_tone1.png differ diff --git a/app/assets/images/emoji/older_woman_tone2.png b/app/assets/images/emoji/older_woman_tone2.png new file mode 100644 index 00000000000..e86bf5ab3b7 Binary files /dev/null and b/app/assets/images/emoji/older_woman_tone2.png differ diff --git a/app/assets/images/emoji/older_woman_tone3.png b/app/assets/images/emoji/older_woman_tone3.png new file mode 100644 index 00000000000..83fc14b0874 Binary files /dev/null and b/app/assets/images/emoji/older_woman_tone3.png differ diff --git a/app/assets/images/emoji/older_woman_tone4.png b/app/assets/images/emoji/older_woman_tone4.png new file mode 100644 index 00000000000..e4aa8a424d4 Binary files /dev/null and b/app/assets/images/emoji/older_woman_tone4.png differ diff --git a/app/assets/images/emoji/older_woman_tone5.png b/app/assets/images/emoji/older_woman_tone5.png new file mode 100644 index 00000000000..4009012bb0a Binary files /dev/null and b/app/assets/images/emoji/older_woman_tone5.png differ diff --git a/app/assets/images/emoji/om_symbol.png b/app/assets/images/emoji/om_symbol.png new file mode 100644 index 00000000000..a35c63c459c Binary files /dev/null and b/app/assets/images/emoji/om_symbol.png differ diff --git a/app/assets/images/emoji/on.png b/app/assets/images/emoji/on.png new file mode 100644 index 00000000000..a0c371ae21e Binary files /dev/null and b/app/assets/images/emoji/on.png differ diff --git a/app/assets/images/emoji/oncoming_automobile.png b/app/assets/images/emoji/oncoming_automobile.png new file mode 100644 index 00000000000..3c7e1d52e63 Binary files /dev/null and b/app/assets/images/emoji/oncoming_automobile.png differ diff --git a/app/assets/images/emoji/oncoming_bus.png b/app/assets/images/emoji/oncoming_bus.png new file mode 100644 index 00000000000..ad91e256c7f Binary files /dev/null and b/app/assets/images/emoji/oncoming_bus.png differ diff --git a/app/assets/images/emoji/oncoming_police_car.png b/app/assets/images/emoji/oncoming_police_car.png new file mode 100644 index 00000000000..c9109c85b5d Binary files /dev/null and b/app/assets/images/emoji/oncoming_police_car.png differ diff --git a/app/assets/images/emoji/oncoming_taxi.png b/app/assets/images/emoji/oncoming_taxi.png new file mode 100644 index 00000000000..fea14e45846 Binary files /dev/null and b/app/assets/images/emoji/oncoming_taxi.png differ diff --git a/app/assets/images/emoji/one.png b/app/assets/images/emoji/one.png new file mode 100644 index 00000000000..e6d84b80128 Binary files /dev/null and b/app/assets/images/emoji/one.png differ diff --git a/app/assets/images/emoji/open_file_folder.png b/app/assets/images/emoji/open_file_folder.png new file mode 100644 index 00000000000..3993b09222f Binary files /dev/null and b/app/assets/images/emoji/open_file_folder.png differ diff --git a/app/assets/images/emoji/open_hands.png b/app/assets/images/emoji/open_hands.png new file mode 100644 index 00000000000..1cf75c9101e Binary files /dev/null and b/app/assets/images/emoji/open_hands.png differ diff --git a/app/assets/images/emoji/open_hands_tone1.png b/app/assets/images/emoji/open_hands_tone1.png new file mode 100644 index 00000000000..352d2614f11 Binary files /dev/null and b/app/assets/images/emoji/open_hands_tone1.png differ diff --git a/app/assets/images/emoji/open_hands_tone2.png b/app/assets/images/emoji/open_hands_tone2.png new file mode 100644 index 00000000000..70824a50c73 Binary files /dev/null and b/app/assets/images/emoji/open_hands_tone2.png differ diff --git a/app/assets/images/emoji/open_hands_tone3.png b/app/assets/images/emoji/open_hands_tone3.png new file mode 100644 index 00000000000..d7d136bd3db Binary files /dev/null and b/app/assets/images/emoji/open_hands_tone3.png differ diff --git a/app/assets/images/emoji/open_hands_tone4.png b/app/assets/images/emoji/open_hands_tone4.png new file mode 100644 index 00000000000..df4eaa711e7 Binary files /dev/null and b/app/assets/images/emoji/open_hands_tone4.png differ diff --git a/app/assets/images/emoji/open_hands_tone5.png b/app/assets/images/emoji/open_hands_tone5.png new file mode 100644 index 00000000000..7dc04eaebd8 Binary files /dev/null and b/app/assets/images/emoji/open_hands_tone5.png differ diff --git a/app/assets/images/emoji/open_mouth.png b/app/assets/images/emoji/open_mouth.png new file mode 100644 index 00000000000..a62cd27e148 Binary files /dev/null and b/app/assets/images/emoji/open_mouth.png differ diff --git a/app/assets/images/emoji/ophiuchus.png b/app/assets/images/emoji/ophiuchus.png new file mode 100644 index 00000000000..0a780a700da Binary files /dev/null and b/app/assets/images/emoji/ophiuchus.png differ diff --git a/app/assets/images/emoji/orange_book.png b/app/assets/images/emoji/orange_book.png new file mode 100644 index 00000000000..ab40e6ae6a2 Binary files /dev/null and b/app/assets/images/emoji/orange_book.png differ diff --git a/app/assets/images/emoji/orthodox_cross.png b/app/assets/images/emoji/orthodox_cross.png new file mode 100644 index 00000000000..0530e33a4d4 Binary files /dev/null and b/app/assets/images/emoji/orthodox_cross.png differ diff --git a/app/assets/images/emoji/outbox_tray.png b/app/assets/images/emoji/outbox_tray.png new file mode 100644 index 00000000000..46493ed5b2c Binary files /dev/null and b/app/assets/images/emoji/outbox_tray.png differ diff --git a/app/assets/images/emoji/owl.png b/app/assets/images/emoji/owl.png new file mode 100644 index 00000000000..fa6815480c3 Binary files /dev/null and b/app/assets/images/emoji/owl.png differ diff --git a/app/assets/images/emoji/ox.png b/app/assets/images/emoji/ox.png new file mode 100644 index 00000000000..badf5708f2f Binary files /dev/null and b/app/assets/images/emoji/ox.png differ diff --git a/app/assets/images/emoji/package.png b/app/assets/images/emoji/package.png new file mode 100644 index 00000000000..85431756ad8 Binary files /dev/null and b/app/assets/images/emoji/package.png differ diff --git a/app/assets/images/emoji/page_facing_up.png b/app/assets/images/emoji/page_facing_up.png new file mode 100644 index 00000000000..ba4ed757e01 Binary files /dev/null and b/app/assets/images/emoji/page_facing_up.png differ diff --git a/app/assets/images/emoji/page_with_curl.png b/app/assets/images/emoji/page_with_curl.png new file mode 100644 index 00000000000..06355319c74 Binary files /dev/null and b/app/assets/images/emoji/page_with_curl.png differ diff --git a/app/assets/images/emoji/pager.png b/app/assets/images/emoji/pager.png new file mode 100644 index 00000000000..b24b99306a2 Binary files /dev/null and b/app/assets/images/emoji/pager.png differ diff --git a/app/assets/images/emoji/paintbrush.png b/app/assets/images/emoji/paintbrush.png new file mode 100644 index 00000000000..28bffbaa3c9 Binary files /dev/null and b/app/assets/images/emoji/paintbrush.png differ diff --git a/app/assets/images/emoji/palm_tree.png b/app/assets/images/emoji/palm_tree.png new file mode 100644 index 00000000000..4bbb10f4f19 Binary files /dev/null and b/app/assets/images/emoji/palm_tree.png differ diff --git a/app/assets/images/emoji/pancakes.png b/app/assets/images/emoji/pancakes.png new file mode 100644 index 00000000000..6223d1a28e9 Binary files /dev/null and b/app/assets/images/emoji/pancakes.png differ diff --git a/app/assets/images/emoji/panda_face.png b/app/assets/images/emoji/panda_face.png new file mode 100644 index 00000000000..978382775ce Binary files /dev/null and b/app/assets/images/emoji/panda_face.png differ diff --git a/app/assets/images/emoji/paperclip.png b/app/assets/images/emoji/paperclip.png new file mode 100644 index 00000000000..8cd8d4f8750 Binary files /dev/null and b/app/assets/images/emoji/paperclip.png differ diff --git a/app/assets/images/emoji/paperclips.png b/app/assets/images/emoji/paperclips.png new file mode 100644 index 00000000000..76021e8c705 Binary files /dev/null and b/app/assets/images/emoji/paperclips.png differ diff --git a/app/assets/images/emoji/park.png b/app/assets/images/emoji/park.png new file mode 100644 index 00000000000..63ec7016301 Binary files /dev/null and b/app/assets/images/emoji/park.png differ diff --git a/app/assets/images/emoji/parking.png b/app/assets/images/emoji/parking.png new file mode 100644 index 00000000000..7be7dac27e8 Binary files /dev/null and b/app/assets/images/emoji/parking.png differ diff --git a/app/assets/images/emoji/part_alternation_mark.png b/app/assets/images/emoji/part_alternation_mark.png new file mode 100644 index 00000000000..70453d41528 Binary files /dev/null and b/app/assets/images/emoji/part_alternation_mark.png differ diff --git a/app/assets/images/emoji/partly_sunny.png b/app/assets/images/emoji/partly_sunny.png new file mode 100644 index 00000000000..a55e59c344c Binary files /dev/null and b/app/assets/images/emoji/partly_sunny.png differ diff --git a/app/assets/images/emoji/passport_control.png b/app/assets/images/emoji/passport_control.png new file mode 100644 index 00000000000..079e34ee4d4 Binary files /dev/null and b/app/assets/images/emoji/passport_control.png differ diff --git a/app/assets/images/emoji/pause_button.png b/app/assets/images/emoji/pause_button.png new file mode 100644 index 00000000000..4f07e7ebfd7 Binary files /dev/null and b/app/assets/images/emoji/pause_button.png differ diff --git a/app/assets/images/emoji/peace.png b/app/assets/images/emoji/peace.png new file mode 100644 index 00000000000..86033faf477 Binary files /dev/null and b/app/assets/images/emoji/peace.png differ diff --git a/app/assets/images/emoji/peach.png b/app/assets/images/emoji/peach.png new file mode 100644 index 00000000000..9ab57cbb758 Binary files /dev/null and b/app/assets/images/emoji/peach.png differ diff --git a/app/assets/images/emoji/peanuts.png b/app/assets/images/emoji/peanuts.png new file mode 100644 index 00000000000..b64fadad010 Binary files /dev/null and b/app/assets/images/emoji/peanuts.png differ diff --git a/app/assets/images/emoji/pear.png b/app/assets/images/emoji/pear.png new file mode 100644 index 00000000000..3869f718bcf Binary files /dev/null and b/app/assets/images/emoji/pear.png differ diff --git a/app/assets/images/emoji/pen_ballpoint.png b/app/assets/images/emoji/pen_ballpoint.png new file mode 100644 index 00000000000..6ef7a342433 Binary files /dev/null and b/app/assets/images/emoji/pen_ballpoint.png differ diff --git a/app/assets/images/emoji/pen_fountain.png b/app/assets/images/emoji/pen_fountain.png new file mode 100644 index 00000000000..3ca4bd2c231 Binary files /dev/null and b/app/assets/images/emoji/pen_fountain.png differ diff --git a/app/assets/images/emoji/pencil.png b/app/assets/images/emoji/pencil.png new file mode 100644 index 00000000000..edc6155e168 Binary files /dev/null and b/app/assets/images/emoji/pencil.png differ diff --git a/app/assets/images/emoji/pencil2.png b/app/assets/images/emoji/pencil2.png new file mode 100644 index 00000000000..3833d590fa2 Binary files /dev/null and b/app/assets/images/emoji/pencil2.png differ diff --git a/app/assets/images/emoji/penguin.png b/app/assets/images/emoji/penguin.png new file mode 100644 index 00000000000..c0064fb9734 Binary files /dev/null and b/app/assets/images/emoji/penguin.png differ diff --git a/app/assets/images/emoji/pensive.png b/app/assets/images/emoji/pensive.png new file mode 100644 index 00000000000..490fb566954 Binary files /dev/null and b/app/assets/images/emoji/pensive.png differ diff --git a/app/assets/images/emoji/performing_arts.png b/app/assets/images/emoji/performing_arts.png new file mode 100644 index 00000000000..685441fdaa1 Binary files /dev/null and b/app/assets/images/emoji/performing_arts.png differ diff --git a/app/assets/images/emoji/persevere.png b/app/assets/images/emoji/persevere.png new file mode 100644 index 00000000000..646a05fe908 Binary files /dev/null and b/app/assets/images/emoji/persevere.png differ diff --git a/app/assets/images/emoji/person_frowning.png b/app/assets/images/emoji/person_frowning.png new file mode 100644 index 00000000000..579324959a1 Binary files /dev/null and b/app/assets/images/emoji/person_frowning.png differ diff --git a/app/assets/images/emoji/person_frowning_tone1.png b/app/assets/images/emoji/person_frowning_tone1.png new file mode 100644 index 00000000000..21d3bb43923 Binary files /dev/null and b/app/assets/images/emoji/person_frowning_tone1.png differ diff --git a/app/assets/images/emoji/person_frowning_tone2.png b/app/assets/images/emoji/person_frowning_tone2.png new file mode 100644 index 00000000000..973f5fc8382 Binary files /dev/null and b/app/assets/images/emoji/person_frowning_tone2.png differ diff --git a/app/assets/images/emoji/person_frowning_tone3.png b/app/assets/images/emoji/person_frowning_tone3.png new file mode 100644 index 00000000000..41fbcc78816 Binary files /dev/null and b/app/assets/images/emoji/person_frowning_tone3.png differ diff --git a/app/assets/images/emoji/person_frowning_tone4.png b/app/assets/images/emoji/person_frowning_tone4.png new file mode 100644 index 00000000000..5a37c741030 Binary files /dev/null and b/app/assets/images/emoji/person_frowning_tone4.png differ diff --git a/app/assets/images/emoji/person_frowning_tone5.png b/app/assets/images/emoji/person_frowning_tone5.png new file mode 100644 index 00000000000..e08141f3efe Binary files /dev/null and b/app/assets/images/emoji/person_frowning_tone5.png differ diff --git a/app/assets/images/emoji/person_with_blond_hair.png b/app/assets/images/emoji/person_with_blond_hair.png new file mode 100644 index 00000000000..ad6f01a7dda Binary files /dev/null and b/app/assets/images/emoji/person_with_blond_hair.png differ diff --git a/app/assets/images/emoji/person_with_blond_hair_tone1.png b/app/assets/images/emoji/person_with_blond_hair_tone1.png new file mode 100644 index 00000000000..7d18ef24445 Binary files /dev/null and b/app/assets/images/emoji/person_with_blond_hair_tone1.png differ diff --git a/app/assets/images/emoji/person_with_blond_hair_tone2.png b/app/assets/images/emoji/person_with_blond_hair_tone2.png new file mode 100644 index 00000000000..dae1307315c Binary files /dev/null and b/app/assets/images/emoji/person_with_blond_hair_tone2.png differ diff --git a/app/assets/images/emoji/person_with_blond_hair_tone3.png b/app/assets/images/emoji/person_with_blond_hair_tone3.png new file mode 100644 index 00000000000..684677e8e5a Binary files /dev/null and b/app/assets/images/emoji/person_with_blond_hair_tone3.png differ diff --git a/app/assets/images/emoji/person_with_blond_hair_tone4.png b/app/assets/images/emoji/person_with_blond_hair_tone4.png new file mode 100644 index 00000000000..012be0b51f8 Binary files /dev/null and b/app/assets/images/emoji/person_with_blond_hair_tone4.png differ diff --git a/app/assets/images/emoji/person_with_blond_hair_tone5.png b/app/assets/images/emoji/person_with_blond_hair_tone5.png new file mode 100644 index 00000000000..d4ecc4cf44b Binary files /dev/null and b/app/assets/images/emoji/person_with_blond_hair_tone5.png differ diff --git a/app/assets/images/emoji/person_with_pouting_face.png b/app/assets/images/emoji/person_with_pouting_face.png new file mode 100644 index 00000000000..10eb0571078 Binary files /dev/null and b/app/assets/images/emoji/person_with_pouting_face.png differ diff --git a/app/assets/images/emoji/person_with_pouting_face_tone1.png b/app/assets/images/emoji/person_with_pouting_face_tone1.png new file mode 100644 index 00000000000..57e826b75a4 Binary files /dev/null and b/app/assets/images/emoji/person_with_pouting_face_tone1.png differ diff --git a/app/assets/images/emoji/person_with_pouting_face_tone2.png b/app/assets/images/emoji/person_with_pouting_face_tone2.png new file mode 100644 index 00000000000..3f317c0c25f Binary files /dev/null and b/app/assets/images/emoji/person_with_pouting_face_tone2.png differ diff --git a/app/assets/images/emoji/person_with_pouting_face_tone3.png b/app/assets/images/emoji/person_with_pouting_face_tone3.png new file mode 100644 index 00000000000..d2fbb6c20bf Binary files /dev/null and b/app/assets/images/emoji/person_with_pouting_face_tone3.png differ diff --git a/app/assets/images/emoji/person_with_pouting_face_tone4.png b/app/assets/images/emoji/person_with_pouting_face_tone4.png new file mode 100644 index 00000000000..643ceb4a5c5 Binary files /dev/null and b/app/assets/images/emoji/person_with_pouting_face_tone4.png differ diff --git a/app/assets/images/emoji/person_with_pouting_face_tone5.png b/app/assets/images/emoji/person_with_pouting_face_tone5.png new file mode 100644 index 00000000000..b2eb6859c32 Binary files /dev/null and b/app/assets/images/emoji/person_with_pouting_face_tone5.png differ diff --git a/app/assets/images/emoji/pick.png b/app/assets/images/emoji/pick.png new file mode 100644 index 00000000000..6370fe6d791 Binary files /dev/null and b/app/assets/images/emoji/pick.png differ diff --git a/app/assets/images/emoji/pig.png b/app/assets/images/emoji/pig.png new file mode 100644 index 00000000000..afe05ca1676 Binary files /dev/null and b/app/assets/images/emoji/pig.png differ diff --git a/app/assets/images/emoji/pig2.png b/app/assets/images/emoji/pig2.png new file mode 100644 index 00000000000..5f31c1a2d75 Binary files /dev/null and b/app/assets/images/emoji/pig2.png differ diff --git a/app/assets/images/emoji/pig_nose.png b/app/assets/images/emoji/pig_nose.png new file mode 100644 index 00000000000..3610ae4a910 Binary files /dev/null and b/app/assets/images/emoji/pig_nose.png differ diff --git a/app/assets/images/emoji/pill.png b/app/assets/images/emoji/pill.png new file mode 100644 index 00000000000..1d4530e77a3 Binary files /dev/null and b/app/assets/images/emoji/pill.png differ diff --git a/app/assets/images/emoji/pineapple.png b/app/assets/images/emoji/pineapple.png new file mode 100644 index 00000000000..c89a1606462 Binary files /dev/null and b/app/assets/images/emoji/pineapple.png differ diff --git a/app/assets/images/emoji/ping_pong.png b/app/assets/images/emoji/ping_pong.png new file mode 100644 index 00000000000..ff3c51727d1 Binary files /dev/null and b/app/assets/images/emoji/ping_pong.png differ diff --git a/app/assets/images/emoji/pisces.png b/app/assets/images/emoji/pisces.png new file mode 100644 index 00000000000..7f6f646a95c Binary files /dev/null and b/app/assets/images/emoji/pisces.png differ diff --git a/app/assets/images/emoji/pizza.png b/app/assets/images/emoji/pizza.png new file mode 100644 index 00000000000..e07365cb398 Binary files /dev/null and b/app/assets/images/emoji/pizza.png differ diff --git a/app/assets/images/emoji/place_of_worship.png b/app/assets/images/emoji/place_of_worship.png new file mode 100644 index 00000000000..207d59cce85 Binary files /dev/null and b/app/assets/images/emoji/place_of_worship.png differ diff --git a/app/assets/images/emoji/play_pause.png b/app/assets/images/emoji/play_pause.png new file mode 100644 index 00000000000..a9f857139ac Binary files /dev/null and b/app/assets/images/emoji/play_pause.png differ diff --git a/app/assets/images/emoji/point_down.png b/app/assets/images/emoji/point_down.png new file mode 100644 index 00000000000..00d3d13ab5c Binary files /dev/null and b/app/assets/images/emoji/point_down.png differ diff --git a/app/assets/images/emoji/point_down_tone1.png b/app/assets/images/emoji/point_down_tone1.png new file mode 100644 index 00000000000..140f157d8c7 Binary files /dev/null and b/app/assets/images/emoji/point_down_tone1.png differ diff --git a/app/assets/images/emoji/point_down_tone2.png b/app/assets/images/emoji/point_down_tone2.png new file mode 100644 index 00000000000..d518544f7fa Binary files /dev/null and b/app/assets/images/emoji/point_down_tone2.png differ diff --git a/app/assets/images/emoji/point_down_tone3.png b/app/assets/images/emoji/point_down_tone3.png new file mode 100644 index 00000000000..018b688b8b7 Binary files /dev/null and b/app/assets/images/emoji/point_down_tone3.png differ diff --git a/app/assets/images/emoji/point_down_tone4.png b/app/assets/images/emoji/point_down_tone4.png new file mode 100644 index 00000000000..98845bf6f72 Binary files /dev/null and b/app/assets/images/emoji/point_down_tone4.png differ diff --git a/app/assets/images/emoji/point_down_tone5.png b/app/assets/images/emoji/point_down_tone5.png new file mode 100644 index 00000000000..9a9b039a9fc Binary files /dev/null and b/app/assets/images/emoji/point_down_tone5.png differ diff --git a/app/assets/images/emoji/point_left.png b/app/assets/images/emoji/point_left.png new file mode 100644 index 00000000000..599fa2e3cf1 Binary files /dev/null and b/app/assets/images/emoji/point_left.png differ diff --git a/app/assets/images/emoji/point_left_tone1.png b/app/assets/images/emoji/point_left_tone1.png new file mode 100644 index 00000000000..88e2c306076 Binary files /dev/null and b/app/assets/images/emoji/point_left_tone1.png differ diff --git a/app/assets/images/emoji/point_left_tone2.png b/app/assets/images/emoji/point_left_tone2.png new file mode 100644 index 00000000000..d3c89d87c5f Binary files /dev/null and b/app/assets/images/emoji/point_left_tone2.png differ diff --git a/app/assets/images/emoji/point_left_tone3.png b/app/assets/images/emoji/point_left_tone3.png new file mode 100644 index 00000000000..b23b9167358 Binary files /dev/null and b/app/assets/images/emoji/point_left_tone3.png differ diff --git a/app/assets/images/emoji/point_left_tone4.png b/app/assets/images/emoji/point_left_tone4.png new file mode 100644 index 00000000000..3093f325c27 Binary files /dev/null and b/app/assets/images/emoji/point_left_tone4.png differ diff --git a/app/assets/images/emoji/point_left_tone5.png b/app/assets/images/emoji/point_left_tone5.png new file mode 100644 index 00000000000..2b4cbfa120c Binary files /dev/null and b/app/assets/images/emoji/point_left_tone5.png differ diff --git a/app/assets/images/emoji/point_right.png b/app/assets/images/emoji/point_right.png new file mode 100644 index 00000000000..93a3cd34aa5 Binary files /dev/null and b/app/assets/images/emoji/point_right.png differ diff --git a/app/assets/images/emoji/point_right_tone1.png b/app/assets/images/emoji/point_right_tone1.png new file mode 100644 index 00000000000..4a28c6bbc89 Binary files /dev/null and b/app/assets/images/emoji/point_right_tone1.png differ diff --git a/app/assets/images/emoji/point_right_tone2.png b/app/assets/images/emoji/point_right_tone2.png new file mode 100644 index 00000000000..7cb13231733 Binary files /dev/null and b/app/assets/images/emoji/point_right_tone2.png differ diff --git a/app/assets/images/emoji/point_right_tone3.png b/app/assets/images/emoji/point_right_tone3.png new file mode 100644 index 00000000000..5514807d71a Binary files /dev/null and b/app/assets/images/emoji/point_right_tone3.png differ diff --git a/app/assets/images/emoji/point_right_tone4.png b/app/assets/images/emoji/point_right_tone4.png new file mode 100644 index 00000000000..b8541d6440d Binary files /dev/null and b/app/assets/images/emoji/point_right_tone4.png differ diff --git a/app/assets/images/emoji/point_right_tone5.png b/app/assets/images/emoji/point_right_tone5.png new file mode 100644 index 00000000000..1b7aab07bb1 Binary files /dev/null and b/app/assets/images/emoji/point_right_tone5.png differ diff --git a/app/assets/images/emoji/point_up.png b/app/assets/images/emoji/point_up.png new file mode 100644 index 00000000000..f4978ff0f00 Binary files /dev/null and b/app/assets/images/emoji/point_up.png differ diff --git a/app/assets/images/emoji/point_up_2.png b/app/assets/images/emoji/point_up_2.png new file mode 100644 index 00000000000..bc496dfeae4 Binary files /dev/null and b/app/assets/images/emoji/point_up_2.png differ diff --git a/app/assets/images/emoji/point_up_2_tone1.png b/app/assets/images/emoji/point_up_2_tone1.png new file mode 100644 index 00000000000..a12a7e78430 Binary files /dev/null and b/app/assets/images/emoji/point_up_2_tone1.png differ diff --git a/app/assets/images/emoji/point_up_2_tone2.png b/app/assets/images/emoji/point_up_2_tone2.png new file mode 100644 index 00000000000..cdff40ceab0 Binary files /dev/null and b/app/assets/images/emoji/point_up_2_tone2.png differ diff --git a/app/assets/images/emoji/point_up_2_tone3.png b/app/assets/images/emoji/point_up_2_tone3.png new file mode 100644 index 00000000000..a07ce9e5ae8 Binary files /dev/null and b/app/assets/images/emoji/point_up_2_tone3.png differ diff --git a/app/assets/images/emoji/point_up_2_tone4.png b/app/assets/images/emoji/point_up_2_tone4.png new file mode 100644 index 00000000000..4f86c88ba42 Binary files /dev/null and b/app/assets/images/emoji/point_up_2_tone4.png differ diff --git a/app/assets/images/emoji/point_up_2_tone5.png b/app/assets/images/emoji/point_up_2_tone5.png new file mode 100644 index 00000000000..ed1b26c35d3 Binary files /dev/null and b/app/assets/images/emoji/point_up_2_tone5.png differ diff --git a/app/assets/images/emoji/point_up_tone1.png b/app/assets/images/emoji/point_up_tone1.png new file mode 100644 index 00000000000..6a9db21d64c Binary files /dev/null and b/app/assets/images/emoji/point_up_tone1.png differ diff --git a/app/assets/images/emoji/point_up_tone2.png b/app/assets/images/emoji/point_up_tone2.png new file mode 100644 index 00000000000..15aa9ea0e05 Binary files /dev/null and b/app/assets/images/emoji/point_up_tone2.png differ diff --git a/app/assets/images/emoji/point_up_tone3.png b/app/assets/images/emoji/point_up_tone3.png new file mode 100644 index 00000000000..652b73a9c5d Binary files /dev/null and b/app/assets/images/emoji/point_up_tone3.png differ diff --git a/app/assets/images/emoji/point_up_tone4.png b/app/assets/images/emoji/point_up_tone4.png new file mode 100644 index 00000000000..692bad926e9 Binary files /dev/null and b/app/assets/images/emoji/point_up_tone4.png differ diff --git a/app/assets/images/emoji/point_up_tone5.png b/app/assets/images/emoji/point_up_tone5.png new file mode 100644 index 00000000000..1e1b10fb71c Binary files /dev/null and b/app/assets/images/emoji/point_up_tone5.png differ diff --git a/app/assets/images/emoji/police_car.png b/app/assets/images/emoji/police_car.png new file mode 100644 index 00000000000..3da4253de7e Binary files /dev/null and b/app/assets/images/emoji/police_car.png differ diff --git a/app/assets/images/emoji/poodle.png b/app/assets/images/emoji/poodle.png new file mode 100644 index 00000000000..8ec39e396af Binary files /dev/null and b/app/assets/images/emoji/poodle.png differ diff --git a/app/assets/images/emoji/poop.png b/app/assets/images/emoji/poop.png new file mode 100644 index 00000000000..10b15e72d56 Binary files /dev/null and b/app/assets/images/emoji/poop.png differ diff --git a/app/assets/images/emoji/popcorn.png b/app/assets/images/emoji/popcorn.png new file mode 100644 index 00000000000..36853e381d4 Binary files /dev/null and b/app/assets/images/emoji/popcorn.png differ diff --git a/app/assets/images/emoji/post_office.png b/app/assets/images/emoji/post_office.png new file mode 100644 index 00000000000..a23848f9aa0 Binary files /dev/null and b/app/assets/images/emoji/post_office.png differ diff --git a/app/assets/images/emoji/postal_horn.png b/app/assets/images/emoji/postal_horn.png new file mode 100644 index 00000000000..c173b8dbd67 Binary files /dev/null and b/app/assets/images/emoji/postal_horn.png differ diff --git a/app/assets/images/emoji/postbox.png b/app/assets/images/emoji/postbox.png new file mode 100644 index 00000000000..07c9c4ab3d6 Binary files /dev/null and b/app/assets/images/emoji/postbox.png differ diff --git a/app/assets/images/emoji/potable_water.png b/app/assets/images/emoji/potable_water.png new file mode 100644 index 00000000000..2c610049459 Binary files /dev/null and b/app/assets/images/emoji/potable_water.png differ diff --git a/app/assets/images/emoji/potato.png b/app/assets/images/emoji/potato.png new file mode 100644 index 00000000000..70350ca2c0a Binary files /dev/null and b/app/assets/images/emoji/potato.png differ diff --git a/app/assets/images/emoji/pouch.png b/app/assets/images/emoji/pouch.png new file mode 100644 index 00000000000..8795c6c66ff Binary files /dev/null and b/app/assets/images/emoji/pouch.png differ diff --git a/app/assets/images/emoji/poultry_leg.png b/app/assets/images/emoji/poultry_leg.png new file mode 100644 index 00000000000..eea4a53a2f9 Binary files /dev/null and b/app/assets/images/emoji/poultry_leg.png differ diff --git a/app/assets/images/emoji/pound.png b/app/assets/images/emoji/pound.png new file mode 100644 index 00000000000..a0d4c4099e9 Binary files /dev/null and b/app/assets/images/emoji/pound.png differ diff --git a/app/assets/images/emoji/pouting_cat.png b/app/assets/images/emoji/pouting_cat.png new file mode 100644 index 00000000000..41ddfeab42b Binary files /dev/null and b/app/assets/images/emoji/pouting_cat.png differ diff --git a/app/assets/images/emoji/pray.png b/app/assets/images/emoji/pray.png new file mode 100644 index 00000000000..8347f2435be Binary files /dev/null and b/app/assets/images/emoji/pray.png differ diff --git a/app/assets/images/emoji/pray_tone1.png b/app/assets/images/emoji/pray_tone1.png new file mode 100644 index 00000000000..060ef257172 Binary files /dev/null and b/app/assets/images/emoji/pray_tone1.png differ diff --git a/app/assets/images/emoji/pray_tone2.png b/app/assets/images/emoji/pray_tone2.png new file mode 100644 index 00000000000..56dc607c07a Binary files /dev/null and b/app/assets/images/emoji/pray_tone2.png differ diff --git a/app/assets/images/emoji/pray_tone3.png b/app/assets/images/emoji/pray_tone3.png new file mode 100644 index 00000000000..0f33b862008 Binary files /dev/null and b/app/assets/images/emoji/pray_tone3.png differ diff --git a/app/assets/images/emoji/pray_tone4.png b/app/assets/images/emoji/pray_tone4.png new file mode 100644 index 00000000000..2ea8dc11657 Binary files /dev/null and b/app/assets/images/emoji/pray_tone4.png differ diff --git a/app/assets/images/emoji/pray_tone5.png b/app/assets/images/emoji/pray_tone5.png new file mode 100644 index 00000000000..2128a6c4703 Binary files /dev/null and b/app/assets/images/emoji/pray_tone5.png differ diff --git a/app/assets/images/emoji/prayer_beads.png b/app/assets/images/emoji/prayer_beads.png new file mode 100644 index 00000000000..a4b6dfcc62e Binary files /dev/null and b/app/assets/images/emoji/prayer_beads.png differ diff --git a/app/assets/images/emoji/pregnant_woman.png b/app/assets/images/emoji/pregnant_woman.png new file mode 100644 index 00000000000..084e83a414a Binary files /dev/null and b/app/assets/images/emoji/pregnant_woman.png differ diff --git a/app/assets/images/emoji/pregnant_woman_tone1.png b/app/assets/images/emoji/pregnant_woman_tone1.png new file mode 100644 index 00000000000..a78703b33aa Binary files /dev/null and b/app/assets/images/emoji/pregnant_woman_tone1.png differ diff --git a/app/assets/images/emoji/pregnant_woman_tone2.png b/app/assets/images/emoji/pregnant_woman_tone2.png new file mode 100644 index 00000000000..0068c6c4a77 Binary files /dev/null and b/app/assets/images/emoji/pregnant_woman_tone2.png differ diff --git a/app/assets/images/emoji/pregnant_woman_tone3.png b/app/assets/images/emoji/pregnant_woman_tone3.png new file mode 100644 index 00000000000..3206296b684 Binary files /dev/null and b/app/assets/images/emoji/pregnant_woman_tone3.png differ diff --git a/app/assets/images/emoji/pregnant_woman_tone4.png b/app/assets/images/emoji/pregnant_woman_tone4.png new file mode 100644 index 00000000000..120fda5cd8c Binary files /dev/null and b/app/assets/images/emoji/pregnant_woman_tone4.png differ diff --git a/app/assets/images/emoji/pregnant_woman_tone5.png b/app/assets/images/emoji/pregnant_woman_tone5.png new file mode 100644 index 00000000000..569bfdf05ce Binary files /dev/null and b/app/assets/images/emoji/pregnant_woman_tone5.png differ diff --git a/app/assets/images/emoji/prince.png b/app/assets/images/emoji/prince.png new file mode 100644 index 00000000000..38d69344c84 Binary files /dev/null and b/app/assets/images/emoji/prince.png differ diff --git a/app/assets/images/emoji/prince_tone1.png b/app/assets/images/emoji/prince_tone1.png new file mode 100644 index 00000000000..849930c8887 Binary files /dev/null and b/app/assets/images/emoji/prince_tone1.png differ diff --git a/app/assets/images/emoji/prince_tone2.png b/app/assets/images/emoji/prince_tone2.png new file mode 100644 index 00000000000..23d8b3b1285 Binary files /dev/null and b/app/assets/images/emoji/prince_tone2.png differ diff --git a/app/assets/images/emoji/prince_tone3.png b/app/assets/images/emoji/prince_tone3.png new file mode 100644 index 00000000000..db6dfff0647 Binary files /dev/null and b/app/assets/images/emoji/prince_tone3.png differ diff --git a/app/assets/images/emoji/prince_tone4.png b/app/assets/images/emoji/prince_tone4.png new file mode 100644 index 00000000000..8e10f8be6a8 Binary files /dev/null and b/app/assets/images/emoji/prince_tone4.png differ diff --git a/app/assets/images/emoji/prince_tone5.png b/app/assets/images/emoji/prince_tone5.png new file mode 100644 index 00000000000..138d4ea7048 Binary files /dev/null and b/app/assets/images/emoji/prince_tone5.png differ diff --git a/app/assets/images/emoji/princess.png b/app/assets/images/emoji/princess.png new file mode 100644 index 00000000000..879e9fa8c5d Binary files /dev/null and b/app/assets/images/emoji/princess.png differ diff --git a/app/assets/images/emoji/princess_tone1.png b/app/assets/images/emoji/princess_tone1.png new file mode 100644 index 00000000000..c28078cdc36 Binary files /dev/null and b/app/assets/images/emoji/princess_tone1.png differ diff --git a/app/assets/images/emoji/princess_tone2.png b/app/assets/images/emoji/princess_tone2.png new file mode 100644 index 00000000000..dcd20e6ecd4 Binary files /dev/null and b/app/assets/images/emoji/princess_tone2.png differ diff --git a/app/assets/images/emoji/princess_tone3.png b/app/assets/images/emoji/princess_tone3.png new file mode 100644 index 00000000000..cde6f315c56 Binary files /dev/null and b/app/assets/images/emoji/princess_tone3.png differ diff --git a/app/assets/images/emoji/princess_tone4.png b/app/assets/images/emoji/princess_tone4.png new file mode 100644 index 00000000000..c71e69caaef Binary files /dev/null and b/app/assets/images/emoji/princess_tone4.png differ diff --git a/app/assets/images/emoji/princess_tone5.png b/app/assets/images/emoji/princess_tone5.png new file mode 100644 index 00000000000..063e2645910 Binary files /dev/null and b/app/assets/images/emoji/princess_tone5.png differ diff --git a/app/assets/images/emoji/printer.png b/app/assets/images/emoji/printer.png new file mode 100644 index 00000000000..027c830f0fe Binary files /dev/null and b/app/assets/images/emoji/printer.png differ diff --git a/app/assets/images/emoji/projector.png b/app/assets/images/emoji/projector.png new file mode 100644 index 00000000000..ce9ab0daa28 Binary files /dev/null and b/app/assets/images/emoji/projector.png differ diff --git a/app/assets/images/emoji/punch.png b/app/assets/images/emoji/punch.png new file mode 100644 index 00000000000..b14ca5f5211 Binary files /dev/null and b/app/assets/images/emoji/punch.png differ diff --git a/app/assets/images/emoji/punch_tone1.png b/app/assets/images/emoji/punch_tone1.png new file mode 100644 index 00000000000..93c7d17fb47 Binary files /dev/null and b/app/assets/images/emoji/punch_tone1.png differ diff --git a/app/assets/images/emoji/punch_tone2.png b/app/assets/images/emoji/punch_tone2.png new file mode 100644 index 00000000000..c0a1af6e10a Binary files /dev/null and b/app/assets/images/emoji/punch_tone2.png differ diff --git a/app/assets/images/emoji/punch_tone3.png b/app/assets/images/emoji/punch_tone3.png new file mode 100644 index 00000000000..1458b021201 Binary files /dev/null and b/app/assets/images/emoji/punch_tone3.png differ diff --git a/app/assets/images/emoji/punch_tone4.png b/app/assets/images/emoji/punch_tone4.png new file mode 100644 index 00000000000..c1466bfcdef Binary files /dev/null and b/app/assets/images/emoji/punch_tone4.png differ diff --git a/app/assets/images/emoji/punch_tone5.png b/app/assets/images/emoji/punch_tone5.png new file mode 100644 index 00000000000..00b4ddb8953 Binary files /dev/null and b/app/assets/images/emoji/punch_tone5.png differ diff --git a/app/assets/images/emoji/purple_heart.png b/app/assets/images/emoji/purple_heart.png new file mode 100644 index 00000000000..95c53a9ade6 Binary files /dev/null and b/app/assets/images/emoji/purple_heart.png differ diff --git a/app/assets/images/emoji/purse.png b/app/assets/images/emoji/purse.png new file mode 100644 index 00000000000..981346193c5 Binary files /dev/null and b/app/assets/images/emoji/purse.png differ diff --git a/app/assets/images/emoji/pushpin.png b/app/assets/images/emoji/pushpin.png new file mode 100644 index 00000000000..57e07d7f4cc Binary files /dev/null and b/app/assets/images/emoji/pushpin.png differ diff --git a/app/assets/images/emoji/put_litter_in_its_place.png b/app/assets/images/emoji/put_litter_in_its_place.png new file mode 100644 index 00000000000..82a84f9a375 Binary files /dev/null and b/app/assets/images/emoji/put_litter_in_its_place.png differ diff --git a/app/assets/images/emoji/question.png b/app/assets/images/emoji/question.png new file mode 100644 index 00000000000..5a58f3458aa Binary files /dev/null and b/app/assets/images/emoji/question.png differ diff --git a/app/assets/images/emoji/rabbit.png b/app/assets/images/emoji/rabbit.png new file mode 100644 index 00000000000..ea75ab0426e Binary files /dev/null and b/app/assets/images/emoji/rabbit.png differ diff --git a/app/assets/images/emoji/rabbit2.png b/app/assets/images/emoji/rabbit2.png new file mode 100644 index 00000000000..2c8a29c642f Binary files /dev/null and b/app/assets/images/emoji/rabbit2.png differ diff --git a/app/assets/images/emoji/race_car.png b/app/assets/images/emoji/race_car.png new file mode 100644 index 00000000000..fe3f045f446 Binary files /dev/null and b/app/assets/images/emoji/race_car.png differ diff --git a/app/assets/images/emoji/racehorse.png b/app/assets/images/emoji/racehorse.png new file mode 100644 index 00000000000..b3e73cc8903 Binary files /dev/null and b/app/assets/images/emoji/racehorse.png differ diff --git a/app/assets/images/emoji/radio.png b/app/assets/images/emoji/radio.png new file mode 100644 index 00000000000..dec381fa242 Binary files /dev/null and b/app/assets/images/emoji/radio.png differ diff --git a/app/assets/images/emoji/radio_button.png b/app/assets/images/emoji/radio_button.png new file mode 100644 index 00000000000..3a23449d917 Binary files /dev/null and b/app/assets/images/emoji/radio_button.png differ diff --git a/app/assets/images/emoji/radioactive.png b/app/assets/images/emoji/radioactive.png new file mode 100644 index 00000000000..3b46199fe37 Binary files /dev/null and b/app/assets/images/emoji/radioactive.png differ diff --git a/app/assets/images/emoji/rage.png b/app/assets/images/emoji/rage.png new file mode 100644 index 00000000000..9d739bd40ad Binary files /dev/null and b/app/assets/images/emoji/rage.png differ diff --git a/app/assets/images/emoji/railway_car.png b/app/assets/images/emoji/railway_car.png new file mode 100644 index 00000000000..a9acbf13008 Binary files /dev/null and b/app/assets/images/emoji/railway_car.png differ diff --git a/app/assets/images/emoji/railway_track.png b/app/assets/images/emoji/railway_track.png new file mode 100644 index 00000000000..e1a7a0d1430 Binary files /dev/null and b/app/assets/images/emoji/railway_track.png differ diff --git a/app/assets/images/emoji/rainbow.png b/app/assets/images/emoji/rainbow.png new file mode 100644 index 00000000000..154735d7147 Binary files /dev/null and b/app/assets/images/emoji/rainbow.png differ diff --git a/app/assets/images/emoji/raised_back_of_hand.png b/app/assets/images/emoji/raised_back_of_hand.png new file mode 100644 index 00000000000..479234294b4 Binary files /dev/null and b/app/assets/images/emoji/raised_back_of_hand.png differ diff --git a/app/assets/images/emoji/raised_back_of_hand_tone1.png b/app/assets/images/emoji/raised_back_of_hand_tone1.png new file mode 100644 index 00000000000..813d28499b5 Binary files /dev/null and b/app/assets/images/emoji/raised_back_of_hand_tone1.png differ diff --git a/app/assets/images/emoji/raised_back_of_hand_tone2.png b/app/assets/images/emoji/raised_back_of_hand_tone2.png new file mode 100644 index 00000000000..192ff795e37 Binary files /dev/null and b/app/assets/images/emoji/raised_back_of_hand_tone2.png differ diff --git a/app/assets/images/emoji/raised_back_of_hand_tone3.png b/app/assets/images/emoji/raised_back_of_hand_tone3.png new file mode 100644 index 00000000000..61a727abe6b Binary files /dev/null and b/app/assets/images/emoji/raised_back_of_hand_tone3.png differ diff --git a/app/assets/images/emoji/raised_back_of_hand_tone4.png b/app/assets/images/emoji/raised_back_of_hand_tone4.png new file mode 100644 index 00000000000..2e83da511f5 Binary files /dev/null and b/app/assets/images/emoji/raised_back_of_hand_tone4.png differ diff --git a/app/assets/images/emoji/raised_back_of_hand_tone5.png b/app/assets/images/emoji/raised_back_of_hand_tone5.png new file mode 100644 index 00000000000..d7a5b95a02c Binary files /dev/null and b/app/assets/images/emoji/raised_back_of_hand_tone5.png differ diff --git a/app/assets/images/emoji/raised_hand.png b/app/assets/images/emoji/raised_hand.png new file mode 100644 index 00000000000..6b2954315d1 Binary files /dev/null and b/app/assets/images/emoji/raised_hand.png differ diff --git a/app/assets/images/emoji/raised_hand_tone1.png b/app/assets/images/emoji/raised_hand_tone1.png new file mode 100644 index 00000000000..3b752902c07 Binary files /dev/null and b/app/assets/images/emoji/raised_hand_tone1.png differ diff --git a/app/assets/images/emoji/raised_hand_tone2.png b/app/assets/images/emoji/raised_hand_tone2.png new file mode 100644 index 00000000000..44e2a514c60 Binary files /dev/null and b/app/assets/images/emoji/raised_hand_tone2.png differ diff --git a/app/assets/images/emoji/raised_hand_tone3.png b/app/assets/images/emoji/raised_hand_tone3.png new file mode 100644 index 00000000000..5bb62a7528a Binary files /dev/null and b/app/assets/images/emoji/raised_hand_tone3.png differ diff --git a/app/assets/images/emoji/raised_hand_tone4.png b/app/assets/images/emoji/raised_hand_tone4.png new file mode 100644 index 00000000000..c7f8c9ec270 Binary files /dev/null and b/app/assets/images/emoji/raised_hand_tone4.png differ diff --git a/app/assets/images/emoji/raised_hand_tone5.png b/app/assets/images/emoji/raised_hand_tone5.png new file mode 100644 index 00000000000..c601b58a73e Binary files /dev/null and b/app/assets/images/emoji/raised_hand_tone5.png differ diff --git a/app/assets/images/emoji/raised_hands.png b/app/assets/images/emoji/raised_hands.png new file mode 100644 index 00000000000..c0155f728e7 Binary files /dev/null and b/app/assets/images/emoji/raised_hands.png differ diff --git a/app/assets/images/emoji/raised_hands_tone1.png b/app/assets/images/emoji/raised_hands_tone1.png new file mode 100644 index 00000000000..1168b8236b6 Binary files /dev/null and b/app/assets/images/emoji/raised_hands_tone1.png differ diff --git a/app/assets/images/emoji/raised_hands_tone2.png b/app/assets/images/emoji/raised_hands_tone2.png new file mode 100644 index 00000000000..322de622903 Binary files /dev/null and b/app/assets/images/emoji/raised_hands_tone2.png differ diff --git a/app/assets/images/emoji/raised_hands_tone3.png b/app/assets/images/emoji/raised_hands_tone3.png new file mode 100644 index 00000000000..2aa24e05ae1 Binary files /dev/null and b/app/assets/images/emoji/raised_hands_tone3.png differ diff --git a/app/assets/images/emoji/raised_hands_tone4.png b/app/assets/images/emoji/raised_hands_tone4.png new file mode 100644 index 00000000000..f31bf0db992 Binary files /dev/null and b/app/assets/images/emoji/raised_hands_tone4.png differ diff --git a/app/assets/images/emoji/raised_hands_tone5.png b/app/assets/images/emoji/raised_hands_tone5.png new file mode 100644 index 00000000000..5e95067f98b Binary files /dev/null and b/app/assets/images/emoji/raised_hands_tone5.png differ diff --git a/app/assets/images/emoji/raising_hand.png b/app/assets/images/emoji/raising_hand.png new file mode 100644 index 00000000000..2880708c0cc Binary files /dev/null and b/app/assets/images/emoji/raising_hand.png differ diff --git a/app/assets/images/emoji/raising_hand_tone1.png b/app/assets/images/emoji/raising_hand_tone1.png new file mode 100644 index 00000000000..1c90e3e2689 Binary files /dev/null and b/app/assets/images/emoji/raising_hand_tone1.png differ diff --git a/app/assets/images/emoji/raising_hand_tone2.png b/app/assets/images/emoji/raising_hand_tone2.png new file mode 100644 index 00000000000..82c3ef2bfc5 Binary files /dev/null and b/app/assets/images/emoji/raising_hand_tone2.png differ diff --git a/app/assets/images/emoji/raising_hand_tone3.png b/app/assets/images/emoji/raising_hand_tone3.png new file mode 100644 index 00000000000..1b1da2aa0ca Binary files /dev/null and b/app/assets/images/emoji/raising_hand_tone3.png differ diff --git a/app/assets/images/emoji/raising_hand_tone4.png b/app/assets/images/emoji/raising_hand_tone4.png new file mode 100644 index 00000000000..e453855c01f Binary files /dev/null and b/app/assets/images/emoji/raising_hand_tone4.png differ diff --git a/app/assets/images/emoji/raising_hand_tone5.png b/app/assets/images/emoji/raising_hand_tone5.png new file mode 100644 index 00000000000..b86200fd844 Binary files /dev/null and b/app/assets/images/emoji/raising_hand_tone5.png differ diff --git a/app/assets/images/emoji/ram.png b/app/assets/images/emoji/ram.png new file mode 100644 index 00000000000..52a44464c9b Binary files /dev/null and b/app/assets/images/emoji/ram.png differ diff --git a/app/assets/images/emoji/ramen.png b/app/assets/images/emoji/ramen.png new file mode 100644 index 00000000000..c1cb7cd7384 Binary files /dev/null and b/app/assets/images/emoji/ramen.png differ diff --git a/app/assets/images/emoji/rat.png b/app/assets/images/emoji/rat.png new file mode 100644 index 00000000000..86219144f10 Binary files /dev/null and b/app/assets/images/emoji/rat.png differ diff --git a/app/assets/images/emoji/record_button.png b/app/assets/images/emoji/record_button.png new file mode 100644 index 00000000000..ada52830fce Binary files /dev/null and b/app/assets/images/emoji/record_button.png differ diff --git a/app/assets/images/emoji/recycle.png b/app/assets/images/emoji/recycle.png new file mode 100644 index 00000000000..9221f095c37 Binary files /dev/null and b/app/assets/images/emoji/recycle.png differ diff --git a/app/assets/images/emoji/red_car.png b/app/assets/images/emoji/red_car.png new file mode 100644 index 00000000000..b3e6a774dea Binary files /dev/null and b/app/assets/images/emoji/red_car.png differ diff --git a/app/assets/images/emoji/red_circle.png b/app/assets/images/emoji/red_circle.png new file mode 100644 index 00000000000..4bef930d92f Binary files /dev/null and b/app/assets/images/emoji/red_circle.png differ diff --git a/app/assets/images/emoji/registered.png b/app/assets/images/emoji/registered.png new file mode 100644 index 00000000000..53ef9f2d4e6 Binary files /dev/null and b/app/assets/images/emoji/registered.png differ diff --git a/app/assets/images/emoji/relaxed.png b/app/assets/images/emoji/relaxed.png new file mode 100644 index 00000000000..e9e53c03d45 Binary files /dev/null and b/app/assets/images/emoji/relaxed.png differ diff --git a/app/assets/images/emoji/relieved.png b/app/assets/images/emoji/relieved.png new file mode 100644 index 00000000000..715ad0bf53f Binary files /dev/null and b/app/assets/images/emoji/relieved.png differ diff --git a/app/assets/images/emoji/reminder_ribbon.png b/app/assets/images/emoji/reminder_ribbon.png new file mode 100644 index 00000000000..3988bbd094c Binary files /dev/null and b/app/assets/images/emoji/reminder_ribbon.png differ diff --git a/app/assets/images/emoji/repeat.png b/app/assets/images/emoji/repeat.png new file mode 100644 index 00000000000..540ce4e0fba Binary files /dev/null and b/app/assets/images/emoji/repeat.png differ diff --git a/app/assets/images/emoji/repeat_one.png b/app/assets/images/emoji/repeat_one.png new file mode 100644 index 00000000000..9567e83337f Binary files /dev/null and b/app/assets/images/emoji/repeat_one.png differ diff --git a/app/assets/images/emoji/restroom.png b/app/assets/images/emoji/restroom.png new file mode 100644 index 00000000000..9588e0f0ef7 Binary files /dev/null and b/app/assets/images/emoji/restroom.png differ diff --git a/app/assets/images/emoji/revolving_hearts.png b/app/assets/images/emoji/revolving_hearts.png new file mode 100644 index 00000000000..7b9d1948f73 Binary files /dev/null and b/app/assets/images/emoji/revolving_hearts.png differ diff --git a/app/assets/images/emoji/rewind.png b/app/assets/images/emoji/rewind.png new file mode 100644 index 00000000000..e22e2bd3da5 Binary files /dev/null and b/app/assets/images/emoji/rewind.png differ diff --git a/app/assets/images/emoji/rhino.png b/app/assets/images/emoji/rhino.png new file mode 100644 index 00000000000..12f4e0d9d9b Binary files /dev/null and b/app/assets/images/emoji/rhino.png differ diff --git a/app/assets/images/emoji/ribbon.png b/app/assets/images/emoji/ribbon.png new file mode 100644 index 00000000000..0f253c3d8c8 Binary files /dev/null and b/app/assets/images/emoji/ribbon.png differ diff --git a/app/assets/images/emoji/rice.png b/app/assets/images/emoji/rice.png new file mode 100644 index 00000000000..6e3ac7956b1 Binary files /dev/null and b/app/assets/images/emoji/rice.png differ diff --git a/app/assets/images/emoji/rice_ball.png b/app/assets/images/emoji/rice_ball.png new file mode 100644 index 00000000000..d3d8ee25cb8 Binary files /dev/null and b/app/assets/images/emoji/rice_ball.png differ diff --git a/app/assets/images/emoji/rice_cracker.png b/app/assets/images/emoji/rice_cracker.png new file mode 100644 index 00000000000..7fbd08e4ff9 Binary files /dev/null and b/app/assets/images/emoji/rice_cracker.png differ diff --git a/app/assets/images/emoji/rice_scene.png b/app/assets/images/emoji/rice_scene.png new file mode 100644 index 00000000000..1a28426592a Binary files /dev/null and b/app/assets/images/emoji/rice_scene.png differ diff --git a/app/assets/images/emoji/right_facing_fist.png b/app/assets/images/emoji/right_facing_fist.png new file mode 100644 index 00000000000..754ed066d2c Binary files /dev/null and b/app/assets/images/emoji/right_facing_fist.png differ diff --git a/app/assets/images/emoji/right_facing_fist_tone1.png b/app/assets/images/emoji/right_facing_fist_tone1.png new file mode 100644 index 00000000000..33ded2f61a6 Binary files /dev/null and b/app/assets/images/emoji/right_facing_fist_tone1.png differ diff --git a/app/assets/images/emoji/right_facing_fist_tone2.png b/app/assets/images/emoji/right_facing_fist_tone2.png new file mode 100644 index 00000000000..88054e335c7 Binary files /dev/null and b/app/assets/images/emoji/right_facing_fist_tone2.png differ diff --git a/app/assets/images/emoji/right_facing_fist_tone3.png b/app/assets/images/emoji/right_facing_fist_tone3.png new file mode 100644 index 00000000000..84b9f5da7f7 Binary files /dev/null and b/app/assets/images/emoji/right_facing_fist_tone3.png differ diff --git a/app/assets/images/emoji/right_facing_fist_tone4.png b/app/assets/images/emoji/right_facing_fist_tone4.png new file mode 100644 index 00000000000..e741cfea68b Binary files /dev/null and b/app/assets/images/emoji/right_facing_fist_tone4.png differ diff --git a/app/assets/images/emoji/right_facing_fist_tone5.png b/app/assets/images/emoji/right_facing_fist_tone5.png new file mode 100644 index 00000000000..cf66d760c1f Binary files /dev/null and b/app/assets/images/emoji/right_facing_fist_tone5.png differ diff --git a/app/assets/images/emoji/ring.png b/app/assets/images/emoji/ring.png new file mode 100644 index 00000000000..87d227adb74 Binary files /dev/null and b/app/assets/images/emoji/ring.png differ diff --git a/app/assets/images/emoji/robot.png b/app/assets/images/emoji/robot.png new file mode 100644 index 00000000000..7cc62612c6a Binary files /dev/null and b/app/assets/images/emoji/robot.png differ diff --git a/app/assets/images/emoji/rocket.png b/app/assets/images/emoji/rocket.png new file mode 100644 index 00000000000..0d8da089a37 Binary files /dev/null and b/app/assets/images/emoji/rocket.png differ diff --git a/app/assets/images/emoji/rofl.png b/app/assets/images/emoji/rofl.png new file mode 100644 index 00000000000..b1736fedfeb Binary files /dev/null and b/app/assets/images/emoji/rofl.png differ diff --git a/app/assets/images/emoji/roller_coaster.png b/app/assets/images/emoji/roller_coaster.png new file mode 100644 index 00000000000..5b849e071e8 Binary files /dev/null and b/app/assets/images/emoji/roller_coaster.png differ diff --git a/app/assets/images/emoji/rolling_eyes.png b/app/assets/images/emoji/rolling_eyes.png new file mode 100644 index 00000000000..2f77b9fc3b9 Binary files /dev/null and b/app/assets/images/emoji/rolling_eyes.png differ diff --git a/app/assets/images/emoji/rooster.png b/app/assets/images/emoji/rooster.png new file mode 100644 index 00000000000..bbf2bbff97a Binary files /dev/null and b/app/assets/images/emoji/rooster.png differ diff --git a/app/assets/images/emoji/rose.png b/app/assets/images/emoji/rose.png new file mode 100644 index 00000000000..52c286d31ce Binary files /dev/null and b/app/assets/images/emoji/rose.png differ diff --git a/app/assets/images/emoji/rosette.png b/app/assets/images/emoji/rosette.png new file mode 100644 index 00000000000..8030e494bcf Binary files /dev/null and b/app/assets/images/emoji/rosette.png differ diff --git a/app/assets/images/emoji/rotating_light.png b/app/assets/images/emoji/rotating_light.png new file mode 100644 index 00000000000..cad66b0afef Binary files /dev/null and b/app/assets/images/emoji/rotating_light.png differ diff --git a/app/assets/images/emoji/round_pushpin.png b/app/assets/images/emoji/round_pushpin.png new file mode 100644 index 00000000000..28b9d72866e Binary files /dev/null and b/app/assets/images/emoji/round_pushpin.png differ diff --git a/app/assets/images/emoji/rowboat.png b/app/assets/images/emoji/rowboat.png new file mode 100644 index 00000000000..dd4dfc095d9 Binary files /dev/null and b/app/assets/images/emoji/rowboat.png differ diff --git a/app/assets/images/emoji/rowboat_tone1.png b/app/assets/images/emoji/rowboat_tone1.png new file mode 100644 index 00000000000..5e5d18548cb Binary files /dev/null and b/app/assets/images/emoji/rowboat_tone1.png differ diff --git a/app/assets/images/emoji/rowboat_tone2.png b/app/assets/images/emoji/rowboat_tone2.png new file mode 100644 index 00000000000..9b123ef8871 Binary files /dev/null and b/app/assets/images/emoji/rowboat_tone2.png differ diff --git a/app/assets/images/emoji/rowboat_tone3.png b/app/assets/images/emoji/rowboat_tone3.png new file mode 100644 index 00000000000..8ebd89a55f5 Binary files /dev/null and b/app/assets/images/emoji/rowboat_tone3.png differ diff --git a/app/assets/images/emoji/rowboat_tone4.png b/app/assets/images/emoji/rowboat_tone4.png new file mode 100644 index 00000000000..2b0d04f8725 Binary files /dev/null and b/app/assets/images/emoji/rowboat_tone4.png differ diff --git a/app/assets/images/emoji/rowboat_tone5.png b/app/assets/images/emoji/rowboat_tone5.png new file mode 100644 index 00000000000..b346f2dfc84 Binary files /dev/null and b/app/assets/images/emoji/rowboat_tone5.png differ diff --git a/app/assets/images/emoji/rugby_football.png b/app/assets/images/emoji/rugby_football.png new file mode 100644 index 00000000000..b1872273436 Binary files /dev/null and b/app/assets/images/emoji/rugby_football.png differ diff --git a/app/assets/images/emoji/runner.png b/app/assets/images/emoji/runner.png new file mode 100644 index 00000000000..e914915976a Binary files /dev/null and b/app/assets/images/emoji/runner.png differ diff --git a/app/assets/images/emoji/runner_tone1.png b/app/assets/images/emoji/runner_tone1.png new file mode 100644 index 00000000000..9355239a52d Binary files /dev/null and b/app/assets/images/emoji/runner_tone1.png differ diff --git a/app/assets/images/emoji/runner_tone2.png b/app/assets/images/emoji/runner_tone2.png new file mode 100644 index 00000000000..6112fd5c376 Binary files /dev/null and b/app/assets/images/emoji/runner_tone2.png differ diff --git a/app/assets/images/emoji/runner_tone3.png b/app/assets/images/emoji/runner_tone3.png new file mode 100644 index 00000000000..625ec708f48 Binary files /dev/null and b/app/assets/images/emoji/runner_tone3.png differ diff --git a/app/assets/images/emoji/runner_tone4.png b/app/assets/images/emoji/runner_tone4.png new file mode 100644 index 00000000000..242f1b56337 Binary files /dev/null and b/app/assets/images/emoji/runner_tone4.png differ diff --git a/app/assets/images/emoji/runner_tone5.png b/app/assets/images/emoji/runner_tone5.png new file mode 100644 index 00000000000..2976c6f019f Binary files /dev/null and b/app/assets/images/emoji/runner_tone5.png differ diff --git a/app/assets/images/emoji/running_shirt_with_sash.png b/app/assets/images/emoji/running_shirt_with_sash.png new file mode 100644 index 00000000000..6d83c06b803 Binary files /dev/null and b/app/assets/images/emoji/running_shirt_with_sash.png differ diff --git a/app/assets/images/emoji/sa.png b/app/assets/images/emoji/sa.png new file mode 100644 index 00000000000..900f9633247 Binary files /dev/null and b/app/assets/images/emoji/sa.png differ diff --git a/app/assets/images/emoji/sagittarius.png b/app/assets/images/emoji/sagittarius.png new file mode 100644 index 00000000000..f8d94ff2923 Binary files /dev/null and b/app/assets/images/emoji/sagittarius.png differ diff --git a/app/assets/images/emoji/sailboat.png b/app/assets/images/emoji/sailboat.png new file mode 100644 index 00000000000..772ef11da5d Binary files /dev/null and b/app/assets/images/emoji/sailboat.png differ diff --git a/app/assets/images/emoji/sake.png b/app/assets/images/emoji/sake.png new file mode 100644 index 00000000000..2933f5672c4 Binary files /dev/null and b/app/assets/images/emoji/sake.png differ diff --git a/app/assets/images/emoji/salad.png b/app/assets/images/emoji/salad.png new file mode 100644 index 00000000000..c89f9341158 Binary files /dev/null and b/app/assets/images/emoji/salad.png differ diff --git a/app/assets/images/emoji/sandal.png b/app/assets/images/emoji/sandal.png new file mode 100644 index 00000000000..9d9f5122b7a Binary files /dev/null and b/app/assets/images/emoji/sandal.png differ diff --git a/app/assets/images/emoji/santa.png b/app/assets/images/emoji/santa.png new file mode 100644 index 00000000000..bc83ab80d52 Binary files /dev/null and b/app/assets/images/emoji/santa.png differ diff --git a/app/assets/images/emoji/santa_tone1.png b/app/assets/images/emoji/santa_tone1.png new file mode 100644 index 00000000000..5233ffb7174 Binary files /dev/null and b/app/assets/images/emoji/santa_tone1.png differ diff --git a/app/assets/images/emoji/santa_tone2.png b/app/assets/images/emoji/santa_tone2.png new file mode 100644 index 00000000000..4e845438197 Binary files /dev/null and b/app/assets/images/emoji/santa_tone2.png differ diff --git a/app/assets/images/emoji/santa_tone3.png b/app/assets/images/emoji/santa_tone3.png new file mode 100644 index 00000000000..7fc4f33b60f Binary files /dev/null and b/app/assets/images/emoji/santa_tone3.png differ diff --git a/app/assets/images/emoji/santa_tone4.png b/app/assets/images/emoji/santa_tone4.png new file mode 100644 index 00000000000..d1d5a15132d Binary files /dev/null and b/app/assets/images/emoji/santa_tone4.png differ diff --git a/app/assets/images/emoji/santa_tone5.png b/app/assets/images/emoji/santa_tone5.png new file mode 100644 index 00000000000..4d697a01f24 Binary files /dev/null and b/app/assets/images/emoji/santa_tone5.png differ diff --git a/app/assets/images/emoji/satellite.png b/app/assets/images/emoji/satellite.png new file mode 100644 index 00000000000..db0372795f4 Binary files /dev/null and b/app/assets/images/emoji/satellite.png differ diff --git a/app/assets/images/emoji/satellite_orbital.png b/app/assets/images/emoji/satellite_orbital.png new file mode 100644 index 00000000000..4ba55d6e297 Binary files /dev/null and b/app/assets/images/emoji/satellite_orbital.png differ diff --git a/app/assets/images/emoji/saxophone.png b/app/assets/images/emoji/saxophone.png new file mode 100644 index 00000000000..a392faec291 Binary files /dev/null and b/app/assets/images/emoji/saxophone.png differ diff --git a/app/assets/images/emoji/scales.png b/app/assets/images/emoji/scales.png new file mode 100644 index 00000000000..0757eda1684 Binary files /dev/null and b/app/assets/images/emoji/scales.png differ diff --git a/app/assets/images/emoji/school.png b/app/assets/images/emoji/school.png new file mode 100644 index 00000000000..269759534f0 Binary files /dev/null and b/app/assets/images/emoji/school.png differ diff --git a/app/assets/images/emoji/school_satchel.png b/app/assets/images/emoji/school_satchel.png new file mode 100644 index 00000000000..9997c86e7dc Binary files /dev/null and b/app/assets/images/emoji/school_satchel.png differ diff --git a/app/assets/images/emoji/scissors.png b/app/assets/images/emoji/scissors.png new file mode 100644 index 00000000000..270571c8cdd Binary files /dev/null and b/app/assets/images/emoji/scissors.png differ diff --git a/app/assets/images/emoji/scooter.png b/app/assets/images/emoji/scooter.png new file mode 100644 index 00000000000..4ab7ef59cd2 Binary files /dev/null and b/app/assets/images/emoji/scooter.png differ diff --git a/app/assets/images/emoji/scorpion.png b/app/assets/images/emoji/scorpion.png new file mode 100644 index 00000000000..449a6b281c9 Binary files /dev/null and b/app/assets/images/emoji/scorpion.png differ diff --git a/app/assets/images/emoji/scorpius.png b/app/assets/images/emoji/scorpius.png new file mode 100644 index 00000000000..c31a9920455 Binary files /dev/null and b/app/assets/images/emoji/scorpius.png differ diff --git a/app/assets/images/emoji/scream.png b/app/assets/images/emoji/scream.png new file mode 100644 index 00000000000..c3bea9f2510 Binary files /dev/null and b/app/assets/images/emoji/scream.png differ diff --git a/app/assets/images/emoji/scream_cat.png b/app/assets/images/emoji/scream_cat.png new file mode 100644 index 00000000000..15803ad8e6e Binary files /dev/null and b/app/assets/images/emoji/scream_cat.png differ diff --git a/app/assets/images/emoji/scroll.png b/app/assets/images/emoji/scroll.png new file mode 100644 index 00000000000..50ee5dcd4b9 Binary files /dev/null and b/app/assets/images/emoji/scroll.png differ diff --git a/app/assets/images/emoji/seat.png b/app/assets/images/emoji/seat.png new file mode 100644 index 00000000000..a6d72d95adb Binary files /dev/null and b/app/assets/images/emoji/seat.png differ diff --git a/app/assets/images/emoji/second_place.png b/app/assets/images/emoji/second_place.png new file mode 100644 index 00000000000..17b011268b6 Binary files /dev/null and b/app/assets/images/emoji/second_place.png differ diff --git a/app/assets/images/emoji/secret.png b/app/assets/images/emoji/secret.png new file mode 100644 index 00000000000..5fd72608e60 Binary files /dev/null and b/app/assets/images/emoji/secret.png differ diff --git a/app/assets/images/emoji/see_no_evil.png b/app/assets/images/emoji/see_no_evil.png new file mode 100644 index 00000000000..5187e474531 Binary files /dev/null and b/app/assets/images/emoji/see_no_evil.png differ diff --git a/app/assets/images/emoji/seedling.png b/app/assets/images/emoji/seedling.png new file mode 100644 index 00000000000..ae0948bcfd6 Binary files /dev/null and b/app/assets/images/emoji/seedling.png differ diff --git a/app/assets/images/emoji/selfie.png b/app/assets/images/emoji/selfie.png new file mode 100644 index 00000000000..6a1ba75c7e3 Binary files /dev/null and b/app/assets/images/emoji/selfie.png differ diff --git a/app/assets/images/emoji/selfie_tone1.png b/app/assets/images/emoji/selfie_tone1.png new file mode 100644 index 00000000000..290e075b56f Binary files /dev/null and b/app/assets/images/emoji/selfie_tone1.png differ diff --git a/app/assets/images/emoji/selfie_tone2.png b/app/assets/images/emoji/selfie_tone2.png new file mode 100644 index 00000000000..fcd9595b643 Binary files /dev/null and b/app/assets/images/emoji/selfie_tone2.png differ diff --git a/app/assets/images/emoji/selfie_tone3.png b/app/assets/images/emoji/selfie_tone3.png new file mode 100644 index 00000000000..f3a22fdf435 Binary files /dev/null and b/app/assets/images/emoji/selfie_tone3.png differ diff --git a/app/assets/images/emoji/selfie_tone4.png b/app/assets/images/emoji/selfie_tone4.png new file mode 100644 index 00000000000..cdecf6d9f4e Binary files /dev/null and b/app/assets/images/emoji/selfie_tone4.png differ diff --git a/app/assets/images/emoji/selfie_tone5.png b/app/assets/images/emoji/selfie_tone5.png new file mode 100644 index 00000000000..86acbb6c202 Binary files /dev/null and b/app/assets/images/emoji/selfie_tone5.png differ diff --git a/app/assets/images/emoji/seven.png b/app/assets/images/emoji/seven.png new file mode 100644 index 00000000000..9b3476ae7c7 Binary files /dev/null and b/app/assets/images/emoji/seven.png differ diff --git a/app/assets/images/emoji/shallow_pan_of_food.png b/app/assets/images/emoji/shallow_pan_of_food.png new file mode 100644 index 00000000000..663a1006acd Binary files /dev/null and b/app/assets/images/emoji/shallow_pan_of_food.png differ diff --git a/app/assets/images/emoji/shamrock.png b/app/assets/images/emoji/shamrock.png new file mode 100644 index 00000000000..f202aecfe6f Binary files /dev/null and b/app/assets/images/emoji/shamrock.png differ diff --git a/app/assets/images/emoji/shark.png b/app/assets/images/emoji/shark.png new file mode 100644 index 00000000000..c75076d57d8 Binary files /dev/null and b/app/assets/images/emoji/shark.png differ diff --git a/app/assets/images/emoji/shaved_ice.png b/app/assets/images/emoji/shaved_ice.png new file mode 100644 index 00000000000..36dfb53ca93 Binary files /dev/null and b/app/assets/images/emoji/shaved_ice.png differ diff --git a/app/assets/images/emoji/sheep.png b/app/assets/images/emoji/sheep.png new file mode 100644 index 00000000000..102b8a52b28 Binary files /dev/null and b/app/assets/images/emoji/sheep.png differ diff --git a/app/assets/images/emoji/shell.png b/app/assets/images/emoji/shell.png new file mode 100644 index 00000000000..55721629f62 Binary files /dev/null and b/app/assets/images/emoji/shell.png differ diff --git a/app/assets/images/emoji/shield.png b/app/assets/images/emoji/shield.png new file mode 100644 index 00000000000..610bf033ce0 Binary files /dev/null and b/app/assets/images/emoji/shield.png differ diff --git a/app/assets/images/emoji/shinto_shrine.png b/app/assets/images/emoji/shinto_shrine.png new file mode 100644 index 00000000000..5a344975bf3 Binary files /dev/null and b/app/assets/images/emoji/shinto_shrine.png differ diff --git a/app/assets/images/emoji/ship.png b/app/assets/images/emoji/ship.png new file mode 100644 index 00000000000..62d54f7d6c9 Binary files /dev/null and b/app/assets/images/emoji/ship.png differ diff --git a/app/assets/images/emoji/shirt.png b/app/assets/images/emoji/shirt.png new file mode 100644 index 00000000000..af08dec8b59 Binary files /dev/null and b/app/assets/images/emoji/shirt.png differ diff --git a/app/assets/images/emoji/shopping_bags.png b/app/assets/images/emoji/shopping_bags.png new file mode 100644 index 00000000000..99f2a2b13ac Binary files /dev/null and b/app/assets/images/emoji/shopping_bags.png differ diff --git a/app/assets/images/emoji/shopping_cart.png b/app/assets/images/emoji/shopping_cart.png new file mode 100644 index 00000000000..1086fe6e456 Binary files /dev/null and b/app/assets/images/emoji/shopping_cart.png differ diff --git a/app/assets/images/emoji/shower.png b/app/assets/images/emoji/shower.png new file mode 100644 index 00000000000..156776a2e52 Binary files /dev/null and b/app/assets/images/emoji/shower.png differ diff --git a/app/assets/images/emoji/shrimp.png b/app/assets/images/emoji/shrimp.png new file mode 100644 index 00000000000..49eff28a71e Binary files /dev/null and b/app/assets/images/emoji/shrimp.png differ diff --git a/app/assets/images/emoji/shrug.png b/app/assets/images/emoji/shrug.png new file mode 100644 index 00000000000..76e63bfac77 Binary files /dev/null and b/app/assets/images/emoji/shrug.png differ diff --git a/app/assets/images/emoji/shrug_tone1.png b/app/assets/images/emoji/shrug_tone1.png new file mode 100644 index 00000000000..1c895e64468 Binary files /dev/null and b/app/assets/images/emoji/shrug_tone1.png differ diff --git a/app/assets/images/emoji/shrug_tone2.png b/app/assets/images/emoji/shrug_tone2.png new file mode 100644 index 00000000000..4e3ca8f8bac Binary files /dev/null and b/app/assets/images/emoji/shrug_tone2.png differ diff --git a/app/assets/images/emoji/shrug_tone3.png b/app/assets/images/emoji/shrug_tone3.png new file mode 100644 index 00000000000..d1b16a19bb5 Binary files /dev/null and b/app/assets/images/emoji/shrug_tone3.png differ diff --git a/app/assets/images/emoji/shrug_tone4.png b/app/assets/images/emoji/shrug_tone4.png new file mode 100644 index 00000000000..5fbef3f2255 Binary files /dev/null and b/app/assets/images/emoji/shrug_tone4.png differ diff --git a/app/assets/images/emoji/shrug_tone5.png b/app/assets/images/emoji/shrug_tone5.png new file mode 100644 index 00000000000..4af2e28bc5c Binary files /dev/null and b/app/assets/images/emoji/shrug_tone5.png differ diff --git a/app/assets/images/emoji/signal_strength.png b/app/assets/images/emoji/signal_strength.png new file mode 100644 index 00000000000..ee2b5a4b519 Binary files /dev/null and b/app/assets/images/emoji/signal_strength.png differ diff --git a/app/assets/images/emoji/six.png b/app/assets/images/emoji/six.png new file mode 100644 index 00000000000..371b3acef2c Binary files /dev/null and b/app/assets/images/emoji/six.png differ diff --git a/app/assets/images/emoji/six_pointed_star.png b/app/assets/images/emoji/six_pointed_star.png new file mode 100644 index 00000000000..2eb1707458b Binary files /dev/null and b/app/assets/images/emoji/six_pointed_star.png differ diff --git a/app/assets/images/emoji/ski.png b/app/assets/images/emoji/ski.png new file mode 100644 index 00000000000..4a2d2c12306 Binary files /dev/null and b/app/assets/images/emoji/ski.png differ diff --git a/app/assets/images/emoji/skier.png b/app/assets/images/emoji/skier.png new file mode 100644 index 00000000000..2eb3bdce2af Binary files /dev/null and b/app/assets/images/emoji/skier.png differ diff --git a/app/assets/images/emoji/skull.png b/app/assets/images/emoji/skull.png new file mode 100644 index 00000000000..26abb17296a Binary files /dev/null and b/app/assets/images/emoji/skull.png differ diff --git a/app/assets/images/emoji/skull_crossbones.png b/app/assets/images/emoji/skull_crossbones.png new file mode 100644 index 00000000000..b459df9227a Binary files /dev/null and b/app/assets/images/emoji/skull_crossbones.png differ diff --git a/app/assets/images/emoji/sleeping.png b/app/assets/images/emoji/sleeping.png new file mode 100644 index 00000000000..9ecf600d6d8 Binary files /dev/null and b/app/assets/images/emoji/sleeping.png differ diff --git a/app/assets/images/emoji/sleeping_accommodation.png b/app/assets/images/emoji/sleeping_accommodation.png new file mode 100644 index 00000000000..c739e7fb69b Binary files /dev/null and b/app/assets/images/emoji/sleeping_accommodation.png differ diff --git a/app/assets/images/emoji/sleepy.png b/app/assets/images/emoji/sleepy.png new file mode 100644 index 00000000000..836b4107717 Binary files /dev/null and b/app/assets/images/emoji/sleepy.png differ diff --git a/app/assets/images/emoji/slight_frown.png b/app/assets/images/emoji/slight_frown.png new file mode 100644 index 00000000000..b2f1d983d36 Binary files /dev/null and b/app/assets/images/emoji/slight_frown.png differ diff --git a/app/assets/images/emoji/slight_smile.png b/app/assets/images/emoji/slight_smile.png new file mode 100644 index 00000000000..ddd7d65dd3d Binary files /dev/null and b/app/assets/images/emoji/slight_smile.png differ diff --git a/app/assets/images/emoji/slot_machine.png b/app/assets/images/emoji/slot_machine.png new file mode 100644 index 00000000000..ee71b6c268c Binary files /dev/null and b/app/assets/images/emoji/slot_machine.png differ diff --git a/app/assets/images/emoji/small_blue_diamond.png b/app/assets/images/emoji/small_blue_diamond.png new file mode 100644 index 00000000000..b86b5bc4db3 Binary files /dev/null and b/app/assets/images/emoji/small_blue_diamond.png differ diff --git a/app/assets/images/emoji/small_orange_diamond.png b/app/assets/images/emoji/small_orange_diamond.png new file mode 100644 index 00000000000..e1c6ed9b2f8 Binary files /dev/null and b/app/assets/images/emoji/small_orange_diamond.png differ diff --git a/app/assets/images/emoji/small_red_triangle.png b/app/assets/images/emoji/small_red_triangle.png new file mode 100644 index 00000000000..785887c195a Binary files /dev/null and b/app/assets/images/emoji/small_red_triangle.png differ diff --git a/app/assets/images/emoji/small_red_triangle_down.png b/app/assets/images/emoji/small_red_triangle_down.png new file mode 100644 index 00000000000..a83beff1914 Binary files /dev/null and b/app/assets/images/emoji/small_red_triangle_down.png differ diff --git a/app/assets/images/emoji/smile.png b/app/assets/images/emoji/smile.png new file mode 100644 index 00000000000..aa47ffe978c Binary files /dev/null and b/app/assets/images/emoji/smile.png differ diff --git a/app/assets/images/emoji/smile_cat.png b/app/assets/images/emoji/smile_cat.png new file mode 100644 index 00000000000..6f25f11dd3a Binary files /dev/null and b/app/assets/images/emoji/smile_cat.png differ diff --git a/app/assets/images/emoji/smiley.png b/app/assets/images/emoji/smiley.png new file mode 100644 index 00000000000..30957a65968 Binary files /dev/null and b/app/assets/images/emoji/smiley.png differ diff --git a/app/assets/images/emoji/smiley_cat.png b/app/assets/images/emoji/smiley_cat.png new file mode 100644 index 00000000000..163b57a3427 Binary files /dev/null and b/app/assets/images/emoji/smiley_cat.png differ diff --git a/app/assets/images/emoji/smiling_imp.png b/app/assets/images/emoji/smiling_imp.png new file mode 100644 index 00000000000..cc2c5f1ec72 Binary files /dev/null and b/app/assets/images/emoji/smiling_imp.png differ diff --git a/app/assets/images/emoji/smirk.png b/app/assets/images/emoji/smirk.png new file mode 100644 index 00000000000..87852109988 Binary files /dev/null and b/app/assets/images/emoji/smirk.png differ diff --git a/app/assets/images/emoji/smirk_cat.png b/app/assets/images/emoji/smirk_cat.png new file mode 100644 index 00000000000..9ac5954c199 Binary files /dev/null and b/app/assets/images/emoji/smirk_cat.png differ diff --git a/app/assets/images/emoji/smoking.png b/app/assets/images/emoji/smoking.png new file mode 100644 index 00000000000..910f648c8f9 Binary files /dev/null and b/app/assets/images/emoji/smoking.png differ diff --git a/app/assets/images/emoji/snail.png b/app/assets/images/emoji/snail.png new file mode 100644 index 00000000000..f4ea071e2d3 Binary files /dev/null and b/app/assets/images/emoji/snail.png differ diff --git a/app/assets/images/emoji/snake.png b/app/assets/images/emoji/snake.png new file mode 100644 index 00000000000..d0278a28d8c Binary files /dev/null and b/app/assets/images/emoji/snake.png differ diff --git a/app/assets/images/emoji/sneezing_face.png b/app/assets/images/emoji/sneezing_face.png new file mode 100644 index 00000000000..ccf07d4b64d Binary files /dev/null and b/app/assets/images/emoji/sneezing_face.png differ diff --git a/app/assets/images/emoji/snowboarder.png b/app/assets/images/emoji/snowboarder.png new file mode 100644 index 00000000000..6361c0f2c9d Binary files /dev/null and b/app/assets/images/emoji/snowboarder.png differ diff --git a/app/assets/images/emoji/snowflake.png b/app/assets/images/emoji/snowflake.png new file mode 100644 index 00000000000..db319a77ec6 Binary files /dev/null and b/app/assets/images/emoji/snowflake.png differ diff --git a/app/assets/images/emoji/snowman.png b/app/assets/images/emoji/snowman.png new file mode 100644 index 00000000000..20c177c2aff Binary files /dev/null and b/app/assets/images/emoji/snowman.png differ diff --git a/app/assets/images/emoji/snowman2.png b/app/assets/images/emoji/snowman2.png new file mode 100644 index 00000000000..896f28502af Binary files /dev/null and b/app/assets/images/emoji/snowman2.png differ diff --git a/app/assets/images/emoji/sob.png b/app/assets/images/emoji/sob.png new file mode 100644 index 00000000000..52e3517a1ee Binary files /dev/null and b/app/assets/images/emoji/sob.png differ diff --git a/app/assets/images/emoji/soccer.png b/app/assets/images/emoji/soccer.png new file mode 100644 index 00000000000..28cfa218d6d Binary files /dev/null and b/app/assets/images/emoji/soccer.png differ diff --git a/app/assets/images/emoji/soon.png b/app/assets/images/emoji/soon.png new file mode 100644 index 00000000000..8cdfd86690d Binary files /dev/null and b/app/assets/images/emoji/soon.png differ diff --git a/app/assets/images/emoji/sos.png b/app/assets/images/emoji/sos.png new file mode 100644 index 00000000000..d7d8c9953e4 Binary files /dev/null and b/app/assets/images/emoji/sos.png differ diff --git a/app/assets/images/emoji/sound.png b/app/assets/images/emoji/sound.png new file mode 100644 index 00000000000..e75ddca53ba Binary files /dev/null and b/app/assets/images/emoji/sound.png differ diff --git a/app/assets/images/emoji/space_invader.png b/app/assets/images/emoji/space_invader.png new file mode 100644 index 00000000000..2e73f5f32e5 Binary files /dev/null and b/app/assets/images/emoji/space_invader.png differ diff --git a/app/assets/images/emoji/spades.png b/app/assets/images/emoji/spades.png new file mode 100644 index 00000000000..f822f184cb0 Binary files /dev/null and b/app/assets/images/emoji/spades.png differ diff --git a/app/assets/images/emoji/spaghetti.png b/app/assets/images/emoji/spaghetti.png new file mode 100644 index 00000000000..89c24a321f1 Binary files /dev/null and b/app/assets/images/emoji/spaghetti.png differ diff --git a/app/assets/images/emoji/sparkle.png b/app/assets/images/emoji/sparkle.png new file mode 100644 index 00000000000..6aa7b6ec9cf Binary files /dev/null and b/app/assets/images/emoji/sparkle.png differ diff --git a/app/assets/images/emoji/sparkler.png b/app/assets/images/emoji/sparkler.png new file mode 100644 index 00000000000..30339cd6e09 Binary files /dev/null and b/app/assets/images/emoji/sparkler.png differ diff --git a/app/assets/images/emoji/sparkles.png b/app/assets/images/emoji/sparkles.png new file mode 100644 index 00000000000..169bc10b023 Binary files /dev/null and b/app/assets/images/emoji/sparkles.png differ diff --git a/app/assets/images/emoji/sparkling_heart.png b/app/assets/images/emoji/sparkling_heart.png new file mode 100644 index 00000000000..6709269454e Binary files /dev/null and b/app/assets/images/emoji/sparkling_heart.png differ diff --git a/app/assets/images/emoji/speak_no_evil.png b/app/assets/images/emoji/speak_no_evil.png new file mode 100644 index 00000000000..9d9e07c974b Binary files /dev/null and b/app/assets/images/emoji/speak_no_evil.png differ diff --git a/app/assets/images/emoji/speaker.png b/app/assets/images/emoji/speaker.png new file mode 100644 index 00000000000..7bcffb8fc43 Binary files /dev/null and b/app/assets/images/emoji/speaker.png differ diff --git a/app/assets/images/emoji/speaking_head.png b/app/assets/images/emoji/speaking_head.png new file mode 100644 index 00000000000..2df93aaae09 Binary files /dev/null and b/app/assets/images/emoji/speaking_head.png differ diff --git a/app/assets/images/emoji/speech_balloon.png b/app/assets/images/emoji/speech_balloon.png new file mode 100644 index 00000000000..a34ef741733 Binary files /dev/null and b/app/assets/images/emoji/speech_balloon.png differ diff --git a/app/assets/images/emoji/speedboat.png b/app/assets/images/emoji/speedboat.png new file mode 100644 index 00000000000..74059d12de1 Binary files /dev/null and b/app/assets/images/emoji/speedboat.png differ diff --git a/app/assets/images/emoji/spider.png b/app/assets/images/emoji/spider.png new file mode 100644 index 00000000000..3849fa90b94 Binary files /dev/null and b/app/assets/images/emoji/spider.png differ diff --git a/app/assets/images/emoji/spider_web.png b/app/assets/images/emoji/spider_web.png new file mode 100644 index 00000000000..ba448ee7fba Binary files /dev/null and b/app/assets/images/emoji/spider_web.png differ diff --git a/app/assets/images/emoji/spoon.png b/app/assets/images/emoji/spoon.png new file mode 100644 index 00000000000..3c4da766aee Binary files /dev/null and b/app/assets/images/emoji/spoon.png differ diff --git a/app/assets/images/emoji/spy.png b/app/assets/images/emoji/spy.png new file mode 100644 index 00000000000..a729e9584d6 Binary files /dev/null and b/app/assets/images/emoji/spy.png differ diff --git a/app/assets/images/emoji/spy_tone1.png b/app/assets/images/emoji/spy_tone1.png new file mode 100644 index 00000000000..2d1c022caee Binary files /dev/null and b/app/assets/images/emoji/spy_tone1.png differ diff --git a/app/assets/images/emoji/spy_tone2.png b/app/assets/images/emoji/spy_tone2.png new file mode 100644 index 00000000000..548b9c26f5d Binary files /dev/null and b/app/assets/images/emoji/spy_tone2.png differ diff --git a/app/assets/images/emoji/spy_tone3.png b/app/assets/images/emoji/spy_tone3.png new file mode 100644 index 00000000000..b023f4b18e1 Binary files /dev/null and b/app/assets/images/emoji/spy_tone3.png differ diff --git a/app/assets/images/emoji/spy_tone4.png b/app/assets/images/emoji/spy_tone4.png new file mode 100644 index 00000000000..d8300af492d Binary files /dev/null and b/app/assets/images/emoji/spy_tone4.png differ diff --git a/app/assets/images/emoji/spy_tone5.png b/app/assets/images/emoji/spy_tone5.png new file mode 100644 index 00000000000..ca1462595fa Binary files /dev/null and b/app/assets/images/emoji/spy_tone5.png differ diff --git a/app/assets/images/emoji/squid.png b/app/assets/images/emoji/squid.png new file mode 100644 index 00000000000..d2af223f0cb Binary files /dev/null and b/app/assets/images/emoji/squid.png differ diff --git a/app/assets/images/emoji/stadium.png b/app/assets/images/emoji/stadium.png new file mode 100644 index 00000000000..00cd6db5e29 Binary files /dev/null and b/app/assets/images/emoji/stadium.png differ diff --git a/app/assets/images/emoji/star.png b/app/assets/images/emoji/star.png new file mode 100644 index 00000000000..c930947076e Binary files /dev/null and b/app/assets/images/emoji/star.png differ diff --git a/app/assets/images/emoji/star2.png b/app/assets/images/emoji/star2.png new file mode 100644 index 00000000000..2f5cba592db Binary files /dev/null and b/app/assets/images/emoji/star2.png differ diff --git a/app/assets/images/emoji/star_and_crescent.png b/app/assets/images/emoji/star_and_crescent.png new file mode 100644 index 00000000000..e182636457d Binary files /dev/null and b/app/assets/images/emoji/star_and_crescent.png differ diff --git a/app/assets/images/emoji/star_of_david.png b/app/assets/images/emoji/star_of_david.png new file mode 100644 index 00000000000..fc59d0dde24 Binary files /dev/null and b/app/assets/images/emoji/star_of_david.png differ diff --git a/app/assets/images/emoji/stars.png b/app/assets/images/emoji/stars.png new file mode 100644 index 00000000000..aa45384d1c6 Binary files /dev/null and b/app/assets/images/emoji/stars.png differ diff --git a/app/assets/images/emoji/station.png b/app/assets/images/emoji/station.png new file mode 100644 index 00000000000..5c26fee529c Binary files /dev/null and b/app/assets/images/emoji/station.png differ diff --git a/app/assets/images/emoji/statue_of_liberty.png b/app/assets/images/emoji/statue_of_liberty.png new file mode 100644 index 00000000000..05df8289b59 Binary files /dev/null and b/app/assets/images/emoji/statue_of_liberty.png differ diff --git a/app/assets/images/emoji/steam_locomotive.png b/app/assets/images/emoji/steam_locomotive.png new file mode 100644 index 00000000000..9ac0d999c4c Binary files /dev/null and b/app/assets/images/emoji/steam_locomotive.png differ diff --git a/app/assets/images/emoji/stew.png b/app/assets/images/emoji/stew.png new file mode 100644 index 00000000000..6b3f010c17a Binary files /dev/null and b/app/assets/images/emoji/stew.png differ diff --git a/app/assets/images/emoji/stop_button.png b/app/assets/images/emoji/stop_button.png new file mode 100644 index 00000000000..cfa99988ac2 Binary files /dev/null and b/app/assets/images/emoji/stop_button.png differ diff --git a/app/assets/images/emoji/stopwatch.png b/app/assets/images/emoji/stopwatch.png new file mode 100644 index 00000000000..8fae1c9a898 Binary files /dev/null and b/app/assets/images/emoji/stopwatch.png differ diff --git a/app/assets/images/emoji/straight_ruler.png b/app/assets/images/emoji/straight_ruler.png new file mode 100644 index 00000000000..1017b7433a1 Binary files /dev/null and b/app/assets/images/emoji/straight_ruler.png differ diff --git a/app/assets/images/emoji/strawberry.png b/app/assets/images/emoji/strawberry.png new file mode 100644 index 00000000000..7bb86f0b29c Binary files /dev/null and b/app/assets/images/emoji/strawberry.png differ diff --git a/app/assets/images/emoji/stuck_out_tongue.png b/app/assets/images/emoji/stuck_out_tongue.png new file mode 100644 index 00000000000..25757341f96 Binary files /dev/null and b/app/assets/images/emoji/stuck_out_tongue.png differ diff --git a/app/assets/images/emoji/stuck_out_tongue_closed_eyes.png b/app/assets/images/emoji/stuck_out_tongue_closed_eyes.png new file mode 100644 index 00000000000..5c0401e9b1d Binary files /dev/null and b/app/assets/images/emoji/stuck_out_tongue_closed_eyes.png differ diff --git a/app/assets/images/emoji/stuck_out_tongue_winking_eye.png b/app/assets/images/emoji/stuck_out_tongue_winking_eye.png new file mode 100644 index 00000000000..4817eaa3dc6 Binary files /dev/null and b/app/assets/images/emoji/stuck_out_tongue_winking_eye.png differ diff --git a/app/assets/images/emoji/stuffed_flatbread.png b/app/assets/images/emoji/stuffed_flatbread.png new file mode 100644 index 00000000000..a2e10df40a5 Binary files /dev/null and b/app/assets/images/emoji/stuffed_flatbread.png differ diff --git a/app/assets/images/emoji/sun_with_face.png b/app/assets/images/emoji/sun_with_face.png new file mode 100644 index 00000000000..14a4ea971db Binary files /dev/null and b/app/assets/images/emoji/sun_with_face.png differ diff --git a/app/assets/images/emoji/sunflower.png b/app/assets/images/emoji/sunflower.png new file mode 100644 index 00000000000..08cc07761ea Binary files /dev/null and b/app/assets/images/emoji/sunflower.png differ diff --git a/app/assets/images/emoji/sunglasses.png b/app/assets/images/emoji/sunglasses.png new file mode 100644 index 00000000000..20011735110 Binary files /dev/null and b/app/assets/images/emoji/sunglasses.png differ diff --git a/app/assets/images/emoji/sunny.png b/app/assets/images/emoji/sunny.png new file mode 100644 index 00000000000..fd521ae31a7 Binary files /dev/null and b/app/assets/images/emoji/sunny.png differ diff --git a/app/assets/images/emoji/sunrise.png b/app/assets/images/emoji/sunrise.png new file mode 100644 index 00000000000..4ad36003c20 Binary files /dev/null and b/app/assets/images/emoji/sunrise.png differ diff --git a/app/assets/images/emoji/sunrise_over_mountains.png b/app/assets/images/emoji/sunrise_over_mountains.png new file mode 100644 index 00000000000..2b99307344d Binary files /dev/null and b/app/assets/images/emoji/sunrise_over_mountains.png differ diff --git a/app/assets/images/emoji/surfer.png b/app/assets/images/emoji/surfer.png new file mode 100644 index 00000000000..3ab017adf4b Binary files /dev/null and b/app/assets/images/emoji/surfer.png differ diff --git a/app/assets/images/emoji/surfer_tone1.png b/app/assets/images/emoji/surfer_tone1.png new file mode 100644 index 00000000000..b5faaa524cc Binary files /dev/null and b/app/assets/images/emoji/surfer_tone1.png differ diff --git a/app/assets/images/emoji/surfer_tone2.png b/app/assets/images/emoji/surfer_tone2.png new file mode 100644 index 00000000000..6d92e412ff1 Binary files /dev/null and b/app/assets/images/emoji/surfer_tone2.png differ diff --git a/app/assets/images/emoji/surfer_tone3.png b/app/assets/images/emoji/surfer_tone3.png new file mode 100644 index 00000000000..f05ef59496e Binary files /dev/null and b/app/assets/images/emoji/surfer_tone3.png differ diff --git a/app/assets/images/emoji/surfer_tone4.png b/app/assets/images/emoji/surfer_tone4.png new file mode 100644 index 00000000000..35e143d19dc Binary files /dev/null and b/app/assets/images/emoji/surfer_tone4.png differ diff --git a/app/assets/images/emoji/surfer_tone5.png b/app/assets/images/emoji/surfer_tone5.png new file mode 100644 index 00000000000..38917658eac Binary files /dev/null and b/app/assets/images/emoji/surfer_tone5.png differ diff --git a/app/assets/images/emoji/sushi.png b/app/assets/images/emoji/sushi.png new file mode 100644 index 00000000000..f171fd2f7a1 Binary files /dev/null and b/app/assets/images/emoji/sushi.png differ diff --git a/app/assets/images/emoji/suspension_railway.png b/app/assets/images/emoji/suspension_railway.png new file mode 100644 index 00000000000..a59d5f48c24 Binary files /dev/null and b/app/assets/images/emoji/suspension_railway.png differ diff --git a/app/assets/images/emoji/sweat.png b/app/assets/images/emoji/sweat.png new file mode 100644 index 00000000000..f0dae7b7893 Binary files /dev/null and b/app/assets/images/emoji/sweat.png differ diff --git a/app/assets/images/emoji/sweat_drops.png b/app/assets/images/emoji/sweat_drops.png new file mode 100644 index 00000000000..4106117ebc8 Binary files /dev/null and b/app/assets/images/emoji/sweat_drops.png differ diff --git a/app/assets/images/emoji/sweat_smile.png b/app/assets/images/emoji/sweat_smile.png new file mode 100644 index 00000000000..cb18d9c899b Binary files /dev/null and b/app/assets/images/emoji/sweat_smile.png differ diff --git a/app/assets/images/emoji/sweet_potato.png b/app/assets/images/emoji/sweet_potato.png new file mode 100644 index 00000000000..92a425f2e20 Binary files /dev/null and b/app/assets/images/emoji/sweet_potato.png differ diff --git a/app/assets/images/emoji/swimmer.png b/app/assets/images/emoji/swimmer.png new file mode 100644 index 00000000000..55b4d72f9a7 Binary files /dev/null and b/app/assets/images/emoji/swimmer.png differ diff --git a/app/assets/images/emoji/swimmer_tone1.png b/app/assets/images/emoji/swimmer_tone1.png new file mode 100644 index 00000000000..38441c9ca9a Binary files /dev/null and b/app/assets/images/emoji/swimmer_tone1.png differ diff --git a/app/assets/images/emoji/swimmer_tone2.png b/app/assets/images/emoji/swimmer_tone2.png new file mode 100644 index 00000000000..b0d43112444 Binary files /dev/null and b/app/assets/images/emoji/swimmer_tone2.png differ diff --git a/app/assets/images/emoji/swimmer_tone3.png b/app/assets/images/emoji/swimmer_tone3.png new file mode 100644 index 00000000000..211e77e2aa0 Binary files /dev/null and b/app/assets/images/emoji/swimmer_tone3.png differ diff --git a/app/assets/images/emoji/swimmer_tone4.png b/app/assets/images/emoji/swimmer_tone4.png new file mode 100644 index 00000000000..f34c34db9d2 Binary files /dev/null and b/app/assets/images/emoji/swimmer_tone4.png differ diff --git a/app/assets/images/emoji/swimmer_tone5.png b/app/assets/images/emoji/swimmer_tone5.png new file mode 100644 index 00000000000..3e9231ff868 Binary files /dev/null and b/app/assets/images/emoji/swimmer_tone5.png differ diff --git a/app/assets/images/emoji/symbols.png b/app/assets/images/emoji/symbols.png new file mode 100644 index 00000000000..ac2fc1f358f Binary files /dev/null and b/app/assets/images/emoji/symbols.png differ diff --git a/app/assets/images/emoji/synagogue.png b/app/assets/images/emoji/synagogue.png new file mode 100644 index 00000000000..ee347904c80 Binary files /dev/null and b/app/assets/images/emoji/synagogue.png differ diff --git a/app/assets/images/emoji/syringe.png b/app/assets/images/emoji/syringe.png new file mode 100644 index 00000000000..71c1a9528d5 Binary files /dev/null and b/app/assets/images/emoji/syringe.png differ diff --git a/app/assets/images/emoji/taco.png b/app/assets/images/emoji/taco.png new file mode 100644 index 00000000000..10e847a4619 Binary files /dev/null and b/app/assets/images/emoji/taco.png differ diff --git a/app/assets/images/emoji/tada.png b/app/assets/images/emoji/tada.png new file mode 100644 index 00000000000..0244d60f269 Binary files /dev/null and b/app/assets/images/emoji/tada.png differ diff --git a/app/assets/images/emoji/tanabata_tree.png b/app/assets/images/emoji/tanabata_tree.png new file mode 100644 index 00000000000..46fcb3a1aac Binary files /dev/null and b/app/assets/images/emoji/tanabata_tree.png differ diff --git a/app/assets/images/emoji/tangerine.png b/app/assets/images/emoji/tangerine.png new file mode 100644 index 00000000000..ab14e5378db Binary files /dev/null and b/app/assets/images/emoji/tangerine.png differ diff --git a/app/assets/images/emoji/taurus.png b/app/assets/images/emoji/taurus.png new file mode 100644 index 00000000000..b2a370df42b Binary files /dev/null and b/app/assets/images/emoji/taurus.png differ diff --git a/app/assets/images/emoji/taxi.png b/app/assets/images/emoji/taxi.png new file mode 100644 index 00000000000..55f4cc84797 Binary files /dev/null and b/app/assets/images/emoji/taxi.png differ diff --git a/app/assets/images/emoji/tea.png b/app/assets/images/emoji/tea.png new file mode 100644 index 00000000000..b53b98f0c45 Binary files /dev/null and b/app/assets/images/emoji/tea.png differ diff --git a/app/assets/images/emoji/telephone.png b/app/assets/images/emoji/telephone.png new file mode 100644 index 00000000000..a1e69f566bc Binary files /dev/null and b/app/assets/images/emoji/telephone.png differ diff --git a/app/assets/images/emoji/telephone_receiver.png b/app/assets/images/emoji/telephone_receiver.png new file mode 100644 index 00000000000..69388316c35 Binary files /dev/null and b/app/assets/images/emoji/telephone_receiver.png differ diff --git a/app/assets/images/emoji/telescope.png b/app/assets/images/emoji/telescope.png new file mode 100644 index 00000000000..d63154614b5 Binary files /dev/null and b/app/assets/images/emoji/telescope.png differ diff --git a/app/assets/images/emoji/ten.png b/app/assets/images/emoji/ten.png new file mode 100644 index 00000000000..782d4004962 Binary files /dev/null and b/app/assets/images/emoji/ten.png differ diff --git a/app/assets/images/emoji/tennis.png b/app/assets/images/emoji/tennis.png new file mode 100644 index 00000000000..7e68ba8f301 Binary files /dev/null and b/app/assets/images/emoji/tennis.png differ diff --git a/app/assets/images/emoji/tent.png b/app/assets/images/emoji/tent.png new file mode 100644 index 00000000000..3fddcfc56eb Binary files /dev/null and b/app/assets/images/emoji/tent.png differ diff --git a/app/assets/images/emoji/thermometer.png b/app/assets/images/emoji/thermometer.png new file mode 100644 index 00000000000..b1147392426 Binary files /dev/null and b/app/assets/images/emoji/thermometer.png differ diff --git a/app/assets/images/emoji/thermometer_face.png b/app/assets/images/emoji/thermometer_face.png new file mode 100644 index 00000000000..8fc57387563 Binary files /dev/null and b/app/assets/images/emoji/thermometer_face.png differ diff --git a/app/assets/images/emoji/thinking.png b/app/assets/images/emoji/thinking.png new file mode 100644 index 00000000000..c18f6fd14ad Binary files /dev/null and b/app/assets/images/emoji/thinking.png differ diff --git a/app/assets/images/emoji/third_place.png b/app/assets/images/emoji/third_place.png new file mode 100644 index 00000000000..636e04a5950 Binary files /dev/null and b/app/assets/images/emoji/third_place.png differ diff --git a/app/assets/images/emoji/thought_balloon.png b/app/assets/images/emoji/thought_balloon.png new file mode 100644 index 00000000000..72fe8fa7022 Binary files /dev/null and b/app/assets/images/emoji/thought_balloon.png differ diff --git a/app/assets/images/emoji/three.png b/app/assets/images/emoji/three.png new file mode 100644 index 00000000000..dbaa6183e72 Binary files /dev/null and b/app/assets/images/emoji/three.png differ diff --git a/app/assets/images/emoji/thumbsdown.png b/app/assets/images/emoji/thumbsdown.png new file mode 100644 index 00000000000..b63da2f20a8 Binary files /dev/null and b/app/assets/images/emoji/thumbsdown.png differ diff --git a/app/assets/images/emoji/thumbsdown_tone1.png b/app/assets/images/emoji/thumbsdown_tone1.png new file mode 100644 index 00000000000..a1631af8e92 Binary files /dev/null and b/app/assets/images/emoji/thumbsdown_tone1.png differ diff --git a/app/assets/images/emoji/thumbsdown_tone2.png b/app/assets/images/emoji/thumbsdown_tone2.png new file mode 100644 index 00000000000..85fff82d595 Binary files /dev/null and b/app/assets/images/emoji/thumbsdown_tone2.png differ diff --git a/app/assets/images/emoji/thumbsdown_tone3.png b/app/assets/images/emoji/thumbsdown_tone3.png new file mode 100644 index 00000000000..eeba3be80fd Binary files /dev/null and b/app/assets/images/emoji/thumbsdown_tone3.png differ diff --git a/app/assets/images/emoji/thumbsdown_tone4.png b/app/assets/images/emoji/thumbsdown_tone4.png new file mode 100644 index 00000000000..1addafdaed0 Binary files /dev/null and b/app/assets/images/emoji/thumbsdown_tone4.png differ diff --git a/app/assets/images/emoji/thumbsdown_tone5.png b/app/assets/images/emoji/thumbsdown_tone5.png new file mode 100644 index 00000000000..37ec07b5721 Binary files /dev/null and b/app/assets/images/emoji/thumbsdown_tone5.png differ diff --git a/app/assets/images/emoji/thumbsup.png b/app/assets/images/emoji/thumbsup.png new file mode 100644 index 00000000000..f9e6f13a34f Binary files /dev/null and b/app/assets/images/emoji/thumbsup.png differ diff --git a/app/assets/images/emoji/thumbsup_tone1.png b/app/assets/images/emoji/thumbsup_tone1.png new file mode 100644 index 00000000000..39684cd5cc7 Binary files /dev/null and b/app/assets/images/emoji/thumbsup_tone1.png differ diff --git a/app/assets/images/emoji/thumbsup_tone2.png b/app/assets/images/emoji/thumbsup_tone2.png new file mode 100644 index 00000000000..a9b59723573 Binary files /dev/null and b/app/assets/images/emoji/thumbsup_tone2.png differ diff --git a/app/assets/images/emoji/thumbsup_tone3.png b/app/assets/images/emoji/thumbsup_tone3.png new file mode 100644 index 00000000000..c5e29167015 Binary files /dev/null and b/app/assets/images/emoji/thumbsup_tone3.png differ diff --git a/app/assets/images/emoji/thumbsup_tone4.png b/app/assets/images/emoji/thumbsup_tone4.png new file mode 100644 index 00000000000..5bf4857a884 Binary files /dev/null and b/app/assets/images/emoji/thumbsup_tone4.png differ diff --git a/app/assets/images/emoji/thumbsup_tone5.png b/app/assets/images/emoji/thumbsup_tone5.png new file mode 100644 index 00000000000..d829f787c61 Binary files /dev/null and b/app/assets/images/emoji/thumbsup_tone5.png differ diff --git a/app/assets/images/emoji/thunder_cloud_rain.png b/app/assets/images/emoji/thunder_cloud_rain.png new file mode 100644 index 00000000000..31a26a1b6ee Binary files /dev/null and b/app/assets/images/emoji/thunder_cloud_rain.png differ diff --git a/app/assets/images/emoji/ticket.png b/app/assets/images/emoji/ticket.png new file mode 100644 index 00000000000..605936bb6b3 Binary files /dev/null and b/app/assets/images/emoji/ticket.png differ diff --git a/app/assets/images/emoji/tickets.png b/app/assets/images/emoji/tickets.png new file mode 100644 index 00000000000..e510f4a7a50 Binary files /dev/null and b/app/assets/images/emoji/tickets.png differ diff --git a/app/assets/images/emoji/tiger.png b/app/assets/images/emoji/tiger.png new file mode 100644 index 00000000000..a4d3ef086d4 Binary files /dev/null and b/app/assets/images/emoji/tiger.png differ diff --git a/app/assets/images/emoji/tiger2.png b/app/assets/images/emoji/tiger2.png new file mode 100644 index 00000000000..871a8b74d56 Binary files /dev/null and b/app/assets/images/emoji/tiger2.png differ diff --git a/app/assets/images/emoji/timer.png b/app/assets/images/emoji/timer.png new file mode 100644 index 00000000000..8a3be574c24 Binary files /dev/null and b/app/assets/images/emoji/timer.png differ diff --git a/app/assets/images/emoji/tired_face.png b/app/assets/images/emoji/tired_face.png new file mode 100644 index 00000000000..4e01eff5b23 Binary files /dev/null and b/app/assets/images/emoji/tired_face.png differ diff --git a/app/assets/images/emoji/tm.png b/app/assets/images/emoji/tm.png new file mode 100644 index 00000000000..7a0c44a2c2b Binary files /dev/null and b/app/assets/images/emoji/tm.png differ diff --git a/app/assets/images/emoji/toilet.png b/app/assets/images/emoji/toilet.png new file mode 100644 index 00000000000..1392f761835 Binary files /dev/null and b/app/assets/images/emoji/toilet.png differ diff --git a/app/assets/images/emoji/tokyo_tower.png b/app/assets/images/emoji/tokyo_tower.png new file mode 100644 index 00000000000..37df7fc65b1 Binary files /dev/null and b/app/assets/images/emoji/tokyo_tower.png differ diff --git a/app/assets/images/emoji/tomato.png b/app/assets/images/emoji/tomato.png new file mode 100644 index 00000000000..497da8f6b22 Binary files /dev/null and b/app/assets/images/emoji/tomato.png differ diff --git a/app/assets/images/emoji/tone1.png b/app/assets/images/emoji/tone1.png new file mode 100644 index 00000000000..c395f3d0d68 Binary files /dev/null and b/app/assets/images/emoji/tone1.png differ diff --git a/app/assets/images/emoji/tone2.png b/app/assets/images/emoji/tone2.png new file mode 100644 index 00000000000..080847431c1 Binary files /dev/null and b/app/assets/images/emoji/tone2.png differ diff --git a/app/assets/images/emoji/tone3.png b/app/assets/images/emoji/tone3.png new file mode 100644 index 00000000000..482dd403475 Binary files /dev/null and b/app/assets/images/emoji/tone3.png differ diff --git a/app/assets/images/emoji/tone4.png b/app/assets/images/emoji/tone4.png new file mode 100644 index 00000000000..5cae8bb20b0 Binary files /dev/null and b/app/assets/images/emoji/tone4.png differ diff --git a/app/assets/images/emoji/tone5.png b/app/assets/images/emoji/tone5.png new file mode 100644 index 00000000000..49d1a8c3a64 Binary files /dev/null and b/app/assets/images/emoji/tone5.png differ diff --git a/app/assets/images/emoji/tongue.png b/app/assets/images/emoji/tongue.png new file mode 100644 index 00000000000..70ce9c1225f Binary files /dev/null and b/app/assets/images/emoji/tongue.png differ diff --git a/app/assets/images/emoji/tools.png b/app/assets/images/emoji/tools.png new file mode 100644 index 00000000000..3c6049273a9 Binary files /dev/null and b/app/assets/images/emoji/tools.png differ diff --git a/app/assets/images/emoji/top.png b/app/assets/images/emoji/top.png new file mode 100644 index 00000000000..49dea8c08b5 Binary files /dev/null and b/app/assets/images/emoji/top.png differ diff --git a/app/assets/images/emoji/tophat.png b/app/assets/images/emoji/tophat.png new file mode 100644 index 00000000000..131b657b109 Binary files /dev/null and b/app/assets/images/emoji/tophat.png differ diff --git a/app/assets/images/emoji/track_next.png b/app/assets/images/emoji/track_next.png new file mode 100644 index 00000000000..f8880d33bab Binary files /dev/null and b/app/assets/images/emoji/track_next.png differ diff --git a/app/assets/images/emoji/track_previous.png b/app/assets/images/emoji/track_previous.png new file mode 100644 index 00000000000..1ffd0566cfc Binary files /dev/null and b/app/assets/images/emoji/track_previous.png differ diff --git a/app/assets/images/emoji/trackball.png b/app/assets/images/emoji/trackball.png new file mode 100644 index 00000000000..3bea84ad7ce Binary files /dev/null and b/app/assets/images/emoji/trackball.png differ diff --git a/app/assets/images/emoji/tractor.png b/app/assets/images/emoji/tractor.png new file mode 100644 index 00000000000..c1bf8cae44f Binary files /dev/null and b/app/assets/images/emoji/tractor.png differ diff --git a/app/assets/images/emoji/traffic_light.png b/app/assets/images/emoji/traffic_light.png new file mode 100644 index 00000000000..6b312285b00 Binary files /dev/null and b/app/assets/images/emoji/traffic_light.png differ diff --git a/app/assets/images/emoji/train.png b/app/assets/images/emoji/train.png new file mode 100644 index 00000000000..3c80321f7e8 Binary files /dev/null and b/app/assets/images/emoji/train.png differ diff --git a/app/assets/images/emoji/train2.png b/app/assets/images/emoji/train2.png new file mode 100644 index 00000000000..367c7bc5d39 Binary files /dev/null and b/app/assets/images/emoji/train2.png differ diff --git a/app/assets/images/emoji/tram.png b/app/assets/images/emoji/tram.png new file mode 100644 index 00000000000..b6f0e69038f Binary files /dev/null and b/app/assets/images/emoji/tram.png differ diff --git a/app/assets/images/emoji/triangular_flag_on_post.png b/app/assets/images/emoji/triangular_flag_on_post.png new file mode 100644 index 00000000000..c12d8b06886 Binary files /dev/null and b/app/assets/images/emoji/triangular_flag_on_post.png differ diff --git a/app/assets/images/emoji/triangular_ruler.png b/app/assets/images/emoji/triangular_ruler.png new file mode 100644 index 00000000000..77dee9ee843 Binary files /dev/null and b/app/assets/images/emoji/triangular_ruler.png differ diff --git a/app/assets/images/emoji/trident.png b/app/assets/images/emoji/trident.png new file mode 100644 index 00000000000..777a1dad121 Binary files /dev/null and b/app/assets/images/emoji/trident.png differ diff --git a/app/assets/images/emoji/triumph.png b/app/assets/images/emoji/triumph.png new file mode 100644 index 00000000000..0be7a501969 Binary files /dev/null and b/app/assets/images/emoji/triumph.png differ diff --git a/app/assets/images/emoji/trolleybus.png b/app/assets/images/emoji/trolleybus.png new file mode 100644 index 00000000000..139a9931b52 Binary files /dev/null and b/app/assets/images/emoji/trolleybus.png differ diff --git a/app/assets/images/emoji/trophy.png b/app/assets/images/emoji/trophy.png new file mode 100644 index 00000000000..ac2895c1896 Binary files /dev/null and b/app/assets/images/emoji/trophy.png differ diff --git a/app/assets/images/emoji/tropical_drink.png b/app/assets/images/emoji/tropical_drink.png new file mode 100644 index 00000000000..cd714f81b36 Binary files /dev/null and b/app/assets/images/emoji/tropical_drink.png differ diff --git a/app/assets/images/emoji/tropical_fish.png b/app/assets/images/emoji/tropical_fish.png new file mode 100644 index 00000000000..252105235a6 Binary files /dev/null and b/app/assets/images/emoji/tropical_fish.png differ diff --git a/app/assets/images/emoji/truck.png b/app/assets/images/emoji/truck.png new file mode 100644 index 00000000000..130de047f8b Binary files /dev/null and b/app/assets/images/emoji/truck.png differ diff --git a/app/assets/images/emoji/trumpet.png b/app/assets/images/emoji/trumpet.png new file mode 100644 index 00000000000..864ccbcd04a Binary files /dev/null and b/app/assets/images/emoji/trumpet.png differ diff --git a/app/assets/images/emoji/tulip.png b/app/assets/images/emoji/tulip.png new file mode 100644 index 00000000000..f799d75c182 Binary files /dev/null and b/app/assets/images/emoji/tulip.png differ diff --git a/app/assets/images/emoji/tumbler_glass.png b/app/assets/images/emoji/tumbler_glass.png new file mode 100644 index 00000000000..7bf09229879 Binary files /dev/null and b/app/assets/images/emoji/tumbler_glass.png differ diff --git a/app/assets/images/emoji/turkey.png b/app/assets/images/emoji/turkey.png new file mode 100644 index 00000000000..344af94c9ec Binary files /dev/null and b/app/assets/images/emoji/turkey.png differ diff --git a/app/assets/images/emoji/turtle.png b/app/assets/images/emoji/turtle.png new file mode 100644 index 00000000000..c22f7519fe8 Binary files /dev/null and b/app/assets/images/emoji/turtle.png differ diff --git a/app/assets/images/emoji/tv.png b/app/assets/images/emoji/tv.png new file mode 100644 index 00000000000..999f1fb5c6d Binary files /dev/null and b/app/assets/images/emoji/tv.png differ diff --git a/app/assets/images/emoji/twisted_rightwards_arrows.png b/app/assets/images/emoji/twisted_rightwards_arrows.png new file mode 100644 index 00000000000..5904badde65 Binary files /dev/null and b/app/assets/images/emoji/twisted_rightwards_arrows.png differ diff --git a/app/assets/images/emoji/two.png b/app/assets/images/emoji/two.png new file mode 100644 index 00000000000..927339c9bff Binary files /dev/null and b/app/assets/images/emoji/two.png differ diff --git a/app/assets/images/emoji/two_hearts.png b/app/assets/images/emoji/two_hearts.png new file mode 100644 index 00000000000..4d8c3386042 Binary files /dev/null and b/app/assets/images/emoji/two_hearts.png differ diff --git a/app/assets/images/emoji/two_men_holding_hands.png b/app/assets/images/emoji/two_men_holding_hands.png new file mode 100644 index 00000000000..a511fda822a Binary files /dev/null and b/app/assets/images/emoji/two_men_holding_hands.png differ diff --git a/app/assets/images/emoji/two_women_holding_hands.png b/app/assets/images/emoji/two_women_holding_hands.png new file mode 100644 index 00000000000..b077cd3e40f Binary files /dev/null and b/app/assets/images/emoji/two_women_holding_hands.png differ diff --git a/app/assets/images/emoji/u5272.png b/app/assets/images/emoji/u5272.png new file mode 100644 index 00000000000..c4f837fe684 Binary files /dev/null and b/app/assets/images/emoji/u5272.png differ diff --git a/app/assets/images/emoji/u5408.png b/app/assets/images/emoji/u5408.png new file mode 100644 index 00000000000..8375ad9d9af Binary files /dev/null and b/app/assets/images/emoji/u5408.png differ diff --git a/app/assets/images/emoji/u55b6.png b/app/assets/images/emoji/u55b6.png new file mode 100644 index 00000000000..d21cb30eaf3 Binary files /dev/null and b/app/assets/images/emoji/u55b6.png differ diff --git a/app/assets/images/emoji/u6307.png b/app/assets/images/emoji/u6307.png new file mode 100644 index 00000000000..078e23e4ff3 Binary files /dev/null and b/app/assets/images/emoji/u6307.png differ diff --git a/app/assets/images/emoji/u6708.png b/app/assets/images/emoji/u6708.png new file mode 100644 index 00000000000..c41bd36a26a Binary files /dev/null and b/app/assets/images/emoji/u6708.png differ diff --git a/app/assets/images/emoji/u6709.png b/app/assets/images/emoji/u6709.png new file mode 100644 index 00000000000..a4510de41c0 Binary files /dev/null and b/app/assets/images/emoji/u6709.png differ diff --git a/app/assets/images/emoji/u6e80.png b/app/assets/images/emoji/u6e80.png new file mode 100644 index 00000000000..f9dea8b8833 Binary files /dev/null and b/app/assets/images/emoji/u6e80.png differ diff --git a/app/assets/images/emoji/u7121.png b/app/assets/images/emoji/u7121.png new file mode 100644 index 00000000000..d3a19b420de Binary files /dev/null and b/app/assets/images/emoji/u7121.png differ diff --git a/app/assets/images/emoji/u7533.png b/app/assets/images/emoji/u7533.png new file mode 100644 index 00000000000..6b7af0ee222 Binary files /dev/null and b/app/assets/images/emoji/u7533.png differ diff --git a/app/assets/images/emoji/u7981.png b/app/assets/images/emoji/u7981.png new file mode 100644 index 00000000000..4c704e03433 Binary files /dev/null and b/app/assets/images/emoji/u7981.png differ diff --git a/app/assets/images/emoji/u7a7a.png b/app/assets/images/emoji/u7a7a.png new file mode 100644 index 00000000000..47966c1ea93 Binary files /dev/null and b/app/assets/images/emoji/u7a7a.png differ diff --git a/app/assets/images/emoji/umbrella.png b/app/assets/images/emoji/umbrella.png new file mode 100644 index 00000000000..5b35b7ff6a4 Binary files /dev/null and b/app/assets/images/emoji/umbrella.png differ diff --git a/app/assets/images/emoji/umbrella2.png b/app/assets/images/emoji/umbrella2.png new file mode 100644 index 00000000000..97fe859e74f Binary files /dev/null and b/app/assets/images/emoji/umbrella2.png differ diff --git a/app/assets/images/emoji/unamused.png b/app/assets/images/emoji/unamused.png new file mode 100644 index 00000000000..25e3677f2eb Binary files /dev/null and b/app/assets/images/emoji/unamused.png differ diff --git a/app/assets/images/emoji/underage.png b/app/assets/images/emoji/underage.png new file mode 100644 index 00000000000..6dfe6da51e2 Binary files /dev/null and b/app/assets/images/emoji/underage.png differ diff --git a/app/assets/images/emoji/unicorn.png b/app/assets/images/emoji/unicorn.png new file mode 100644 index 00000000000..05a97969f7e Binary files /dev/null and b/app/assets/images/emoji/unicorn.png differ diff --git a/app/assets/images/emoji/unlock.png b/app/assets/images/emoji/unlock.png new file mode 100644 index 00000000000..4a74a693911 Binary files /dev/null and b/app/assets/images/emoji/unlock.png differ diff --git a/app/assets/images/emoji/up.png b/app/assets/images/emoji/up.png new file mode 100644 index 00000000000..0d42142ba04 Binary files /dev/null and b/app/assets/images/emoji/up.png differ diff --git a/app/assets/images/emoji/upside_down.png b/app/assets/images/emoji/upside_down.png new file mode 100644 index 00000000000..128f31c9828 Binary files /dev/null and b/app/assets/images/emoji/upside_down.png differ diff --git a/app/assets/images/emoji/urn.png b/app/assets/images/emoji/urn.png new file mode 100644 index 00000000000..6b5b3503438 Binary files /dev/null and b/app/assets/images/emoji/urn.png differ diff --git a/app/assets/images/emoji/v.png b/app/assets/images/emoji/v.png new file mode 100644 index 00000000000..70c5516ffee Binary files /dev/null and b/app/assets/images/emoji/v.png differ diff --git a/app/assets/images/emoji/v_tone1.png b/app/assets/images/emoji/v_tone1.png new file mode 100644 index 00000000000..6ac54a745f4 Binary files /dev/null and b/app/assets/images/emoji/v_tone1.png differ diff --git a/app/assets/images/emoji/v_tone2.png b/app/assets/images/emoji/v_tone2.png new file mode 100644 index 00000000000..6dd9669866d Binary files /dev/null and b/app/assets/images/emoji/v_tone2.png differ diff --git a/app/assets/images/emoji/v_tone3.png b/app/assets/images/emoji/v_tone3.png new file mode 100644 index 00000000000..a615e53f02f Binary files /dev/null and b/app/assets/images/emoji/v_tone3.png differ diff --git a/app/assets/images/emoji/v_tone4.png b/app/assets/images/emoji/v_tone4.png new file mode 100644 index 00000000000..33a34bd5a78 Binary files /dev/null and b/app/assets/images/emoji/v_tone4.png differ diff --git a/app/assets/images/emoji/v_tone5.png b/app/assets/images/emoji/v_tone5.png new file mode 100644 index 00000000000..45ad14b6c9c Binary files /dev/null and b/app/assets/images/emoji/v_tone5.png differ diff --git a/app/assets/images/emoji/vertical_traffic_light.png b/app/assets/images/emoji/vertical_traffic_light.png new file mode 100644 index 00000000000..8085973eecf Binary files /dev/null and b/app/assets/images/emoji/vertical_traffic_light.png differ diff --git a/app/assets/images/emoji/vhs.png b/app/assets/images/emoji/vhs.png new file mode 100644 index 00000000000..b9eb78ecd92 Binary files /dev/null and b/app/assets/images/emoji/vhs.png differ diff --git a/app/assets/images/emoji/vibration_mode.png b/app/assets/images/emoji/vibration_mode.png new file mode 100644 index 00000000000..cc46510e48e Binary files /dev/null and b/app/assets/images/emoji/vibration_mode.png differ diff --git a/app/assets/images/emoji/video_camera.png b/app/assets/images/emoji/video_camera.png new file mode 100644 index 00000000000..85b300d425c Binary files /dev/null and b/app/assets/images/emoji/video_camera.png differ diff --git a/app/assets/images/emoji/video_game.png b/app/assets/images/emoji/video_game.png new file mode 100644 index 00000000000..316a9106a55 Binary files /dev/null and b/app/assets/images/emoji/video_game.png differ diff --git a/app/assets/images/emoji/violin.png b/app/assets/images/emoji/violin.png new file mode 100644 index 00000000000..e1e76cce242 Binary files /dev/null and b/app/assets/images/emoji/violin.png differ diff --git a/app/assets/images/emoji/virgo.png b/app/assets/images/emoji/virgo.png new file mode 100644 index 00000000000..a6b56c2cb5e Binary files /dev/null and b/app/assets/images/emoji/virgo.png differ diff --git a/app/assets/images/emoji/volcano.png b/app/assets/images/emoji/volcano.png new file mode 100644 index 00000000000..931d569294c Binary files /dev/null and b/app/assets/images/emoji/volcano.png differ diff --git a/app/assets/images/emoji/volleyball.png b/app/assets/images/emoji/volleyball.png new file mode 100644 index 00000000000..7a0e49d4b07 Binary files /dev/null and b/app/assets/images/emoji/volleyball.png differ diff --git a/app/assets/images/emoji/vs.png b/app/assets/images/emoji/vs.png new file mode 100644 index 00000000000..e1180f4a464 Binary files /dev/null and b/app/assets/images/emoji/vs.png differ diff --git a/app/assets/images/emoji/vulcan.png b/app/assets/images/emoji/vulcan.png new file mode 100644 index 00000000000..54728bcaf5c Binary files /dev/null and b/app/assets/images/emoji/vulcan.png differ diff --git a/app/assets/images/emoji/vulcan_tone1.png b/app/assets/images/emoji/vulcan_tone1.png new file mode 100644 index 00000000000..8aff5d8fa16 Binary files /dev/null and b/app/assets/images/emoji/vulcan_tone1.png differ diff --git a/app/assets/images/emoji/vulcan_tone2.png b/app/assets/images/emoji/vulcan_tone2.png new file mode 100644 index 00000000000..82b7ad519b4 Binary files /dev/null and b/app/assets/images/emoji/vulcan_tone2.png differ diff --git a/app/assets/images/emoji/vulcan_tone3.png b/app/assets/images/emoji/vulcan_tone3.png new file mode 100644 index 00000000000..d1400e1dd28 Binary files /dev/null and b/app/assets/images/emoji/vulcan_tone3.png differ diff --git a/app/assets/images/emoji/vulcan_tone4.png b/app/assets/images/emoji/vulcan_tone4.png new file mode 100644 index 00000000000..47e2b280148 Binary files /dev/null and b/app/assets/images/emoji/vulcan_tone4.png differ diff --git a/app/assets/images/emoji/vulcan_tone5.png b/app/assets/images/emoji/vulcan_tone5.png new file mode 100644 index 00000000000..60b5c6077be Binary files /dev/null and b/app/assets/images/emoji/vulcan_tone5.png differ diff --git a/app/assets/images/emoji/walking.png b/app/assets/images/emoji/walking.png new file mode 100644 index 00000000000..06dc169a3fd Binary files /dev/null and b/app/assets/images/emoji/walking.png differ diff --git a/app/assets/images/emoji/walking_tone1.png b/app/assets/images/emoji/walking_tone1.png new file mode 100644 index 00000000000..4e391b45a0b Binary files /dev/null and b/app/assets/images/emoji/walking_tone1.png differ diff --git a/app/assets/images/emoji/walking_tone2.png b/app/assets/images/emoji/walking_tone2.png new file mode 100644 index 00000000000..31f94a1bce1 Binary files /dev/null and b/app/assets/images/emoji/walking_tone2.png differ diff --git a/app/assets/images/emoji/walking_tone3.png b/app/assets/images/emoji/walking_tone3.png new file mode 100644 index 00000000000..f7ed8e39c2e Binary files /dev/null and b/app/assets/images/emoji/walking_tone3.png differ diff --git a/app/assets/images/emoji/walking_tone4.png b/app/assets/images/emoji/walking_tone4.png new file mode 100644 index 00000000000..e58dc04c7b2 Binary files /dev/null and b/app/assets/images/emoji/walking_tone4.png differ diff --git a/app/assets/images/emoji/walking_tone5.png b/app/assets/images/emoji/walking_tone5.png new file mode 100644 index 00000000000..ba4e1b58fcb Binary files /dev/null and b/app/assets/images/emoji/walking_tone5.png differ diff --git a/app/assets/images/emoji/waning_crescent_moon.png b/app/assets/images/emoji/waning_crescent_moon.png new file mode 100644 index 00000000000..cf68706b871 Binary files /dev/null and b/app/assets/images/emoji/waning_crescent_moon.png differ diff --git a/app/assets/images/emoji/waning_gibbous_moon.png b/app/assets/images/emoji/waning_gibbous_moon.png new file mode 100644 index 00000000000..24e16266119 Binary files /dev/null and b/app/assets/images/emoji/waning_gibbous_moon.png differ diff --git a/app/assets/images/emoji/warning.png b/app/assets/images/emoji/warning.png new file mode 100644 index 00000000000..35691c2ed97 Binary files /dev/null and b/app/assets/images/emoji/warning.png differ diff --git a/app/assets/images/emoji/wastebasket.png b/app/assets/images/emoji/wastebasket.png new file mode 100644 index 00000000000..2b3c484b498 Binary files /dev/null and b/app/assets/images/emoji/wastebasket.png differ diff --git a/app/assets/images/emoji/watch.png b/app/assets/images/emoji/watch.png new file mode 100644 index 00000000000..64819bc6e21 Binary files /dev/null and b/app/assets/images/emoji/watch.png differ diff --git a/app/assets/images/emoji/water_buffalo.png b/app/assets/images/emoji/water_buffalo.png new file mode 100644 index 00000000000..80446615caf Binary files /dev/null and b/app/assets/images/emoji/water_buffalo.png differ diff --git a/app/assets/images/emoji/water_polo.png b/app/assets/images/emoji/water_polo.png new file mode 100644 index 00000000000..cb44576780d Binary files /dev/null and b/app/assets/images/emoji/water_polo.png differ diff --git a/app/assets/images/emoji/water_polo_tone1.png b/app/assets/images/emoji/water_polo_tone1.png new file mode 100644 index 00000000000..bed1a908d6a Binary files /dev/null and b/app/assets/images/emoji/water_polo_tone1.png differ diff --git a/app/assets/images/emoji/water_polo_tone2.png b/app/assets/images/emoji/water_polo_tone2.png new file mode 100644 index 00000000000..ec5a43b4d4a Binary files /dev/null and b/app/assets/images/emoji/water_polo_tone2.png differ diff --git a/app/assets/images/emoji/water_polo_tone3.png b/app/assets/images/emoji/water_polo_tone3.png new file mode 100644 index 00000000000..b081a4a5a96 Binary files /dev/null and b/app/assets/images/emoji/water_polo_tone3.png differ diff --git a/app/assets/images/emoji/water_polo_tone4.png b/app/assets/images/emoji/water_polo_tone4.png new file mode 100644 index 00000000000..82cfbc3b0c7 Binary files /dev/null and b/app/assets/images/emoji/water_polo_tone4.png differ diff --git a/app/assets/images/emoji/water_polo_tone5.png b/app/assets/images/emoji/water_polo_tone5.png new file mode 100644 index 00000000000..bd3366eb06c Binary files /dev/null and b/app/assets/images/emoji/water_polo_tone5.png differ diff --git a/app/assets/images/emoji/watermelon.png b/app/assets/images/emoji/watermelon.png new file mode 100644 index 00000000000..0761488b4c9 Binary files /dev/null and b/app/assets/images/emoji/watermelon.png differ diff --git a/app/assets/images/emoji/wave.png b/app/assets/images/emoji/wave.png new file mode 100644 index 00000000000..e0cd79b45f5 Binary files /dev/null and b/app/assets/images/emoji/wave.png differ diff --git a/app/assets/images/emoji/wave_tone1.png b/app/assets/images/emoji/wave_tone1.png new file mode 100644 index 00000000000..6b2b34b106e Binary files /dev/null and b/app/assets/images/emoji/wave_tone1.png differ diff --git a/app/assets/images/emoji/wave_tone2.png b/app/assets/images/emoji/wave_tone2.png new file mode 100644 index 00000000000..b857119732e Binary files /dev/null and b/app/assets/images/emoji/wave_tone2.png differ diff --git a/app/assets/images/emoji/wave_tone3.png b/app/assets/images/emoji/wave_tone3.png new file mode 100644 index 00000000000..6283b670f43 Binary files /dev/null and b/app/assets/images/emoji/wave_tone3.png differ diff --git a/app/assets/images/emoji/wave_tone4.png b/app/assets/images/emoji/wave_tone4.png new file mode 100644 index 00000000000..fe6b2baa747 Binary files /dev/null and b/app/assets/images/emoji/wave_tone4.png differ diff --git a/app/assets/images/emoji/wave_tone5.png b/app/assets/images/emoji/wave_tone5.png new file mode 100644 index 00000000000..4bd168ebb78 Binary files /dev/null and b/app/assets/images/emoji/wave_tone5.png differ diff --git a/app/assets/images/emoji/wavy_dash.png b/app/assets/images/emoji/wavy_dash.png new file mode 100644 index 00000000000..001c8d6e47d Binary files /dev/null and b/app/assets/images/emoji/wavy_dash.png differ diff --git a/app/assets/images/emoji/waxing_crescent_moon.png b/app/assets/images/emoji/waxing_crescent_moon.png new file mode 100644 index 00000000000..687125173d9 Binary files /dev/null and b/app/assets/images/emoji/waxing_crescent_moon.png differ diff --git a/app/assets/images/emoji/waxing_gibbous_moon.png b/app/assets/images/emoji/waxing_gibbous_moon.png new file mode 100644 index 00000000000..3a808156318 Binary files /dev/null and b/app/assets/images/emoji/waxing_gibbous_moon.png differ diff --git a/app/assets/images/emoji/wc.png b/app/assets/images/emoji/wc.png new file mode 100644 index 00000000000..aa433e84ba6 Binary files /dev/null and b/app/assets/images/emoji/wc.png differ diff --git a/app/assets/images/emoji/weary.png b/app/assets/images/emoji/weary.png new file mode 100644 index 00000000000..98bfbd24a16 Binary files /dev/null and b/app/assets/images/emoji/weary.png differ diff --git a/app/assets/images/emoji/wedding.png b/app/assets/images/emoji/wedding.png new file mode 100644 index 00000000000..d0d8aa0bfae Binary files /dev/null and b/app/assets/images/emoji/wedding.png differ diff --git a/app/assets/images/emoji/whale.png b/app/assets/images/emoji/whale.png new file mode 100644 index 00000000000..9f19b44257c Binary files /dev/null and b/app/assets/images/emoji/whale.png differ diff --git a/app/assets/images/emoji/whale2.png b/app/assets/images/emoji/whale2.png new file mode 100644 index 00000000000..0df9d3c73a4 Binary files /dev/null and b/app/assets/images/emoji/whale2.png differ diff --git a/app/assets/images/emoji/wheel_of_dharma.png b/app/assets/images/emoji/wheel_of_dharma.png new file mode 100644 index 00000000000..3666db0016b Binary files /dev/null and b/app/assets/images/emoji/wheel_of_dharma.png differ diff --git a/app/assets/images/emoji/wheelchair.png b/app/assets/images/emoji/wheelchair.png new file mode 100644 index 00000000000..4e5b2698eac Binary files /dev/null and b/app/assets/images/emoji/wheelchair.png differ diff --git a/app/assets/images/emoji/white_check_mark.png b/app/assets/images/emoji/white_check_mark.png new file mode 100644 index 00000000000..e55f087e544 Binary files /dev/null and b/app/assets/images/emoji/white_check_mark.png differ diff --git a/app/assets/images/emoji/white_circle.png b/app/assets/images/emoji/white_circle.png new file mode 100644 index 00000000000..c19e15684dd Binary files /dev/null and b/app/assets/images/emoji/white_circle.png differ diff --git a/app/assets/images/emoji/white_flower.png b/app/assets/images/emoji/white_flower.png new file mode 100644 index 00000000000..d6af8b60077 Binary files /dev/null and b/app/assets/images/emoji/white_flower.png differ diff --git a/app/assets/images/emoji/white_large_square.png b/app/assets/images/emoji/white_large_square.png new file mode 100644 index 00000000000..6f06c1c79de Binary files /dev/null and b/app/assets/images/emoji/white_large_square.png differ diff --git a/app/assets/images/emoji/white_medium_small_square.png b/app/assets/images/emoji/white_medium_small_square.png new file mode 100644 index 00000000000..ae874126750 Binary files /dev/null and b/app/assets/images/emoji/white_medium_small_square.png differ diff --git a/app/assets/images/emoji/white_medium_square.png b/app/assets/images/emoji/white_medium_square.png new file mode 100644 index 00000000000..8daacf57059 Binary files /dev/null and b/app/assets/images/emoji/white_medium_square.png differ diff --git a/app/assets/images/emoji/white_small_square.png b/app/assets/images/emoji/white_small_square.png new file mode 100644 index 00000000000..d7ebdb0c0ed Binary files /dev/null and b/app/assets/images/emoji/white_small_square.png differ diff --git a/app/assets/images/emoji/white_square_button.png b/app/assets/images/emoji/white_square_button.png new file mode 100644 index 00000000000..934b1cedfd2 Binary files /dev/null and b/app/assets/images/emoji/white_square_button.png differ diff --git a/app/assets/images/emoji/white_sun_cloud.png b/app/assets/images/emoji/white_sun_cloud.png new file mode 100644 index 00000000000..0a4cc100269 Binary files /dev/null and b/app/assets/images/emoji/white_sun_cloud.png differ diff --git a/app/assets/images/emoji/white_sun_rain_cloud.png b/app/assets/images/emoji/white_sun_rain_cloud.png new file mode 100644 index 00000000000..491f9ca4839 Binary files /dev/null and b/app/assets/images/emoji/white_sun_rain_cloud.png differ diff --git a/app/assets/images/emoji/white_sun_small_cloud.png b/app/assets/images/emoji/white_sun_small_cloud.png new file mode 100644 index 00000000000..cead0bfa521 Binary files /dev/null and b/app/assets/images/emoji/white_sun_small_cloud.png differ diff --git a/app/assets/images/emoji/wilted_rose.png b/app/assets/images/emoji/wilted_rose.png new file mode 100644 index 00000000000..62412b143ae Binary files /dev/null and b/app/assets/images/emoji/wilted_rose.png differ diff --git a/app/assets/images/emoji/wind_blowing_face.png b/app/assets/images/emoji/wind_blowing_face.png new file mode 100644 index 00000000000..df81b652eb6 Binary files /dev/null and b/app/assets/images/emoji/wind_blowing_face.png differ diff --git a/app/assets/images/emoji/wind_chime.png b/app/assets/images/emoji/wind_chime.png new file mode 100644 index 00000000000..3c9ef3a95f6 Binary files /dev/null and b/app/assets/images/emoji/wind_chime.png differ diff --git a/app/assets/images/emoji/wine_glass.png b/app/assets/images/emoji/wine_glass.png new file mode 100644 index 00000000000..3cc98689192 Binary files /dev/null and b/app/assets/images/emoji/wine_glass.png differ diff --git a/app/assets/images/emoji/wink.png b/app/assets/images/emoji/wink.png new file mode 100644 index 00000000000..7ea7810a37d Binary files /dev/null and b/app/assets/images/emoji/wink.png differ diff --git a/app/assets/images/emoji/wolf.png b/app/assets/images/emoji/wolf.png new file mode 100644 index 00000000000..ba7220f2de9 Binary files /dev/null and b/app/assets/images/emoji/wolf.png differ diff --git a/app/assets/images/emoji/woman.png b/app/assets/images/emoji/woman.png new file mode 100644 index 00000000000..ece440e7a61 Binary files /dev/null and b/app/assets/images/emoji/woman.png differ diff --git a/app/assets/images/emoji/woman_tone1.png b/app/assets/images/emoji/woman_tone1.png new file mode 100644 index 00000000000..ff089b8889b Binary files /dev/null and b/app/assets/images/emoji/woman_tone1.png differ diff --git a/app/assets/images/emoji/woman_tone2.png b/app/assets/images/emoji/woman_tone2.png new file mode 100644 index 00000000000..0719c378016 Binary files /dev/null and b/app/assets/images/emoji/woman_tone2.png differ diff --git a/app/assets/images/emoji/woman_tone3.png b/app/assets/images/emoji/woman_tone3.png new file mode 100644 index 00000000000..5672e2fd52d Binary files /dev/null and b/app/assets/images/emoji/woman_tone3.png differ diff --git a/app/assets/images/emoji/woman_tone4.png b/app/assets/images/emoji/woman_tone4.png new file mode 100644 index 00000000000..5754aab558b Binary files /dev/null and b/app/assets/images/emoji/woman_tone4.png differ diff --git a/app/assets/images/emoji/woman_tone5.png b/app/assets/images/emoji/woman_tone5.png new file mode 100644 index 00000000000..fc252af3a39 Binary files /dev/null and b/app/assets/images/emoji/woman_tone5.png differ diff --git a/app/assets/images/emoji/womans_clothes.png b/app/assets/images/emoji/womans_clothes.png new file mode 100644 index 00000000000..01410dc8107 Binary files /dev/null and b/app/assets/images/emoji/womans_clothes.png differ diff --git a/app/assets/images/emoji/womans_hat.png b/app/assets/images/emoji/womans_hat.png new file mode 100644 index 00000000000..b837b6a2e47 Binary files /dev/null and b/app/assets/images/emoji/womans_hat.png differ diff --git a/app/assets/images/emoji/womens.png b/app/assets/images/emoji/womens.png new file mode 100644 index 00000000000..d4ecc22e7b3 Binary files /dev/null and b/app/assets/images/emoji/womens.png differ diff --git a/app/assets/images/emoji/worried.png b/app/assets/images/emoji/worried.png new file mode 100644 index 00000000000..7074afcf5b7 Binary files /dev/null and b/app/assets/images/emoji/worried.png differ diff --git a/app/assets/images/emoji/wrench.png b/app/assets/images/emoji/wrench.png new file mode 100644 index 00000000000..c16b7439697 Binary files /dev/null and b/app/assets/images/emoji/wrench.png differ diff --git a/app/assets/images/emoji/wrestlers.png b/app/assets/images/emoji/wrestlers.png new file mode 100644 index 00000000000..71e67cfad85 Binary files /dev/null and b/app/assets/images/emoji/wrestlers.png differ diff --git a/app/assets/images/emoji/wrestlers_tone1.png b/app/assets/images/emoji/wrestlers_tone1.png new file mode 100644 index 00000000000..379070fd03b Binary files /dev/null and b/app/assets/images/emoji/wrestlers_tone1.png differ diff --git a/app/assets/images/emoji/wrestlers_tone2.png b/app/assets/images/emoji/wrestlers_tone2.png new file mode 100644 index 00000000000..6863ea9209d Binary files /dev/null and b/app/assets/images/emoji/wrestlers_tone2.png differ diff --git a/app/assets/images/emoji/wrestlers_tone3.png b/app/assets/images/emoji/wrestlers_tone3.png new file mode 100644 index 00000000000..b7e62910127 Binary files /dev/null and b/app/assets/images/emoji/wrestlers_tone3.png differ diff --git a/app/assets/images/emoji/wrestlers_tone4.png b/app/assets/images/emoji/wrestlers_tone4.png new file mode 100644 index 00000000000..750f9589233 Binary files /dev/null and b/app/assets/images/emoji/wrestlers_tone4.png differ diff --git a/app/assets/images/emoji/wrestlers_tone5.png b/app/assets/images/emoji/wrestlers_tone5.png new file mode 100644 index 00000000000..36ab9bb3f42 Binary files /dev/null and b/app/assets/images/emoji/wrestlers_tone5.png differ diff --git a/app/assets/images/emoji/writing_hand.png b/app/assets/images/emoji/writing_hand.png new file mode 100644 index 00000000000..85639f8ac40 Binary files /dev/null and b/app/assets/images/emoji/writing_hand.png differ diff --git a/app/assets/images/emoji/writing_hand_tone1.png b/app/assets/images/emoji/writing_hand_tone1.png new file mode 100644 index 00000000000..7923d8ebb17 Binary files /dev/null and b/app/assets/images/emoji/writing_hand_tone1.png differ diff --git a/app/assets/images/emoji/writing_hand_tone2.png b/app/assets/images/emoji/writing_hand_tone2.png new file mode 100644 index 00000000000..bcb304e15d2 Binary files /dev/null and b/app/assets/images/emoji/writing_hand_tone2.png differ diff --git a/app/assets/images/emoji/writing_hand_tone3.png b/app/assets/images/emoji/writing_hand_tone3.png new file mode 100644 index 00000000000..fd885fd2d90 Binary files /dev/null and b/app/assets/images/emoji/writing_hand_tone3.png differ diff --git a/app/assets/images/emoji/writing_hand_tone4.png b/app/assets/images/emoji/writing_hand_tone4.png new file mode 100644 index 00000000000..d065b8c64ab Binary files /dev/null and b/app/assets/images/emoji/writing_hand_tone4.png differ diff --git a/app/assets/images/emoji/writing_hand_tone5.png b/app/assets/images/emoji/writing_hand_tone5.png new file mode 100644 index 00000000000..a44b3dd757c Binary files /dev/null and b/app/assets/images/emoji/writing_hand_tone5.png differ diff --git a/app/assets/images/emoji/x.png b/app/assets/images/emoji/x.png new file mode 100644 index 00000000000..9f9ed0f7ad2 Binary files /dev/null and b/app/assets/images/emoji/x.png differ diff --git a/app/assets/images/emoji/yellow_heart.png b/app/assets/images/emoji/yellow_heart.png new file mode 100644 index 00000000000..7901a9d0103 Binary files /dev/null and b/app/assets/images/emoji/yellow_heart.png differ diff --git a/app/assets/images/emoji/yen.png b/app/assets/images/emoji/yen.png new file mode 100644 index 00000000000..63ee4799d66 Binary files /dev/null and b/app/assets/images/emoji/yen.png differ diff --git a/app/assets/images/emoji/yin_yang.png b/app/assets/images/emoji/yin_yang.png new file mode 100644 index 00000000000..f2900f6338f Binary files /dev/null and b/app/assets/images/emoji/yin_yang.png differ diff --git a/app/assets/images/emoji/yum.png b/app/assets/images/emoji/yum.png new file mode 100644 index 00000000000..2df15753ca1 Binary files /dev/null and b/app/assets/images/emoji/yum.png differ diff --git a/app/assets/images/emoji/zap.png b/app/assets/images/emoji/zap.png new file mode 100644 index 00000000000..47e68e48e49 Binary files /dev/null and b/app/assets/images/emoji/zap.png differ diff --git a/app/assets/images/emoji/zero.png b/app/assets/images/emoji/zero.png new file mode 100644 index 00000000000..13aca83e018 Binary files /dev/null and b/app/assets/images/emoji/zero.png differ diff --git a/app/assets/images/emoji/zipper_mouth.png b/app/assets/images/emoji/zipper_mouth.png new file mode 100644 index 00000000000..f8ced2502a7 Binary files /dev/null and b/app/assets/images/emoji/zipper_mouth.png differ diff --git a/app/assets/images/emoji/zzz.png b/app/assets/images/emoji/zzz.png new file mode 100644 index 00000000000..9bc72b4469f Binary files /dev/null and b/app/assets/images/emoji/zzz.png differ diff --git a/app/assets/images/emoji@2x.png b/app/assets/images/emoji@2x.png index dc9cae1d44c..b0fa9e1139e 100644 Binary files a/app/assets/images/emoji@2x.png and b/app/assets/images/emoji@2x.png differ diff --git a/app/assets/images/icon-merge-request-unmerged.svg b/app/assets/images/icon-merge-request-unmerged.svg new file mode 100644 index 00000000000..c4d8e65122d --- /dev/null +++ b/app/assets/images/icon-merge-request-unmerged.svg @@ -0,0 +1 @@ + diff --git a/app/assets/images/mailers/gitlab_footer_logo.gif b/app/assets/images/mailers/gitlab_footer_logo.gif new file mode 100644 index 00000000000..3f4ef31947b Binary files /dev/null and b/app/assets/images/mailers/gitlab_footer_logo.gif differ diff --git a/app/assets/images/mailers/gitlab_header_logo.gif b/app/assets/images/mailers/gitlab_header_logo.gif new file mode 100644 index 00000000000..387628f831c Binary files /dev/null and b/app/assets/images/mailers/gitlab_header_logo.gif differ diff --git a/app/assets/javascripts/abuse_reports.js b/app/assets/javascripts/abuse_reports.js new file mode 100644 index 00000000000..346de4ad11e --- /dev/null +++ b/app/assets/javascripts/abuse_reports.js @@ -0,0 +1,37 @@ +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(window.gl.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))}...`); + } + } +} + +window.gl = window.gl || {}; +window.gl.AbuseReports = AbuseReports; diff --git a/app/assets/javascripts/abuse_reports.js.es6 b/app/assets/javascripts/abuse_reports.js.es6 deleted file mode 100644 index 8a260aae1b1..00000000000 --- a/app/assets/javascripts/abuse_reports.js.es6 +++ /dev/null @@ -1,40 +0,0 @@ -/* eslint-disable no-param-reassign */ - -((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 = {})); diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js new file mode 100644 index 00000000000..aebda7780e1 --- /dev/null +++ b/app/assets/javascripts/activities.js @@ -0,0 +1,36 @@ +/* eslint-disable no-param-reassign, class-methods-use-this */ +/* global Pager */ +/* global Cookies */ + +class Activities { + constructor() { + Pager.init(20, true, false, this.updateTooltips); + $('.event-filter-link').on('click', (e) => { + e.preventDefault(); + this.toggleFilter(e.currentTarget); + this.reloadActivities(); + }); + } + + updateTooltips() { + gl.utils.localTimeAgo($('.js-timeago', '.content_list')); + } + + reloadActivities() { + $('.content_list').html(''); + Pager.init(20, true, false, this.updateTooltips); + } + + toggleFilter(sender) { + const $sender = $(sender); + const filter = $sender.attr('id').split('_')[0]; + + $('.event-filter .active').removeClass('active'); + Cookies.set('event_filter', filter); + + $sender.closest('li').toggleClass('active'); + } +} + +window.gl = window.gl || {}; +window.gl.Activities = Activities; diff --git a/app/assets/javascripts/activities.js.es6 b/app/assets/javascripts/activities.js.es6 deleted file mode 100644 index 648cb4d5d85..00000000000 --- a/app/assets/javascripts/activities.js.es6 +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable no-param-reassign, class-methods-use-this */ -/* global Pager */ -/* global Cookies */ - -((global) => { - class Activities { - constructor() { - Pager.init(20, true, false, this.updateTooltips); - $('.event-filter-link').on('click', (e) => { - e.preventDefault(); - this.toggleFilter(e.currentTarget); - this.reloadActivities(); - }); - } - - updateTooltips() { - gl.utils.localTimeAgo($('.js-timeago', '.content_list')); - } - - reloadActivities() { - $('.content_list').html(''); - Pager.init(20, true, false, this.updateTooltips); - } - - toggleFilter(sender) { - const $sender = $(sender); - const filter = $sender.attr('id').split('_')[0]; - - $('.event-filter .active').removeClass('active'); - Cookies.set('event_filter', filter); - - $sender.closest('li').toggleClass('active'); - } - } - - global.Activities = Activities; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index aaed74d6073..34669dd13d6 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -1,64 +1,62 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-arrow-callback, camelcase, quotes, comma-dangle, max-len */ -(function() { - this.Admin = (function() { - function Admin() { - var modal, showBlacklistType; - $('input#user_force_random_password').on('change', function(elem) { - var elems; - elems = $('#user_password, #user_password_confirmation'); - if ($(this).attr('checked')) { - return elems.val('').attr('disabled', true); - } else { - return elems.removeAttr('disabled'); - } - }); - $('body').on('click', '.js-toggle-colors-link', function(e) { - e.preventDefault(); - return $('.js-toggle-colors-container').toggle(); - }); - $('.log-tabs a').click(function(e) { - e.preventDefault(); - return $(this).tab('show'); - }); - $('.log-bottom').click(function(e) { - var visible_log; - e.preventDefault(); - visible_log = $(".file-content:visible"); - return visible_log.animate({ - scrollTop: visible_log.find('ol').height() - }, "fast"); - }); - modal = $('.change-owner-holder'); - $('.change-owner-link').bind("click", function(e) { - e.preventDefault(); - $(this).hide(); - return modal.show(); - }); - $('.change-owner-cancel-link').bind("click", function(e) { - e.preventDefault(); - modal.hide(); - return $('.change-owner-link').show(); - }); - $('li.project_member').bind('ajax:success', function() { - return gl.utils.refreshCurrentPage(); - }); - $('li.group_member').bind('ajax:success', function() { - return gl.utils.refreshCurrentPage(); - }); - showBlacklistType = function() { - if ($("input[name='blacklist_type']:checked").val() === 'file') { - $('.blacklist-file').show(); - return $('.blacklist-raw').hide(); - } else { - $('.blacklist-file').hide(); - return $('.blacklist-raw').show(); - } - }; - $("input[name='blacklist_type']").click(showBlacklistType); - showBlacklistType(); - } +window.Admin = (function() { + function Admin() { + var modal, showBlacklistType; + $('input#user_force_random_password').on('change', function(elem) { + var elems; + elems = $('#user_password, #user_password_confirmation'); + if ($(this).attr('checked')) { + return elems.val('').attr('disabled', true); + } else { + return elems.removeAttr('disabled'); + } + }); + $('body').on('click', '.js-toggle-colors-link', function(e) { + e.preventDefault(); + return $('.js-toggle-colors-container').toggle(); + }); + $('.log-tabs a').click(function(e) { + e.preventDefault(); + return $(this).tab('show'); + }); + $('.log-bottom').click(function(e) { + var visible_log; + e.preventDefault(); + visible_log = $(".file-content:visible"); + return visible_log.animate({ + scrollTop: visible_log.find('ol').height() + }, "fast"); + }); + modal = $('.change-owner-holder'); + $('.change-owner-link').bind("click", function(e) { + e.preventDefault(); + $(this).hide(); + return modal.show(); + }); + $('.change-owner-cancel-link').bind("click", function(e) { + e.preventDefault(); + modal.hide(); + return $('.change-owner-link').show(); + }); + $('li.project_member').bind('ajax:success', function() { + return gl.utils.refreshCurrentPage(); + }); + $('li.group_member').bind('ajax:success', function() { + return gl.utils.refreshCurrentPage(); + }); + showBlacklistType = function() { + if ($("input[name='blacklist_type']:checked").val() === 'file') { + $('.blacklist-file').show(); + return $('.blacklist-raw').hide(); + } else { + $('.blacklist-file').hide(); + return $('.blacklist-raw').show(); + } + }; + $("input[name='blacklist_type']").click(showBlacklistType); + showBlacklistType(); + } - return Admin; - })(); -}).call(window); + return Admin; +})(); diff --git a/app/assets/javascripts/ajax_loading_spinner.js b/app/assets/javascripts/ajax_loading_spinner.js new file mode 100644 index 00000000000..38a8317dbd7 --- /dev/null +++ b/app/assets/javascripts/ajax_loading_spinner.js @@ -0,0 +1,35 @@ +class AjaxLoadingSpinner { + static init() { + const $elements = $('.js-ajax-loading-spinner'); + + $elements.on('ajax:beforeSend', AjaxLoadingSpinner.ajaxBeforeSend); + $elements.on('ajax:complete', AjaxLoadingSpinner.ajaxComplete); + } + + static ajaxBeforeSend(e) { + e.target.setAttribute('disabled', ''); + const iconElement = e.target.querySelector('i'); + // get first fa- icon + const originalIcon = iconElement.className.match(/(fa-)([^\s]+)/g).first(); + iconElement.dataset.icon = originalIcon; + AjaxLoadingSpinner.toggleLoadingIcon(iconElement); + $(e.target).off('ajax:beforeSend', AjaxLoadingSpinner.ajaxBeforeSend); + } + + static ajaxComplete(e) { + e.target.removeAttribute('disabled'); + const iconElement = e.target.querySelector('i'); + AjaxLoadingSpinner.toggleLoadingIcon(iconElement); + $(e.target).off('ajax:complete', AjaxLoadingSpinner.ajaxComplete); + } + + static toggleLoadingIcon(iconElement) { + const classList = iconElement.classList; + classList.toggle(iconElement.dataset.icon); + classList.toggle('fa-spinner'); + classList.toggle('fa-spin'); + } +} + +window.gl = window.gl || {}; +gl.AjaxLoadingSpinner = AjaxLoadingSpinner; diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 86e0ad89431..e5f36c84987 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -1,150 +1,148 @@ /* eslint-disable func-names, space-before-function-paren, quotes, object-shorthand, camelcase, no-var, comma-dangle, prefer-arrow-callback, quote-props, no-param-reassign, max-len */ -(function() { - var Api = { - groupsPath: "/api/:version/groups.json", - groupPath: "/api/:version/groups/:id.json", - namespacesPath: "/api/:version/namespaces.json", - groupProjectsPath: "/api/:version/groups/:id/projects.json", - projectsPath: "/api/:version/projects.json?simple=true", - labelsPath: "/:namespace_path/:project_path/labels", - licensePath: "/api/:version/templates/licenses/:key", - gitignorePath: "/api/:version/templates/gitignores/:key", - gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key", - dockerfilePath: "/api/:version/templates/dockerfiles/:key", - issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key", - group: function(group_id, callback) { - var url = Api.buildUrl(Api.groupPath) - .replace(':id', group_id); - return $.ajax({ - url: url, - dataType: "json" - }).done(function(group) { - return callback(group); - }); - }, - // Return groups list. Filtered by query - groups: function(query, options, callback) { - var url = Api.buildUrl(Api.groupsPath); - return $.ajax({ - url: url, - data: $.extend({ - search: query, - per_page: 20 - }, options), - dataType: "json" - }).done(function(groups) { - return callback(groups); - }); - }, - // Return namespaces list. Filtered by query - namespaces: function(query, callback) { - var url = Api.buildUrl(Api.namespacesPath); - return $.ajax({ - url: url, - data: { - search: query, - per_page: 20 - }, - dataType: "json" - }).done(function(namespaces) { - return callback(namespaces); - }); - }, - // Return projects list. Filtered by query - projects: function(query, order, callback) { - var url = Api.buildUrl(Api.projectsPath); - return $.ajax({ - url: url, - data: { - search: query, - order_by: order, - per_page: 20 - }, - dataType: "json" - }).done(function(projects) { - return callback(projects); - }); - }, - newLabel: function(namespace_path, project_path, data, callback) { - var url = Api.buildUrl(Api.labelsPath) - .replace(':namespace_path', namespace_path) - .replace(':project_path', project_path); - return $.ajax({ - url: url, - type: "POST", - data: { 'label': data }, - dataType: "json" - }).done(function(label) { - return callback(label); - }).error(function(message) { - return callback(message.responseJSON); - }); - }, - // Return group projects list. Filtered by query - groupProjects: function(group_id, query, callback) { - var url = Api.buildUrl(Api.groupProjectsPath) - .replace(':id', group_id); - return $.ajax({ - url: url, - data: { - search: query, - per_page: 20 - }, - dataType: "json" - }).done(function(projects) { - return callback(projects); - }); - }, - // Return text for a specific license - licenseText: function(key, data, callback) { - var url = Api.buildUrl(Api.licensePath) - .replace(':key', key); - return $.ajax({ - url: url, - data: data - }).done(function(license) { - return callback(license); - }); - }, - gitignoreText: function(key, callback) { - var url = Api.buildUrl(Api.gitignorePath) - .replace(':key', key); - return $.get(url, function(gitignore) { - return callback(gitignore); - }); - }, - gitlabCiYml: function(key, callback) { - var url = Api.buildUrl(Api.gitlabCiYmlPath) - .replace(':key', key); - return $.get(url, function(file) { - return callback(file); - }); - }, - dockerfileYml: function(key, callback) { - var url = Api.buildUrl(Api.dockerfilePath).replace(':key', key); - $.get(url, callback); - }, - issueTemplate: function(namespacePath, projectPath, key, type, callback) { - var url = Api.buildUrl(Api.issuableTemplatePath) - .replace(':key', key) - .replace(':type', type) - .replace(':project_path', projectPath) - .replace(':namespace_path', namespacePath); - $.ajax({ - url: url, - dataType: 'json' - }).done(function(file) { - callback(null, file); - }).error(callback); - }, - buildUrl: function(url) { - if (gon.relative_url_root != null) { - url = gon.relative_url_root + url; - } - return url.replace(':version', gon.api_version); +var Api = { + groupsPath: "/api/:version/groups.json", + groupPath: "/api/:version/groups/:id.json", + namespacesPath: "/api/:version/namespaces.json", + groupProjectsPath: "/api/:version/groups/:id/projects.json", + projectsPath: "/api/:version/projects.json?simple=true", + labelsPath: "/:namespace_path/:project_path/labels", + licensePath: "/api/:version/templates/licenses/:key", + gitignorePath: "/api/:version/templates/gitignores/:key", + gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key", + dockerfilePath: "/api/:version/templates/dockerfiles/:key", + issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key", + group: function(group_id, callback) { + var url = Api.buildUrl(Api.groupPath) + .replace(':id', group_id); + return $.ajax({ + url: url, + dataType: "json" + }).done(function(group) { + return callback(group); + }); + }, + // Return groups list. Filtered by query + groups: function(query, options, callback) { + var url = Api.buildUrl(Api.groupsPath); + return $.ajax({ + url: url, + data: $.extend({ + search: query, + per_page: 20 + }, options), + dataType: "json" + }).done(function(groups) { + return callback(groups); + }); + }, + // Return namespaces list. Filtered by query + namespaces: function(query, callback) { + var url = Api.buildUrl(Api.namespacesPath); + return $.ajax({ + url: url, + data: { + search: query, + per_page: 20 + }, + dataType: "json" + }).done(function(namespaces) { + return callback(namespaces); + }); + }, + // Return projects list. Filtered by query + projects: function(query, options, callback) { + var url = Api.buildUrl(Api.projectsPath); + return $.ajax({ + url: url, + data: $.extend({ + search: query, + per_page: 20, + membership: true + }, options), + dataType: "json" + }).done(function(projects) { + return callback(projects); + }); + }, + newLabel: function(namespace_path, project_path, data, callback) { + var url = Api.buildUrl(Api.labelsPath) + .replace(':namespace_path', namespace_path) + .replace(':project_path', project_path); + return $.ajax({ + url: url, + type: "POST", + data: { 'label': data }, + dataType: "json" + }).done(function(label) { + return callback(label); + }).error(function(message) { + return callback(message.responseJSON); + }); + }, + // Return group projects list. Filtered by query + groupProjects: function(group_id, query, callback) { + var url = Api.buildUrl(Api.groupProjectsPath) + .replace(':id', group_id); + return $.ajax({ + url: url, + data: { + search: query, + per_page: 20 + }, + dataType: "json" + }).done(function(projects) { + return callback(projects); + }); + }, + // Return text for a specific license + licenseText: function(key, data, callback) { + var url = Api.buildUrl(Api.licensePath) + .replace(':key', key); + return $.ajax({ + url: url, + data: data + }).done(function(license) { + return callback(license); + }); + }, + gitignoreText: function(key, callback) { + var url = Api.buildUrl(Api.gitignorePath) + .replace(':key', key); + return $.get(url, function(gitignore) { + return callback(gitignore); + }); + }, + gitlabCiYml: function(key, callback) { + var url = Api.buildUrl(Api.gitlabCiYmlPath) + .replace(':key', key); + return $.get(url, function(file) { + return callback(file); + }); + }, + dockerfileYml: function(key, callback) { + var url = Api.buildUrl(Api.dockerfilePath).replace(':key', key); + $.get(url, callback); + }, + issueTemplate: function(namespacePath, projectPath, key, type, callback) { + var url = Api.buildUrl(Api.issuableTemplatePath) + .replace(':key', key) + .replace(':type', type) + .replace(':project_path', projectPath) + .replace(':namespace_path', namespacePath); + $.ajax({ + url: url, + dataType: 'json' + }).done(function(file) { + callback(null, file); + }).error(callback); + }, + buildUrl: function(url) { + if (gon.relative_url_root != null) { + url = gon.relative_url_root + url; } - }; + return url.replace(':version', gon.api_version); + } +}; - window.Api = Api; -}).call(window); +window.Api = Api; diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js deleted file mode 100644 index 8e468faedbf..00000000000 --- a/app/assets/javascripts/application.js +++ /dev/null @@ -1,246 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, quotes, consistent-return, prefer-arrow-callback, comma-dangle, object-shorthand, no-new, max-len, no-multi-spaces, import/newline-after-import */ -/* global bp */ -/* global Cookies */ -/* global Flash */ -/* global ConfirmDangerModal */ -/* global AwardsHandler */ -/* global Aside */ - -function requireAll(context) { return context.keys().map(context); } - -window.$ = window.jQuery = require('jquery'); -require('jquery-ui/ui/autocomplete'); -require('jquery-ui/ui/draggable'); -require('jquery-ui/ui/effect-highlight'); -require('jquery-ui/ui/sortable'); -require('jquery-ujs'); -require('vendor/jquery.endless-scroll'); -require('vendor/jquery.highlight'); -require('vendor/jquery.waitforimages'); -require('vendor/jquery.caret'); -require('vendor/jquery.atwho'); -require('vendor/jquery.scrollTo'); -window.Cookies = require('js-cookie'); -require('./autosave'); -require('bootstrap/js/affix'); -require('bootstrap/js/alert'); -require('bootstrap/js/button'); -require('bootstrap/js/collapse'); -require('bootstrap/js/dropdown'); -require('bootstrap/js/modal'); -require('bootstrap/js/scrollspy'); -require('bootstrap/js/tab'); -require('bootstrap/js/transition'); -require('bootstrap/js/tooltip'); -require('bootstrap/js/popover'); -require('select2/select2.js'); -window.Pikaday = require('pikaday'); -window._ = require('underscore'); -window.Dropzone = require('dropzone'); -window.Sortable = require('vendor/Sortable'); -require('mousetrap'); -require('mousetrap/plugins/pause/mousetrap-pause'); -require('./shortcuts'); -require('./shortcuts_navigation'); -require('./shortcuts_dashboard_navigation'); -require('./shortcuts_issuable'); -require('./shortcuts_network'); -require('vendor/jquery.nicescroll'); -requireAll(require.context('./behaviors', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./blob', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./templates', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./commit', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./extensions', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./lib/utils', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./u2f', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('./droplab', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('.', false, /^\.\/(?!application\.js).*\.(js|es6)$/)); -require('vendor/fuzzaldrin-plus'); -require('es6-promise').polyfill(); - -(function () { - document.addEventListener('beforeunload', function () { - // Unbind scroll events - $(document).off('scroll'); - // Close any open tooltips - $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy'); - }); - - window.addEventListener('hashchange', gl.utils.handleLocationHash); - window.addEventListener('load', function onLoad() { - window.removeEventListener('load', onLoad, false); - gl.utils.handleLocationHash(); - }, false); - - $(function () { - var $body = $('body'); - var $document = $(document); - var $window = $(window); - var $sidebarGutterToggle = $('.js-sidebar-toggle'); - var $flash = $('.flash-container'); - var bootstrapBreakpoint = bp.getBreakpointSize(); - var fitSidebarForSize; - - // Set the default path for all cookies to GitLab's root directory - Cookies.defaults.path = gon.relative_url_root || '/'; - - // `hashchange` is not triggered when link target is already in window.location - $body.on('click', 'a[href^="#"]', function() { - var href = this.getAttribute('href'); - if (href.substr(1) === gl.utils.getLocationHash()) { - setTimeout(gl.utils.handleLocationHash, 1); - } - }); - - // prevent default action for disabled buttons - $('.btn').click(function(e) { - if ($(this).hasClass('disabled')) { - e.preventDefault(); - e.stopImmediatePropagation(); - return false; - } - }); - - $('.js-select-on-focus').on('focusin', function () { - return $(this).select().one('mouseup', function (e) { - 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 () { - $(this).tooltip('destroy') - .closest('li') - .fadeOut(); - }); - $('.js-remove-tr').bind('ajax:before', function () { - return $(this).hide(); - }); - $('.js-remove-tr').bind('ajax:success', function () { - return $(this).closest('tr').fadeOut(); - }); - $('select.select2').select2({ - width: 'resolve', - // Initialize select2 selects - dropdownAutoWidth: true - }); - $('.js-select2').bind('select2-close', function () { - return setTimeout((function () { - $('.select2-container-active').removeClass('select2-container-active'); - return $(':focus').blur(); - }), 1); - // Close select2 on escape - }); - // Initialize tooltips - $.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover'; - $body.tooltip({ - selector: '.has-tooltip, [data-toggle="tooltip"]', - placement: function (_, el) { - return $(el).data('placement') || 'bottom'; - } - }); - $('.trigger-submit').on('change', function () { - return $(this).parents('form').submit(); - // Form submitter - }); - gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true); - // Flash - if ($flash.length > 0) { - $flash.click(function () { - return $(this).fadeOut(); - }); - $flash.show(); - } - // Disable form buttons while a form is submitting - $body.on('ajax:complete, ajax:beforeSend, submit', 'form', function (e) { - var buttons; - buttons = $('[type="submit"]', this); - switch (e.type) { - case 'ajax:beforeSend': - case 'submit': - return buttons.disable(); - default: - return buttons.enable(); - } - }); - $(document).ajaxError(function (e, xhrObj) { - var ref = xhrObj.status; - if (xhrObj.status === 401) { - return new Flash('You need to be logged in.', 'alert'); - } else if (ref === 404 || ref === 500) { - return new Flash('Something went wrong on our end.', 'alert'); - } - }); - $('.account-box').hover(function () { - // Show/Hide the profile menu when hovering the account box - return $(this).toggleClass('hover'); - }); - $document.on('click', '.diff-content .js-show-suppressed-diff', function () { - var $container; - $container = $(this).parent(); - $container.next('table').show(); - return $container.remove(); - // Commit show suppressed diff - }); - $('.navbar-toggle').on('click', function () { - $('.header-content .title').toggle(); - $('.header-content .header-logo').toggle(); - $('.header-content .navbar-collapse').toggle(); - return $('.navbar-toggle').toggleClass('active'); - }); - // Show/hide comments on diff - $body.on('click', '.js-toggle-diff-comments', function (e) { - var $this = $(this); - var notesHolders = $this.closest('.diff-file').find('.notes_holder'); - $this.toggleClass('active'); - if ($this.hasClass('active')) { - notesHolders.show().find('.hide').show(); - } else { - notesHolders.hide(); - } - $this.trigger('blur'); - return e.preventDefault(); - }); - $document.off('click', '.js-confirm-danger'); - $document.on('click', '.js-confirm-danger', function (e) { - var btn = $(e.target); - var form = btn.closest('form'); - var text = btn.data('confirm-danger-message'); - e.preventDefault(); - return new ConfirmDangerModal(form, text); - }); - $('input[type="search"]').each(function () { - var $this = $(this); - $this.attr('value', $this.val()); - }); - $document.off('keyup', 'input[type="search"]').on('keyup', 'input[type="search"]', function () { - var $this; - $this = $(this); - return $this.attr('value', $this.val()); - }); - $document.off('breakpoint:change').on('breakpoint:change', function (e, breakpoint) { - var $gutterIcon; - if (breakpoint === 'sm' || breakpoint === 'xs') { - $gutterIcon = $sidebarGutterToggle.find('i'); - if ($gutterIcon.hasClass('fa-angle-double-right')) { - return $sidebarGutterToggle.trigger('click'); - } - } - }); - fitSidebarForSize = function () { - var oldBootstrapBreakpoint; - oldBootstrapBreakpoint = bootstrapBreakpoint; - bootstrapBreakpoint = bp.getBreakpointSize(); - if (bootstrapBreakpoint !== oldBootstrapBreakpoint) { - return $document.trigger('breakpoint:change', [bootstrapBreakpoint]); - } - }; - $window.off('resize.app').on('resize.app', function () { - return fitSidebarForSize(); - }); - gl.awardsHandler = new AwardsHandler(); - new Aside(); - - gl.utils.initTimeagoTimeout(); - }); -}).call(window); diff --git a/app/assets/javascripts/aside.js b/app/assets/javascripts/aside.js index 448e6e2cc78..88756884d16 100644 --- a/app/assets/javascripts/aside.js +++ b/app/assets/javascripts/aside.js @@ -1,25 +1,24 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, prefer-arrow-callback, no-var, one-var, one-var-declaration-per-line, no-else-return, max-len */ -(function() { - this.Aside = (function() { - function Aside() { - $(document).off("click", "a.show-aside"); - $(document).on("click", 'a.show-aside', function(e) { - var btn, icon; - e.preventDefault(); - btn = $(e.currentTarget); - icon = btn.find('i'); - if (icon.hasClass('fa-angle-left')) { - btn.parent().find('section').hide(); - btn.parent().find('aside').fadeIn(); - return icon.removeClass('fa-angle-left').addClass('fa-angle-right'); - } else { - btn.parent().find('aside').hide(); - btn.parent().find('section').fadeIn(); - return icon.removeClass('fa-angle-right').addClass('fa-angle-left'); - } - }); - } - return Aside; - })(); -}).call(window); +window.Aside = (function() { + function Aside() { + $(document).off("click", "a.show-aside"); + $(document).on("click", 'a.show-aside', function(e) { + var btn, icon; + e.preventDefault(); + btn = $(e.currentTarget); + icon = btn.find('i'); + if (icon.hasClass('fa-angle-left')) { + btn.parent().find('section').hide(); + btn.parent().find('aside').fadeIn(); + return icon.removeClass('fa-angle-left').addClass('fa-angle-right'); + } else { + btn.parent().find('aside').hide(); + btn.parent().find('section').fadeIn(); + return icon.removeClass('fa-angle-right').addClass('fa-angle-left'); + } + }); + } + + return Aside; +})(); diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js index e55405135fb..8630b18a73f 100644 --- a/app/assets/javascripts/autosave.js +++ b/app/assets/javascripts/autosave.js @@ -1,62 +1,61 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, quotes, prefer-template, no-var, one-var, no-unused-vars, one-var-declaration-per-line, no-void, consistent-return, no-empty, max-len */ -(function() { - this.Autosave = (function() { - function Autosave(field, key) { - this.field = field; - if (key.join != null) { - key = key.join("/"); - } - this.key = "autosave/" + key; - this.field.data("autosave", this); - this.restore(); - this.field.on("input", (function(_this) { - return function() { - return _this.save(); - }; - })(this)); + +window.Autosave = (function() { + function Autosave(field, key) { + this.field = field; + if (key.join != null) { + key = key.join("/"); } + this.key = "autosave/" + key; + this.field.data("autosave", this); + this.restore(); + this.field.on("input", (function(_this) { + return function() { + return _this.save(); + }; + })(this)); + } - Autosave.prototype.restore = function() { - var e, text; - if (window.localStorage == null) { - return; - } + Autosave.prototype.restore = function() { + var e, text; + if (window.localStorage == null) { + return; + } + try { + text = window.localStorage.getItem(this.key); + } catch (error) { + e = error; + return; + } + if ((text != null ? text.length : void 0) > 0) { + this.field.val(text); + } + return this.field.trigger("input"); + }; + + Autosave.prototype.save = function() { + var text; + if (window.localStorage == null) { + return; + } + text = this.field.val(); + if ((text != null ? text.length : void 0) > 0) { try { - text = window.localStorage.getItem(this.key); - } catch (error) { - e = error; - return; - } - if ((text != null ? text.length : void 0) > 0) { - this.field.val(text); - } - return this.field.trigger("input"); - }; - - Autosave.prototype.save = function() { - var text; - if (window.localStorage == null) { - return; - } - text = this.field.val(); - if ((text != null ? text.length : void 0) > 0) { - try { - return window.localStorage.setItem(this.key, text); - } catch (error) {} - } else { - return this.reset(); - } - }; - - Autosave.prototype.reset = function() { - if (window.localStorage == null) { - return; - } - try { - return window.localStorage.removeItem(this.key); + return window.localStorage.setItem(this.key, text); } catch (error) {} - }; + } else { + return this.reset(); + } + }; - return Autosave; - })(); -}).call(window); + Autosave.prototype.reset = function() { + if (window.localStorage == null) { + return; + } + try { + return window.localStorage.removeItem(this.key); + } catch (error) {} + }; + + return Autosave; +})(); diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index a4ccb30e447..9349918f7a0 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -1,380 +1,518 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-template, quotes, comma-dangle, no-param-reassign, no-void, brace-style, no-underscore-dangle, no-return-assign, camelcase */ /* global Cookies */ -var emojiAliases = require('emoji-aliases'); +import emojiMap from 'emojis/digests.json'; +import emojiAliases from 'emojis/aliases.json'; +import { glEmojiTag } from './behaviors/gl_emoji'; +import isEmojiNameValid from './behaviors/gl_emoji/is_emoji_name_valid'; -(function() { - this.AwardsHandler = (function() { - var FROM_SENTENCE_REGEX = /(?:, and | and |, )/; // For separating lists produced by ruby's Array#toSentence - function AwardsHandler() { - this.aliases = emojiAliases; - $(document).off('click', '.js-add-award').on('click', '.js-add-award', (function(_this) { - return function(e) { - e.stopPropagation(); - e.preventDefault(); - return _this.showEmojiMenu($(e.currentTarget)); - }; - })(this)); - $('html').on('click', function(e) { - var $target; - $target = $(e.target); - if (!$target.closest('.emoji-menu-content').length) { - $('.js-awards-block.current').removeClass('current'); - } - if (!$target.closest('.emoji-menu').length) { - if ($('.emoji-menu').is(':visible')) { - $('.js-add-award.is-active').removeClass('is-active'); - return $('.emoji-menu').removeClass('is-visible'); - } - } - }); - $(document).off('click', '.js-emoji-btn').on('click', '.js-emoji-btn', (function(_this) { - return function(e) { - var $target, emoji; - e.preventDefault(); - $target = $(e.currentTarget); - emoji = $target.find('.icon').data('emoji'); - $target.closest('.js-awards-block').addClass('current'); - return _this.addAward(_this.getVotesBlock(), _this.getAwardUrl(), emoji); - }; - })(this)); +const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; +const requestAnimationFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.setTimeout; + +const FROM_SENTENCE_REGEX = /(?:, and | and |, )/; // For separating lists produced by ruby's Array#toSentence + +let categoryMap = null; + +const categoryLabelMap = { + activity: 'Activity', + people: 'People', + nature: 'Nature', + food: 'Food', + travel: 'Travel', + objects: 'Objects', + symbols: 'Symbols', + flags: 'Flags', +}; + +function buildCategoryMap() { + return Object.keys(emojiMap).reduce((currentCategoryMap, emojiNameKey) => { + const emojiInfo = emojiMap[emojiNameKey]; + if (currentCategoryMap[emojiInfo.category]) { + currentCategoryMap[emojiInfo.category].push(emojiNameKey); } - AwardsHandler.prototype.showEmojiMenu = function($addBtn) { - var $holder, $menu, url; - $menu = $('.emoji-menu'); - if ($addBtn.hasClass('js-note-emoji')) { - $addBtn.closest('.note').find('.js-awards-block').addClass('current'); - } else { - $addBtn.closest('.js-awards-block').addClass('current'); - } - if ($menu.length) { - $holder = $addBtn.closest('.js-award-holder'); - if ($menu.is('.is-visible')) { - $addBtn.removeClass('is-active'); - $menu.removeClass('is-visible'); - return $('#emoji_search').blur(); - } else { - $addBtn.addClass('is-active'); - this.positionMenu($menu, $addBtn); - $menu.addClass('is-visible'); - return $('#emoji_search').focus(); - } - } else { - $addBtn.addClass('is-loading is-active'); - url = this.getAwardMenuUrl(); - return this.createEmojiMenu(url, (function(_this) { - return function() { - $addBtn.removeClass('is-loading'); - $menu = $('.emoji-menu'); - _this.positionMenu($menu, $addBtn); - if (!_this.frequentEmojiBlockRendered) { - _this.renderFrequentlyUsedBlock(); - } - return setTimeout(function() { - $menu.addClass('is-visible'); - $('#emoji_search').focus(); - return _this.setupSearch(); - }, 200); - }; - })(this)); - } - }; + return currentCategoryMap; + }, { + activity: [], + people: [], + nature: [], + food: [], + travel: [], + objects: [], + symbols: [], + flags: [], + }); +} - AwardsHandler.prototype.createEmojiMenu = function(awardMenuUrl, callback) { - return $.get(awardMenuUrl, function(response) { - $('body').append(response); - return callback(); +function renderCategory(name, emojiList, opts = {}) { + return ` +
+ ${name} +
+ + `; +} + +function AwardsHandler() { + this.eventListeners = []; + this.aliases = emojiAliases; + // If the user shows intent let's pre-build the menu + this.registerEventListener('one', $(document), 'mouseenter focus', '.js-add-award', 'mouseenter focus', () => { + const $menu = $('.emoji-menu'); + if ($menu.length === 0) { + requestAnimationFrame(() => { + this.createEmojiMenu(); }); - }; + } + // Prebuild the categoryMap + categoryMap = categoryMap || buildCategoryMap(); + }); + this.registerEventListener('on', $(document), 'click', '.js-add-award', (e) => { + e.stopPropagation(); + e.preventDefault(); + this.showEmojiMenu($(e.currentTarget)); + }); - AwardsHandler.prototype.positionMenu = function($menu, $addBtn) { - var css, 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 = { - top: ($addBtn.offset().top + $addBtn.outerHeight()) + "px" - }; - if (position === 'right') { - css.left = (($addBtn.offset().left - $menu.outerWidth()) + 20) + "px"; - $menu.addClass('is-aligned-right'); - } else { - css.left = ($addBtn.offset().left) + "px"; - $menu.removeClass('is-aligned-right'); + this.registerEventListener('on', $('html'), 'click', (e) => { + const $target = $(e.target); + if (!$target.closest('.emoji-menu-content').length) { + $('.js-awards-block.current').removeClass('current'); + } + if (!$target.closest('.emoji-menu').length) { + if ($('.emoji-menu').is(':visible')) { + $('.js-add-award.is-active').removeClass('is-active'); + $('.emoji-menu').removeClass('is-visible'); } - return $menu.css(css); - }; + } + }); + this.registerEventListener('on', $(document), 'click', '.js-emoji-btn', (e) => { + e.preventDefault(); + const $target = $(e.currentTarget); + const $glEmojiElement = $target.find('gl-emoji'); + const $spriteIconElement = $target.find('.icon'); + const emoji = ($glEmojiElement.length ? $glEmojiElement : $spriteIconElement).data('name'); + $target.closest('.js-awards-block').addClass('current'); + return this.addAward(this.getVotesBlock(), this.getAwardUrl(), emoji); + }); +} - AwardsHandler.prototype.addAward = function(votesBlock, awardUrl, emoji, checkMutuality, callback) { - if (checkMutuality == null) { - checkMutuality = true; +AwardsHandler.prototype.registerEventListener = function registerEventListener(method = 'on', element, ...args) { + element[method].call(element, ...args); + this.eventListeners.push({ + element, + args, + }); +}; + +AwardsHandler.prototype.showEmojiMenu = function showEmojiMenu($addBtn) { + if ($addBtn.hasClass('js-note-emoji')) { + $addBtn.closest('.note').find('.js-awards-block').addClass('current'); + } else { + $addBtn.closest('.js-awards-block').addClass('current'); + } + + const $menu = $('.emoji-menu'); + if ($menu.length) { + if ($menu.is('.is-visible')) { + $addBtn.removeClass('is-active'); + $menu.removeClass('is-visible'); + $('#emoji_search').blur(); + } else { + $addBtn.addClass('is-active'); + this.positionMenu($menu, $addBtn); + $menu.addClass('is-visible'); + $('#emoji_search').focus(); + } + } else { + $addBtn.addClass('is-loading is-active'); + this.createEmojiMenu(() => { + const $createdMenu = $('.emoji-menu'); + $addBtn.removeClass('is-loading'); + this.positionMenu($createdMenu, $addBtn); + return setTimeout(() => { + $createdMenu.addClass('is-visible'); + $('#emoji_search').focus(); + }, 200); + }); + } +}; + +// Create the emoji menu with the first category of emojis. +// Then render the remaining categories of emojis one by one to avoid jank. +AwardsHandler.prototype.createEmojiMenu = function createEmojiMenu(callback) { + if (this.isCreatingEmojiMenu) { + return; + } + this.isCreatingEmojiMenu = true; + + // Render the first category + categoryMap = categoryMap || buildCategoryMap(); + const categoryNameKey = Object.keys(categoryMap)[0]; + const emojisInCategory = categoryMap[categoryNameKey]; + const firstCategory = renderCategory(categoryLabelMap[categoryNameKey], emojisInCategory); + + // Render the frequently used + const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); + let frequentlyUsedCatgegory = ''; + if (frequentlyUsedEmojis.length > 0) { + frequentlyUsedCatgegory = renderCategory('Frequently used', frequentlyUsedEmojis, { + menuListClass: 'frequent-emojis', + }); + } + + const emojiMenuMarkup = ` +
+ + +
+ ${frequentlyUsedCatgegory} + ${firstCategory} +
+
+ `; + + document.body.insertAdjacentHTML('beforeend', emojiMenuMarkup); + + this.addRemainingEmojiMenuCategories(); + this.setupSearch(); + if (callback) { + callback(); + } +}; + +AwardsHandler + .prototype + .addRemainingEmojiMenuCategories = function addRemainingEmojiMenuCategories() { + if (this.isAddingRemainingEmojiMenuCategories) { + return; + } + this.isAddingRemainingEmojiMenuCategories = true; + + categoryMap = categoryMap || buildCategoryMap(); + + // Avoid the jank and render the remaining categories separately + // This will take more time, but makes UI more responsive + const menu = document.querySelector('.emoji-menu'); + const emojiContentElement = menu.querySelector('.emoji-menu-content'); + const remainingCategories = Object.keys(categoryMap).slice(1); + const allCategoriesAddedPromise = remainingCategories.reduce( + (promiseChain, categoryNameKey) => + promiseChain.then(() => + new Promise((resolve) => { + const emojisInCategory = categoryMap[categoryNameKey]; + const categoryMarkup = renderCategory( + categoryLabelMap[categoryNameKey], + emojisInCategory, + ); + requestAnimationFrame(() => { + emojiContentElement.insertAdjacentHTML('beforeend', categoryMarkup); + resolve(); + }); + }), + ), + Promise.resolve(), + ); + + allCategoriesAddedPromise.then(() => { + // Used for tests + // We check for the menu in case it was destroyed in the meantime + if (menu) { + menu.dispatchEvent(new CustomEvent('build-emoji-menu-finish')); } - emoji = this.normilizeEmojiName(emoji); - this.postEmoji(awardUrl, emoji, (function(_this) { - return function() { - _this.addAwardToEmojiBar(votesBlock, emoji, checkMutuality); - return typeof callback === "function" ? callback() : void 0; - }; - })(this)); - return $('.emoji-menu').removeClass('is-visible'); - }; + }); + }; - AwardsHandler.prototype.addAwardToEmojiBar = function(votesBlock, emoji, checkForMutuality) { - var $emojiButton, counter; - if (checkForMutuality == null) { - checkForMutuality = true; - } - if (checkForMutuality) { - this.checkMutuality(votesBlock, emoji); - } - this.addEmojiToFrequentlyUsedList(emoji); - emoji = this.normilizeEmojiName(emoji); - $emojiButton = this.findEmojiIcon(votesBlock, emoji).parent(); - if ($emojiButton.length > 0) { - if (this.isActive($emojiButton)) { - return this.decrementCounter($emojiButton, emoji); - } else { - counter = $emojiButton.find('.js-counter'); - counter.text(parseInt(counter.text(), 10) + 1); - $emojiButton.addClass('active'); - this.addYouToUserList(votesBlock, emoji); - return this.animateEmoji($emojiButton); - } - } else { - votesBlock.removeClass('hidden'); - return this.createEmoji(votesBlock, emoji); - } - }; +AwardsHandler.prototype.positionMenu = function positionMenu($menu, $addBtn) { + const 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 + const css = { + top: `${$addBtn.offset().top + $addBtn.outerHeight()}px`, + }; + if (position === 'right') { + css.left = `${($addBtn.offset().left - $menu.outerWidth()) + 20}px`; + $menu.addClass('is-aligned-right'); + } else { + css.left = `${$addBtn.offset().left}px`; + $menu.removeClass('is-aligned-right'); + } + return $menu.css(css); +}; - AwardsHandler.prototype.getVotesBlock = function() { - var currentBlock; - currentBlock = $('.js-awards-block.current'); - if (currentBlock.length) { - return currentBlock; - } else { - return $('.js-awards-block').eq(0); - } - }; +AwardsHandler.prototype.addAward = function addAward( + votesBlock, + awardUrl, + emoji, + checkMutuality, + callback, +) { + const normalizedEmoji = this.normalizeEmojiName(emoji); + this.postEmoji(awardUrl, normalizedEmoji, () => { + this.addAwardToEmojiBar(votesBlock, normalizedEmoji, checkMutuality); + return typeof callback === 'function' ? callback() : undefined; + }); + return $('.emoji-menu').removeClass('is-visible'); +}; - AwardsHandler.prototype.getAwardUrl = function() { - return this.getVotesBlock().data('award-url'); - }; - - AwardsHandler.prototype.checkMutuality = function(votesBlock, emoji) { - var $emojiButton, awardUrl, isAlreadyVoted, mutualVote; - awardUrl = this.getAwardUrl(); - if (emoji === 'thumbsup' || emoji === 'thumbsdown') { - mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup'; - $emojiButton = votesBlock.find("[data-emoji=" + mutualVote + "]").parent(); - isAlreadyVoted = $emojiButton.hasClass('active'); - if (isAlreadyVoted) { - this.addAward(votesBlock, awardUrl, mutualVote, false); - } - } - }; - - AwardsHandler.prototype.isActive = function($emojiButton) { - return $emojiButton.hasClass('active'); - }; - - AwardsHandler.prototype.decrementCounter = function($emojiButton, emoji) { - var counter, counterNumber; - counter = $('.js-counter', $emojiButton); - counterNumber = parseInt(counter.text(), 10); - if (counterNumber > 1) { - counter.text(counterNumber - 1); - this.removeYouFromUserList($emojiButton, emoji); - } else if (emoji === 'thumbsup' || emoji === 'thumbsdown') { - $emojiButton.tooltip('destroy'); - counter.text('0'); - this.removeYouFromUserList($emojiButton, emoji); - if ($emojiButton.parents('.note').length) { - this.removeEmoji($emojiButton); - } - } else { - this.removeEmoji($emojiButton); - } - return $emojiButton.removeClass('active'); - }; - - AwardsHandler.prototype.removeEmoji = function($emojiButton) { - var $votesBlock; - $emojiButton.tooltip('destroy'); - $emojiButton.remove(); - $votesBlock = this.getVotesBlock(); - if ($votesBlock.find('.js-emoji-btn').length === 0) { - return $votesBlock.addClass('hidden'); - } - }; - - AwardsHandler.prototype.getAwardTooltip = function($awardBlock) { - return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || ''; - }; - - 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; - awardBlock = $emojiButton; - originalTitle = this.getAwardTooltip(awardBlock); - authors = originalTitle.split(FROM_SENTENCE_REGEX); - authors.splice(authors.indexOf('You'), 1); - return awardBlock - .closest('.js-emoji-btn') - .removeData('title') - .removeAttr('data-title') - .removeAttr('data-original-title') - .attr('title', this.toSentence(authors)) - .tooltip('fixTitle'); - }; - - AwardsHandler.prototype.addYouToUserList = function(votesBlock, emoji) { - var awardBlock, origTitle, users; - awardBlock = this.findEmojiIcon(votesBlock, emoji).parent(); - origTitle = this.getAwardTooltip(awardBlock); - users = []; - if (origTitle) { - users = origTitle.trim().split(FROM_SENTENCE_REGEX); - } - users.unshift('You'); - return awardBlock - .attr('title', this.toSentence(users)) - .tooltip('fixTitle'); - }; - - AwardsHandler.prototype.createEmoji_ = function(votesBlock, emoji) { - var $emojiButton, buttonHtml, emojiCssClass; - emojiCssClass = this.resolveNameToCssClass(emoji); - buttonHtml = ""; - $emojiButton = $(buttonHtml); - $emojiButton.insertBefore(votesBlock.find('.js-award-holder')).find('.emoji-icon').data('emoji', emoji); +AwardsHandler.prototype.addAwardToEmojiBar = function addAwardToEmojiBar( + votesBlock, + emoji, + checkForMutuality, +) { + if (checkForMutuality || checkForMutuality === null) { + this.checkMutuality(votesBlock, emoji); + } + this.addEmojiToFrequentlyUsedList(emoji); + const normalizedEmoji = this.normalizeEmojiName(emoji); + const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent(); + if ($emojiButton.length > 0) { + if (this.isActive($emojiButton)) { + this.decrementCounter($emojiButton, normalizedEmoji); + } else { + const counter = $emojiButton.find('.js-counter'); + counter.text(parseInt(counter.text(), 10) + 1); + $emojiButton.addClass('active'); + this.addYouToUserList(votesBlock, normalizedEmoji); this.animateEmoji($emojiButton); - $('.award-control').tooltip(); - return votesBlock.removeClass('current'); - }; + } + } else { + votesBlock.removeClass('hidden'); + this.createEmoji(votesBlock, normalizedEmoji); + } +}; - AwardsHandler.prototype.animateEmoji = function($emoji) { - var className = 'pulse animated once short'; - $emoji.addClass(className); +AwardsHandler.prototype.getVotesBlock = function getVotesBlock() { + const currentBlock = $('.js-awards-block.current'); + let resultantVotesBlock = currentBlock; + if (currentBlock.length === 0) { + resultantVotesBlock = $('.js-awards-block').eq(0); + } - $emoji.on('webkitAnimationEnd animationEnd', function() { - $(this).removeClass(className); - }); - }; + return resultantVotesBlock; +}; - AwardsHandler.prototype.createEmoji = function(votesBlock, emoji) { - if ($('.emoji-menu').length) { - return this.createEmoji_(votesBlock, emoji); - } - return this.createEmojiMenu(this.getAwardMenuUrl(), (function(_this) { - return function() { - return _this.createEmoji_(votesBlock, emoji); - }; - })(this)); - }; +AwardsHandler.prototype.getAwardUrl = function getAwardUrl() { + return this.getVotesBlock().data('award-url'); +}; - AwardsHandler.prototype.getAwardMenuUrl = function() { - return gon.award_menu_url; - }; +AwardsHandler.prototype.checkMutuality = function checkMutuality(votesBlock, emoji) { + const awardUrl = this.getAwardUrl(); + if (emoji === 'thumbsup' || emoji === 'thumbsdown') { + const mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup'; + const $emojiButton = votesBlock.find(`[data-name="${mutualVote}"]`).parent(); + const isAlreadyVoted = $emojiButton.hasClass('active'); + if (isAlreadyVoted) { + this.addAward(votesBlock, awardUrl, mutualVote, false); + } + } +}; - AwardsHandler.prototype.resolveNameToCssClass = function(emoji) { - var emojiIcon, unicodeName; - emojiIcon = $(".emoji-menu-content [data-emoji='" + emoji + "']"); - if (emojiIcon.length > 0) { - unicodeName = emojiIcon.data('unicode-name'); - } else { - // Find by alias - unicodeName = $(".emoji-menu-content [data-aliases*=':" + emoji + ":']").data('unicode-name'); - } - return "emoji-" + unicodeName; - }; +AwardsHandler.prototype.isActive = function isActive($emojiButton) { + return $emojiButton.hasClass('active'); +}; - AwardsHandler.prototype.postEmoji = function(awardUrl, emoji, callback) { - return $.post(awardUrl, { - name: emoji - }, function(data) { - if (data.ok) { - return callback(); - } - }); - }; +AwardsHandler.prototype.decrementCounter = function decrementCounter($emojiButton, emoji) { + const counter = $('.js-counter', $emojiButton); + const counterNumber = parseInt(counter.text(), 10); + if (counterNumber > 1) { + counter.text(counterNumber - 1); + this.removeYouFromUserList($emojiButton); + } else if (emoji === 'thumbsup' || emoji === 'thumbsdown') { + $emojiButton.tooltip('destroy'); + counter.text('0'); + this.removeYouFromUserList($emojiButton); + if ($emojiButton.parents('.note').length) { + this.removeEmoji($emojiButton); + } + } else { + this.removeEmoji($emojiButton); + } + return $emojiButton.removeClass('active'); +}; - AwardsHandler.prototype.findEmojiIcon = function(votesBlock, emoji) { - return votesBlock.find(".js-emoji-btn [data-emoji='" + emoji + "']"); - }; +AwardsHandler.prototype.removeEmoji = function removeEmoji($emojiButton) { + $emojiButton.tooltip('destroy'); + $emojiButton.remove(); + const $votesBlock = this.getVotesBlock(); + if ($votesBlock.find('.js-emoji-btn').length === 0) { + $votesBlock.addClass('hidden'); + } +}; - AwardsHandler.prototype.scrollToAwards = function() { - var options; - options = { - scrollTop: $('.awards').offset().top - 110 - }; - return $('body, html').animate(options, 200); - }; +AwardsHandler.prototype.getAwardTooltip = function getAwardTooltip($awardBlock) { + return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || ''; +}; - AwardsHandler.prototype.normilizeEmojiName = function(emoji) { - return this.aliases[emoji] || emoji; - }; +AwardsHandler.prototype.toSentence = function toSentence(list) { + let sentence; + if (list.length <= 2) { + sentence = list.join(' and '); + } else { + sentence = `${list.slice(0, -1).join(', ')}, and ${list[list.length - 1]}`; + } - AwardsHandler.prototype.addEmojiToFrequentlyUsedList = function(emoji) { - var frequentlyUsedEmojis; - frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); - frequentlyUsedEmojis.push(emoji); - Cookies.set('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 }); - }; + return sentence; +}; - AwardsHandler.prototype.getFrequentlyUsedEmojis = function() { - var frequentlyUsedEmojis; - frequentlyUsedEmojis = (Cookies.get('frequently_used_emojis') || '').split(','); - return _.compact(_.uniq(frequentlyUsedEmojis)); - }; +AwardsHandler.prototype.removeYouFromUserList = function removeYouFromUserList($emojiButton) { + const awardBlock = $emojiButton; + const originalTitle = this.getAwardTooltip(awardBlock); + const authors = originalTitle.split(FROM_SENTENCE_REGEX); + authors.splice(authors.indexOf('You'), 1); + return awardBlock + .closest('.js-emoji-btn') + .removeData('title') + .removeAttr('data-title') + .removeAttr('data-original-title') + .attr('title', this.toSentence(authors)) + .tooltip('fixTitle'); +}; - AwardsHandler.prototype.renderFrequentlyUsedBlock = function() { - var emoji, frequentlyUsedEmojis, i, len, ul; - if (Cookies.get('frequently_used_emojis')) { - frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); - ul = $(" + + + `, +}; diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6 deleted file mode 100644 index c5a714d9673..00000000000 --- a/app/assets/javascripts/environments/components/environment_actions.js.es6 +++ /dev/null @@ -1,43 +0,0 @@ -const Vue = require('vue'); - -module.exports = Vue.component('actions-component', { - props: { - actions: { - type: Array, - required: false, - default: () => [], - }, - - playIconSvg: { - type: String, - required: false, - }, - }, - - template: ` - - `, -}); diff --git a/app/assets/javascripts/environments/components/environment_external_url.js b/app/assets/javascripts/environments/components/environment_external_url.js new file mode 100644 index 00000000000..b4f9eb357fd --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_external_url.js @@ -0,0 +1,22 @@ +/** + * Renders the external url link in environments table. + */ +export default { + props: { + externalUrl: { + type: String, + default: '', + }, + }, + + template: ` + + + + `, +}; diff --git a/app/assets/javascripts/environments/components/environment_external_url.js.es6 b/app/assets/javascripts/environments/components/environment_external_url.js.es6 deleted file mode 100644 index 2599bba3c59..00000000000 --- a/app/assets/javascripts/environments/components/environment_external_url.js.es6 +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Renders the external url link in environments table. - */ -const Vue = require('vue'); - -module.exports = Vue.component('external-url-component', { - props: { - externalUrl: { - type: String, - default: '', - }, - }, - - template: ` - - - - `, -}); diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js similarity index 84% rename from app/assets/javascripts/environments/components/environment_item.js.es6 rename to app/assets/javascripts/environments/components/environment_item.js index 24fd58a301a..66ed10e19d1 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js @@ -1,26 +1,22 @@ -const Vue = require('vue'); -const Timeago = require('timeago.js'); - -require('../../lib/utils/text_utility'); -require('../../vue_shared/components/commit'); -const ActionsComponent = require('./environment_actions'); -const ExternalUrlComponent = require('./environment_external_url'); -const StopComponent = require('./environment_stop'); -const RollbackComponent = require('./environment_rollback'); -const TerminalButtonComponent = require('./environment_terminal_button'); +import Timeago from 'timeago.js'; +import '../../lib/utils/text_utility'; +import ActionsComponent from './environment_actions'; +import ExternalUrlComponent from './environment_external_url'; +import StopComponent from './environment_stop'; +import RollbackComponent from './environment_rollback'; +import TerminalButtonComponent from './environment_terminal_button'; +import CommitComponent from '../../vue_shared/components/commit'; /** * Envrionment Item Component * * Renders a table row for each environment. */ - const timeagoInstance = new Timeago(); -module.exports = Vue.component('environment-item', { - +export default { components: { - 'commit-component': gl.CommitComponent, + 'commit-component': CommitComponent, 'actions-component': ActionsComponent, 'external-url-component': ExternalUrlComponent, 'stop-component': StopComponent, @@ -47,19 +43,9 @@ module.exports = Vue.component('environment-item', { default: false, }, - commitIconSvg: { - type: String, - required: false, - }, - - playIconSvg: { - type: String, - required: false, - }, - - terminalIconSvg: { - type: String, - required: false, + service: { + type: Object, + required: true, }, }, @@ -487,9 +473,7 @@ module.exports = Vue.component('environment-item', { :commit-url="commitUrl" :short-sha="commitShortSha" :title="commitTitle" - :author="commitAuthor" - :commit-icon-svg="commitIconSvg"> - + :author="commitAuthor"/>

No deployments yet @@ -503,47 +487,28 @@ module.exports = Vue.component('environment-item', { - -

-
- - -
+ +
+ -
- - -
+ -
- - -
+ -
- - -
+ -
- - -
+
`, -}); +}; diff --git a/app/assets/javascripts/environments/components/environment_rollback.js b/app/assets/javascripts/environments/components/environment_rollback.js new file mode 100644 index 00000000000..baa15d9e5b5 --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_rollback.js @@ -0,0 +1,67 @@ +/* global Flash */ +/* eslint-disable no-new */ +/** + * Renders Rollback or Re deploy button in environments table depending + * of the provided property `isLastDeployment`. + * + * Makes a post request when the button is clicked. + */ +import eventHub from '../event_hub'; + +export default { + props: { + retryUrl: { + type: String, + default: '', + }, + + isLastDeployment: { + type: Boolean, + default: true, + }, + + service: { + type: Object, + required: true, + }, + }, + + data() { + return { + isLoading: false, + }; + }, + + methods: { + onClick() { + this.isLoading = true; + + this.service.postAction(this.retryUrl) + .then(() => { + this.isLoading = false; + eventHub.$emit('refreshEnvironments'); + }) + .catch(() => { + this.isLoading = false; + new Flash('An error occured while making the request.'); + }); + }, + }, + + template: ` + + `, +}; diff --git a/app/assets/javascripts/environments/components/environment_rollback.js.es6 b/app/assets/javascripts/environments/components/environment_rollback.js.es6 deleted file mode 100644 index daf126eb4e8..00000000000 --- a/app/assets/javascripts/environments/components/environment_rollback.js.es6 +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Renders Rollback or Re deploy button in environments table depending - * of the provided property `isLastDeployment` - */ -const Vue = require('vue'); - -module.exports = Vue.component('rollback-component', { - props: { - retryUrl: { - type: String, - default: '', - }, - - isLastDeployment: { - type: Boolean, - default: true, - }, - }, - - template: ` - - - Re-deploy - - - Rollback - - - `, -}); diff --git a/app/assets/javascripts/environments/components/environment_stop.js b/app/assets/javascripts/environments/components/environment_stop.js new file mode 100644 index 00000000000..5404d647745 --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_stop.js @@ -0,0 +1,56 @@ +/* global Flash */ +/* eslint-disable no-new, no-alert */ +/** + * Renders the stop "button" that allows stop an environment. + * Used in environments table. + */ +import eventHub from '../event_hub'; + +export default { + props: { + stopUrl: { + type: String, + default: '', + }, + + service: { + type: Object, + required: true, + }, + }, + + data() { + return { + isLoading: false, + }; + }, + + methods: { + onClick() { + if (confirm('Are you sure you want to stop this environment?')) { + this.isLoading = true; + + this.service.postAction(this.retryUrl) + .then(() => { + this.isLoading = false; + eventHub.$emit('refreshEnvironments'); + }) + .catch(() => { + this.isLoading = false; + new Flash('An error occured while making the request.', 'alert'); + }); + } + }, + }, + + template: ` + + `, +}; diff --git a/app/assets/javascripts/environments/components/environment_stop.js.es6 b/app/assets/javascripts/environments/components/environment_stop.js.es6 deleted file mode 100644 index 96983a19568..00000000000 --- a/app/assets/javascripts/environments/components/environment_stop.js.es6 +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Renders the stop "button" that allows stop an environment. - * Used in environments table. - */ -const Vue = require('vue'); - -module.exports = Vue.component('stop-component', { - props: { - stopUrl: { - type: String, - default: '', - }, - }, - - template: ` - - - - `, -}); diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 b/app/assets/javascripts/environments/components/environment_terminal_button.js similarity index 52% rename from app/assets/javascripts/environments/components/environment_terminal_button.js.es6 rename to app/assets/javascripts/environments/components/environment_terminal_button.js index 481e0d15e7a..66a71faa02f 100644 --- a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 +++ b/app/assets/javascripts/environments/components/environment_terminal_button.js @@ -2,24 +2,26 @@ * Renders a terminal button to open a web terminal. * Used in environments table. */ -const Vue = require('vue'); +import terminalIconSvg from 'icons/_icon_terminal.svg'; -module.exports = Vue.component('terminal-button-component', { +export default { props: { terminalPath: { type: String, - default: '', - }, - terminalIconSvg: { - type: String, + required: false, default: '', }, }, + data() { + return { terminalIconSvg }; + }, + template: ` - + ${terminalIconSvg} `, -}); +}; diff --git a/app/assets/javascripts/environments/components/environments_table.js.es6 b/app/assets/javascripts/environments/components/environments_table.js similarity index 61% rename from app/assets/javascripts/environments/components/environments_table.js.es6 rename to app/assets/javascripts/environments/components/environments_table.js index fd35d77fd3d..338dff40bc9 100644 --- a/app/assets/javascripts/environments/components/environments_table.js.es6 +++ b/app/assets/javascripts/environments/components/environments_table.js @@ -1,13 +1,11 @@ /** * Render environments table. */ -const Vue = require('vue'); -const EnvironmentItem = require('./environment_item'); - -module.exports = Vue.component('environment-table-component', { +import EnvironmentTableRowComponent from './environment_item'; +export default { components: { - 'environment-item': EnvironmentItem, + 'environment-item': EnvironmentTableRowComponent, }, props: { @@ -29,24 +27,14 @@ module.exports = Vue.component('environment-table-component', { default: false, }, - commitIconSvg: { - type: String, - required: false, - }, - - playIconSvg: { - type: String, - required: false, - }, - - terminalIconSvg: { - type: String, - required: false, + service: { + type: Object, + required: true, }, }, template: ` - +
@@ -54,7 +42,7 @@ module.exports = Vue.component('environment-table-component', { - + @@ -64,11 +52,9 @@ module.exports = Vue.component('environment-table-component', { :model="model" :can-create-deployment="canCreateDeployment" :can-read-environment="canReadEnvironment" - :play-icon-svg="playIconSvg" - :terminal-icon-svg="terminalIconSvg" - :commit-icon-svg="commitIconSvg"> + :service="service">
EnvironmentJob Commit Updated
`, -}); +}; diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js similarity index 78% rename from app/assets/javascripts/environments/environments_bundle.js.es6 rename to app/assets/javascripts/environments/environments_bundle.js index 7bbba91bc10..8d963b335cf 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js @@ -1,4 +1,4 @@ -const EnvironmentsComponent = require('./components/environment'); +import EnvironmentsComponent from './components/environment'; $(() => { window.gl = window.gl || {}; diff --git a/app/assets/javascripts/environments/event_hub.js b/app/assets/javascripts/environments/event_hub.js new file mode 100644 index 00000000000..0948c2e5352 --- /dev/null +++ b/app/assets/javascripts/environments/event_hub.js @@ -0,0 +1,3 @@ +import Vue from 'vue'; + +export default new Vue(); diff --git a/app/assets/javascripts/environments/folder/environments_folder_bundle.js.es6 b/app/assets/javascripts/environments/folder/environments_folder_bundle.js similarity index 78% rename from app/assets/javascripts/environments/folder/environments_folder_bundle.js.es6 rename to app/assets/javascripts/environments/folder/environments_folder_bundle.js index d2ca465351a..f939eccf246 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_bundle.js.es6 +++ b/app/assets/javascripts/environments/folder/environments_folder_bundle.js @@ -1,4 +1,4 @@ -const EnvironmentsFolderComponent = require('./environments_folder_view'); +import EnvironmentsFolderComponent from './environments_folder_view'; $(() => { window.gl = window.gl || {}; diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.js.es6 b/app/assets/javascripts/environments/folder/environments_folder_view.js similarity index 84% rename from app/assets/javascripts/environments/folder/environments_folder_view.js.es6 rename to app/assets/javascripts/environments/folder/environments_folder_view.js index 53d52965758..8abbcf0c227 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_view.js.es6 +++ b/app/assets/javascripts/environments/folder/environments_folder_view.js @@ -1,20 +1,17 @@ -/* eslint-disable no-param-reassign, no-new */ +/* eslint-disable no-new */ /* global Flash */ +import Vue from 'vue'; +import EnvironmentsService from '../services/environments_service'; +import EnvironmentTable from '../components/environments_table'; +import EnvironmentsStore from '../stores/environments_store'; +import TablePaginationComponent from '../../vue_shared/components/table_pagination'; +import '../../lib/utils/common_utils'; +import '../../vue_shared/vue_resource_interceptor'; -const Vue = window.Vue = require('vue'); -window.Vue.use(require('vue-resource')); -const EnvironmentsService = require('../services/environments_service'); -const EnvironmentTable = require('../components/environments_table'); -const EnvironmentsStore = require('../stores/environments_store'); -require('../../vue_shared/components/table_pagination'); -require('../../lib/utils/common_utils'); -require('../../vue_shared/vue_resource_interceptor'); - -module.exports = Vue.component('environment-folder-view', { - +export default Vue.component('environment-folder-view', { components: { 'environment-table': EnvironmentTable, - 'table-pagination': gl.VueGlPagination, + 'table-pagination': TablePaginationComponent, }, data() { @@ -88,11 +85,11 @@ module.exports = Vue.component('environment-folder-view', { const endpoint = `${this.endpoint}?scope=${scope}&page=${pageNumber}`; - const service = new EnvironmentsService(endpoint); + this.service = new EnvironmentsService(endpoint); this.isLoading = true; - return service.all() + return this.service.get() .then(resp => ({ headers: resp.headers, body: resp.json(), @@ -168,13 +165,12 @@ module.exports = Vue.component('environment-folder-view', { :can-read-environment="canReadEnvironmentParsed" :play-icon-svg="playIconSvg" :terminal-icon-svg="terminalIconSvg" - :commit-icon-svg="commitIconSvg"> - + :commit-icon-svg="commitIconSvg" + :service="service"/> - + :pageInfo="state.paginationInformation"/>
diff --git a/app/assets/javascripts/environments/services/environments_service.js b/app/assets/javascripts/environments/services/environments_service.js new file mode 100644 index 00000000000..07040bf0d73 --- /dev/null +++ b/app/assets/javascripts/environments/services/environments_service.js @@ -0,0 +1,19 @@ +/* eslint-disable class-methods-use-this */ +import Vue from 'vue'; +import VueResource from 'vue-resource'; + +Vue.use(VueResource); + +export default class EnvironmentsService { + constructor(endpoint) { + this.environments = Vue.resource(endpoint); + } + + get(scope, page) { + return this.environments.get({ scope, page }); + } + + postAction(endpoint) { + return Vue.http.post(endpoint, {}, { emulateJSON: true }); + } +} diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6 deleted file mode 100644 index 9cef335868e..00000000000 --- a/app/assets/javascripts/environments/services/environments_service.js.es6 +++ /dev/null @@ -1,13 +0,0 @@ -const Vue = require('vue'); - -class EnvironmentsService { - constructor(endpoint) { - this.environments = Vue.resource(endpoint); - } - - all() { - return this.environments.get(); - } -} - -module.exports = EnvironmentsService; diff --git a/app/assets/javascripts/environments/stores/environments_store.js.es6 b/app/assets/javascripts/environments/stores/environments_store.js similarity index 95% rename from app/assets/javascripts/environments/stores/environments_store.js.es6 rename to app/assets/javascripts/environments/stores/environments_store.js index 15cd9bde08e..3c3084f3b78 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environments_store.js @@ -1,11 +1,11 @@ -require('~/lib/utils/common_utils'); +import '~/lib/utils/common_utils'; /** * Environments Store. * * Stores received environments, count of stopped environments and count of * available environments. */ -class EnvironmentsStore { +export default class EnvironmentsStore { constructor() { this.state = {}; this.state.environments = []; @@ -86,5 +86,3 @@ class EnvironmentsStore { return count; } } - -module.exports = EnvironmentsStore; diff --git a/app/assets/javascripts/extensions/array.js b/app/assets/javascripts/extensions/array.js new file mode 100644 index 00000000000..027222f804d --- /dev/null +++ b/app/assets/javascripts/extensions/array.js @@ -0,0 +1,11 @@ +// TODO: remove this + +// eslint-disable-next-line no-extend-native +Array.prototype.first = function first() { + return this[0]; +}; + +// eslint-disable-next-line no-extend-native +Array.prototype.last = function last() { + return this[this.length - 1]; +}; diff --git a/app/assets/javascripts/extensions/array.js.es6 b/app/assets/javascripts/extensions/array.js.es6 deleted file mode 100644 index f8256a8d26d..00000000000 --- a/app/assets/javascripts/extensions/array.js.es6 +++ /dev/null @@ -1,27 +0,0 @@ -/* eslint-disable no-extend-native, func-names, space-before-function-paren, space-infix-ops, strict, max-len */ - -'use strict'; - -Array.prototype.first = function() { - return this[0]; -}; - -Array.prototype.last = function() { - return this[this.length-1]; -}; - -Array.prototype.find = Array.prototype.find || function(predicate, ...args) { - if (!this) throw new TypeError('Array.prototype.find called on null or undefined'); - if (typeof predicate !== 'function') throw new TypeError('predicate must be a function'); - - const list = Object(this); - const thisArg = args[1]; - let value = {}; - - for (let i = 0; i < list.length; i += 1) { - value = list[i]; - if (predicate.call(thisArg, value, i, list)) return value; - } - - return undefined; -}; diff --git a/app/assets/javascripts/extensions/custom_event.js.es6 b/app/assets/javascripts/extensions/custom_event.js.es6 deleted file mode 100644 index abedae4c1c7..00000000000 --- a/app/assets/javascripts/extensions/custom_event.js.es6 +++ /dev/null @@ -1,12 +0,0 @@ -/* global CustomEvent */ -/* eslint-disable no-global-assign */ - -// Custom event support for IE -CustomEvent = function CustomEvent(event, parameters) { - const params = parameters || { bubbles: false, cancelable: false, detail: undefined }; - const evt = document.createEvent('CustomEvent'); - evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); - return evt; -}; - -CustomEvent.prototype = window.Event.prototype; diff --git a/app/assets/javascripts/extensions/element.js.es6 b/app/assets/javascripts/extensions/element.js.es6 deleted file mode 100644 index 90ab79305a7..00000000000 --- a/app/assets/javascripts/extensions/element.js.es6 +++ /dev/null @@ -1,20 +0,0 @@ -/* global Element */ -/* eslint-disable consistent-return, max-len, no-empty, func-names */ - -Element.prototype.closest = Element.prototype.closest || function closest(selector, selectedElement = this) { - if (!selectedElement) return; - return selectedElement.matches(selector) ? selectedElement : Element.prototype.closest(selector, selectedElement.parentElement); -}; - -Element.prototype.matches = Element.prototype.matches || - Element.prototype.matchesSelector || - Element.prototype.mozMatchesSelector || - Element.prototype.msMatchesSelector || - Element.prototype.oMatchesSelector || - Element.prototype.webkitMatchesSelector || - function (s) { - const matches = (this.document || this.ownerDocument).querySelectorAll(s); - let i = matches.length - 1; - while (i >= 0 && matches.item(i) !== this) { i -= 1; } - return i > -1; - }; diff --git a/app/assets/javascripts/extensions/jquery.js b/app/assets/javascripts/extensions/jquery.js deleted file mode 100644 index 1a489b859e8..00000000000 --- a/app/assets/javascripts/extensions/jquery.js +++ /dev/null @@ -1,16 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, object-shorthand, comma-dangle, max-len */ -// Disable an element and add the 'disabled' Bootstrap class -(function() { - $.fn.extend({ - disable: function() { - return $(this).attr('disabled', 'disabled').addClass('disabled'); - } - }); - - // Enable an element and remove the 'disabled' Bootstrap class - $.fn.extend({ - enable: function() { - return $(this).removeAttr('disabled').removeClass('disabled'); - } - }); -}).call(window); diff --git a/app/assets/javascripts/extensions/object.js.es6 b/app/assets/javascripts/extensions/object.js.es6 deleted file mode 100644 index 70a2d765abd..00000000000 --- a/app/assets/javascripts/extensions/object.js.es6 +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-disable no-restricted-syntax */ - -// Adapted from https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill -if (typeof Object.assign !== 'function') { - Object.assign = function assign(target, ...args) { - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - const to = Object(target); - - for (let index = 0; index < args.length; index += 1) { - const nextSource = args[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (const nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }; -} diff --git a/app/assets/javascripts/files_comment_button.js b/app/assets/javascripts/files_comment_button.js index 698870d0ce1..3f041172ff3 100644 --- a/app/assets/javascripts/files_comment_button.js +++ b/app/assets/javascripts/files_comment_button.js @@ -1,147 +1,141 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, max-len, one-var, one-var-declaration-per-line, quotes, prefer-template, newline-per-chained-call, comma-dangle, new-cap, no-else-return, consistent-return */ /* global FilesCommentButton */ +/* global notes */ -(function() { - var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; +let $commentButtonTemplate; +var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; - this.FilesCommentButton = (function() { - var COMMENT_BUTTON_CLASS, COMMENT_BUTTON_TEMPLATE, DEBOUNCE_TIMEOUT_DURATION, EMPTY_CELL_CLASS, LINE_COLUMN_CLASSES, LINE_CONTENT_CLASS, LINE_HOLDER_CLASS, LINE_NUMBER_CLASS, OLD_LINE_CLASS, TEXT_FILE_SELECTOR, UNFOLDABLE_LINE_CLASS; +window.FilesCommentButton = (function() { + var COMMENT_BUTTON_CLASS, EMPTY_CELL_CLASS, LINE_COLUMN_CLASSES, LINE_CONTENT_CLASS, LINE_HOLDER_CLASS, LINE_NUMBER_CLASS, OLD_LINE_CLASS, TEXT_FILE_SELECTOR, UNFOLDABLE_LINE_CLASS; - COMMENT_BUTTON_CLASS = '.add-diff-note'; + COMMENT_BUTTON_CLASS = '.add-diff-note'; - COMMENT_BUTTON_TEMPLATE = _.template(''); + LINE_HOLDER_CLASS = '.line_holder'; - LINE_HOLDER_CLASS = '.line_holder'; + LINE_NUMBER_CLASS = 'diff-line-num'; - LINE_NUMBER_CLASS = 'diff-line-num'; + LINE_CONTENT_CLASS = 'line_content'; - LINE_CONTENT_CLASS = 'line_content'; + UNFOLDABLE_LINE_CLASS = 'js-unfold'; - UNFOLDABLE_LINE_CLASS = 'js-unfold'; + EMPTY_CELL_CLASS = 'empty-cell'; - EMPTY_CELL_CLASS = 'empty-cell'; + OLD_LINE_CLASS = 'old_line'; - OLD_LINE_CLASS = 'old_line'; + LINE_COLUMN_CLASSES = "." + LINE_NUMBER_CLASS + ", .line_content"; - LINE_COLUMN_CLASSES = "." + LINE_NUMBER_CLASS + ", .line_content"; + TEXT_FILE_SELECTOR = '.text-file'; - TEXT_FILE_SELECTOR = '.text-file'; + function FilesCommentButton(filesContainerElement) { + this.render = bind(this.render, this); + this.hideButton = bind(this.hideButton, this); + this.isParallelView = notes.isParallelView(); + filesContainerElement.on('mouseover', LINE_COLUMN_CLASSES, this.render) + .on('mouseleave', LINE_COLUMN_CLASSES, this.hideButton); + } - DEBOUNCE_TIMEOUT_DURATION = 100; + FilesCommentButton.prototype.render = function(e) { + var $currentTarget, buttonParentElement, lineContentElement, textFileElement, $button; + $currentTarget = $(e.currentTarget); - function FilesCommentButton(filesContainerElement) { - var debounce; - this.filesContainerElement = filesContainerElement; - this.destroy = bind(this.destroy, this); - this.render = bind(this.render, this); - this.VIEW_TYPE = $('input#view[type=hidden]').val(); - debounce = _.debounce(this.render, DEBOUNCE_TIMEOUT_DURATION); - $(this.filesContainerElement).off('mouseover', LINE_COLUMN_CLASSES).off('mouseleave', LINE_COLUMN_CLASSES).on('mouseover', LINE_COLUMN_CLASSES, debounce).on('mouseleave', LINE_COLUMN_CLASSES, this.destroy); - } + if ($currentTarget.hasClass('js-no-comment-btn')) return; - FilesCommentButton.prototype.render = function(e) { - var $currentTarget, buttonParentElement, lineContentElement, textFileElement; - $currentTarget = $(e.currentTarget); + lineContentElement = this.getLineContent($currentTarget); + buttonParentElement = this.getButtonParent($currentTarget); - buttonParentElement = this.getButtonParent($currentTarget); - if (!this.validateButtonParent(buttonParentElement)) return; - lineContentElement = this.getLineContent($currentTarget); - if (!this.validateLineContent(lineContentElement)) return; + if (!this.validateButtonParent(buttonParentElement) || !this.validateLineContent(lineContentElement)) return; - textFileElement = this.getTextFileElement($currentTarget); - buttonParentElement.append(this.buildButton({ - noteableType: textFileElement.attr('data-noteable-type'), - noteableID: textFileElement.attr('data-noteable-id'), - commitID: textFileElement.attr('data-commit-id'), - noteType: lineContentElement.attr('data-note-type'), - position: lineContentElement.attr('data-position'), - lineType: lineContentElement.attr('data-line-type'), - discussionID: lineContentElement.attr('data-discussion-id'), - lineCode: lineContentElement.attr('data-line-code') - })); - }; + $button = $(COMMENT_BUTTON_CLASS, buttonParentElement); + buttonParentElement.addClass('is-over') + .nextUntil(`.${LINE_CONTENT_CLASS}`).addClass('is-over'); - FilesCommentButton.prototype.destroy = function(e) { - if (this.isMovingToSameType(e)) { - return; - } - $(COMMENT_BUTTON_CLASS, this.getButtonParent($(e.currentTarget))).remove(); - }; - - FilesCommentButton.prototype.buildButton = function(buttonAttributes) { - var initializedButtonTemplate; - initializedButtonTemplate = COMMENT_BUTTON_TEMPLATE({ - COMMENT_BUTTON_CLASS: COMMENT_BUTTON_CLASS.substr(1) - }); - return $(initializedButtonTemplate).attr({ - 'data-noteable-type': buttonAttributes.noteableType, - 'data-noteable-id': buttonAttributes.noteableID, - 'data-commit-id': buttonAttributes.commitID, - 'data-note-type': buttonAttributes.noteType, - 'data-line-code': buttonAttributes.lineCode, - 'data-position': buttonAttributes.position, - 'data-discussion-id': buttonAttributes.discussionID, - 'data-line-type': buttonAttributes.lineType - }); - }; - - FilesCommentButton.prototype.getTextFileElement = function(hoveredElement) { - return $(hoveredElement.closest(TEXT_FILE_SELECTOR)); - }; - - FilesCommentButton.prototype.getLineContent = function(hoveredElement) { - if (hoveredElement.hasClass(LINE_CONTENT_CLASS)) { - return hoveredElement; - } - if (this.VIEW_TYPE === 'inline') { - return $(hoveredElement).closest(LINE_HOLDER_CLASS).find("." + LINE_CONTENT_CLASS); - } else { - return $(hoveredElement).next("." + LINE_CONTENT_CLASS); - } - }; - - FilesCommentButton.prototype.getButtonParent = function(hoveredElement) { - if (this.VIEW_TYPE === 'inline') { - if (hoveredElement.hasClass(OLD_LINE_CLASS)) { - return hoveredElement; - } - return hoveredElement.parent().find("." + OLD_LINE_CLASS); - } else { - if (hoveredElement.hasClass(LINE_NUMBER_CLASS)) { - return hoveredElement; - } - return $(hoveredElement).prev("." + LINE_NUMBER_CLASS); - } - }; - - FilesCommentButton.prototype.isMovingToSameType = function(e) { - var newButtonParent; - newButtonParent = this.getButtonParent($(e.toElement)); - if (!newButtonParent) { - return false; - } - return newButtonParent.is(this.getButtonParent($(e.currentTarget))); - }; - - FilesCommentButton.prototype.validateButtonParent = function(buttonParentElement) { - 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; - })(); - - $.fn.filesCommentButton = function() { - if (!(this && (this.parent().data('can-create-note') != null))) { + if ($button.length) { return; } - return this.each(function() { - if (!$.data(this, 'filesCommentButton')) { - return $.data(this, 'filesCommentButton', new FilesCommentButton($(this))); - } + + textFileElement = this.getTextFileElement($currentTarget); + buttonParentElement.append(this.buildButton({ + noteableType: textFileElement.attr('data-noteable-type'), + noteableID: textFileElement.attr('data-noteable-id'), + commitID: textFileElement.attr('data-commit-id'), + noteType: lineContentElement.attr('data-note-type'), + position: lineContentElement.attr('data-position'), + lineType: lineContentElement.attr('data-line-type'), + discussionID: lineContentElement.attr('data-discussion-id'), + lineCode: lineContentElement.attr('data-line-code') + })); + }; + + FilesCommentButton.prototype.hideButton = function(e) { + var $currentTarget = $(e.currentTarget); + var buttonParentElement = this.getButtonParent($currentTarget); + + buttonParentElement.removeClass('is-over') + .nextUntil(`.${LINE_CONTENT_CLASS}`).removeClass('is-over'); + }; + + FilesCommentButton.prototype.buildButton = function(buttonAttributes) { + return $commentButtonTemplate.clone().attr({ + 'data-noteable-type': buttonAttributes.noteableType, + 'data-noteable-id': buttonAttributes.noteableID, + 'data-commit-id': buttonAttributes.commitID, + 'data-note-type': buttonAttributes.noteType, + 'data-line-code': buttonAttributes.lineCode, + 'data-position': buttonAttributes.position, + 'data-discussion-id': buttonAttributes.discussionID, + 'data-line-type': buttonAttributes.lineType }); }; -}).call(window); + + FilesCommentButton.prototype.getTextFileElement = function(hoveredElement) { + return hoveredElement.closest(TEXT_FILE_SELECTOR); + }; + + FilesCommentButton.prototype.getLineContent = function(hoveredElement) { + if (hoveredElement.hasClass(LINE_CONTENT_CLASS)) { + return hoveredElement; + } + if (!this.isParallelView) { + return $(hoveredElement).closest(LINE_HOLDER_CLASS).find("." + LINE_CONTENT_CLASS); + } else { + return $(hoveredElement).next("." + LINE_CONTENT_CLASS); + } + }; + + FilesCommentButton.prototype.getButtonParent = function(hoveredElement) { + if (!this.isParallelView) { + if (hoveredElement.hasClass(OLD_LINE_CLASS)) { + return hoveredElement; + } + return hoveredElement.parent().find("." + OLD_LINE_CLASS); + } else { + if (hoveredElement.hasClass(LINE_NUMBER_CLASS)) { + return hoveredElement; + } + return $(hoveredElement).prev("." + LINE_NUMBER_CLASS); + } + }; + + FilesCommentButton.prototype.validateButtonParent = function(buttonParentElement) { + return !buttonParentElement.hasClass(EMPTY_CELL_CLASS) && !buttonParentElement.hasClass(UNFOLDABLE_LINE_CLASS); + }; + + FilesCommentButton.prototype.validateLineContent = function(lineContentElement) { + return lineContentElement.attr('data-discussion-id') && lineContentElement.attr('data-discussion-id') !== ''; + }; + + return FilesCommentButton; +})(); + +$.fn.filesCommentButton = function() { + $commentButtonTemplate = $(''); + + if (!(this && (this.parent().data('can-create-note') != null))) { + return; + } + return this.each(function() { + if (!$.data(this, 'filesCommentButton')) { + return $.data(this, 'filesCommentButton', new FilesCommentButton($(this))); + } + }); +}; diff --git a/app/assets/javascripts/filterable_list.js b/app/assets/javascripts/filterable_list.js new file mode 100644 index 00000000000..aaaeb9bddb1 --- /dev/null +++ b/app/assets/javascripts/filterable_list.js @@ -0,0 +1,46 @@ +/** + * Makes search request for content when user types a value in the search input. + * Updates the html content of the page with the received one. + */ + +export default class FilterableList { + constructor(form, filter, holder) { + this.filterForm = form; + this.listFilterElement = filter; + this.listHolderElement = holder; + } + + initSearch() { + this.debounceFilter = _.debounce(this.filterResults.bind(this), 500); + + this.listFilterElement.removeEventListener('input', this.debounceFilter); + this.listFilterElement.addEventListener('input', this.debounceFilter); + } + + filterResults() { + const form = this.filterForm; + const filterUrl = `${form.getAttribute('action')}?${$(form).serialize()}`; + + $(this.listHolderElement).fadeTo(250, 0.5); + + return $.ajax({ + url: form.getAttribute('action'), + data: $(form).serialize(), + type: 'GET', + dataType: 'json', + context: this, + complete() { + $(this.listHolderElement).fadeTo(250, 1); + }, + success(data) { + this.listHolderElement.innerHTML = data.html; + + // Change url so if user reload a page - search results are saved + return window.history.replaceState({ + page: filterUrl, + + }, document.title, filterUrl); + }, + }); + } +} diff --git a/app/assets/javascripts/filtered_search/container.js b/app/assets/javascripts/filtered_search/container.js new file mode 100644 index 00000000000..2243c4dd2c5 --- /dev/null +++ b/app/assets/javascripts/filtered_search/container.js @@ -0,0 +1,14 @@ +/* eslint-disable class-methods-use-this */ +let container = document; + +class FilteredSearchContainerClass { + set container(containerParam) { + container = containerParam; + } + + get container() { + return container; + } +} + +export default new FilteredSearchContainerClass(); diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 b/app/assets/javascripts/filtered_search/dropdown_hint.js similarity index 59% rename from app/assets/javascripts/filtered_search/dropdown_hint.js.es6 rename to app/assets/javascripts/filtered_search/dropdown_hint.js index 9e92d544bef..98dcb697af9 100644 --- a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_hint.js @@ -28,7 +28,24 @@ require('./filtered_search_dropdown'); const tag = selected.querySelector('.js-filter-tag').innerText.trim(); if (tag.length) { - gl.FilteredSearchDropdownManager.addWordToInput(token.replace(':', '')); + // Get previous input values in the input field and convert them into visual tokens + const previousInputValues = this.input.value.split(' '); + const searchTerms = []; + + previousInputValues.forEach((value, index) => { + searchTerms.push(value); + + if (index === previousInputValues.length - 1 + && token.indexOf(value.toLowerCase()) !== -1) { + searchTerms.pop(); + } + }); + + if (searchTerms.length > 0) { + gl.FilteredSearchVisualTokens.addSearchVisualToken(searchTerms.join(' ')); + } + + gl.FilteredSearchDropdownManager.addWordToInput(token.replace(':', ''), '', false, this.container); } this.dismissDropdown(); this.dispatchInputEvent(); @@ -39,14 +56,16 @@ require('./filtered_search_dropdown'); renderContent() { const dropdownData = []; - [].forEach.call(this.input.parentElement.querySelectorAll('.dropdown-menu'), (dropdownMenu) => { - const { icon, hint, tag } = dropdownMenu.dataset; + [].forEach.call(this.input.closest('.filtered-search-input-container').querySelectorAll('.dropdown-menu'), (dropdownMenu) => { + const { icon, hint, tag, type } = dropdownMenu.dataset; if (icon && hint && tag) { - dropdownData.push({ - icon: `fa-${icon}`, - hint, - tag: `<${tag}>`, - }); + dropdownData.push( + Object.assign({ + icon: `fa-${icon}`, + hint, + tag: `<${tag}>`, + }, type && { type }), + ); } }); diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_non_user.js similarity index 100% rename from app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 rename to app/assets/javascripts/filtered_search/dropdown_non_user.js diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_user.js similarity index 94% rename from app/assets/javascripts/filtered_search/dropdown_user.js.es6 rename to app/assets/javascripts/filtered_search/dropdown_user.js index 7e9c6f74aa5..04e2afad02f 100644 --- a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_user.js @@ -39,7 +39,12 @@ require('./filtered_search_dropdown'); getSearchInput() { const query = gl.DropdownUtils.getSearchInput(this.input); const { lastToken } = gl.FilteredSearchTokenizer.processTokens(query); - let value = lastToken.value || ''; + + let value = lastToken || ''; + + if (value[0] === '@') { + value = value.slice(1); + } // Removes the first character if it is a quotation so that we can search // with multiple words diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js b/app/assets/javascripts/filtered_search/dropdown_utils.js new file mode 100644 index 00000000000..432b0c0dfd2 --- /dev/null +++ b/app/assets/javascripts/filtered_search/dropdown_utils.js @@ -0,0 +1,181 @@ +import FilteredSearchContainer from './container'; + +(() => { + class DropdownUtils { + static getEscapedText(text) { + let escapedText = text; + const hasSpace = text.indexOf(' ') !== -1; + const hasDoubleQuote = text.indexOf('"') !== -1; + + // Encapsulate value with quotes if it has spaces + // Known side effect: values's with both single and double quotes + // won't escape properly + if (hasSpace) { + if (hasDoubleQuote) { + escapedText = `'${text}'`; + } else { + // Encapsulate singleQuotes or if it hasSpace + escapedText = `"${text}"`; + } + } + + return escapedText; + } + + static filterWithSymbol(filterSymbol, input, item) { + const updatedItem = item; + const searchInput = gl.DropdownUtils.getSearchInput(input); + + const title = updatedItem.title.toLowerCase(); + let value = searchInput.toLowerCase(); + let symbol = ''; + + // Remove the symbol for filter + if (value[0] === filterSymbol) { + symbol = value[0]; + value = value.slice(1); + } + + // Removes the first character if it is a quotation so that we can search + // with multiple words + if ((value[0] === '"' || value[0] === '\'') && title.indexOf(' ') !== -1) { + value = value.slice(1); + } + + // Eg. filterSymbol = ~ for labels + const matchWithoutSymbol = symbol === filterSymbol && title.indexOf(value) !== -1; + const match = title.indexOf(`${symbol}${value}`) !== -1; + + updatedItem.droplab_hidden = !match && !matchWithoutSymbol; + + return updatedItem; + } + + static filterHint(input, item) { + const updatedItem = item; + const searchInput = gl.DropdownUtils.getSearchQuery(input); + const { lastToken, tokens } = gl.FilteredSearchTokenizer.processTokens(searchInput); + const lastKey = lastToken.key || lastToken || ''; + const allowMultiple = item.type === 'array'; + const itemInExistingTokens = tokens.some(t => t.key === item.hint); + + if (!allowMultiple && itemInExistingTokens) { + updatedItem.droplab_hidden = true; + } else if (!lastKey || searchInput.split('').last() === ' ') { + updatedItem.droplab_hidden = false; + } else if (lastKey) { + const split = lastKey.split(':'); + const tokenName = split[0].split(' ').last(); + + const match = updatedItem.hint.indexOf(tokenName.toLowerCase()) === -1; + updatedItem.droplab_hidden = tokenName ? match : false; + } + + return updatedItem; + } + + static setDataValueIfSelected(filter, selected) { + const dataValue = selected.getAttribute('data-value'); + + if (dataValue) { + gl.FilteredSearchDropdownManager.addWordToInput(filter, dataValue, true); + } + + // Return boolean based on whether it was set + return dataValue !== null; + } + + // Determines the full search query (visual tokens + input) + static getSearchQuery(untilInput = false) { + const container = FilteredSearchContainer.container; + const tokens = [].slice.call(container.querySelectorAll('.tokens-container li')); + const values = []; + + if (untilInput) { + const inputIndex = _.findIndex(tokens, t => t.classList.contains('input-token')); + // Add one to include input-token to the tokens array + tokens.splice(inputIndex + 1); + } + + tokens.forEach((token) => { + if (token.classList.contains('js-visual-token')) { + const name = token.querySelector('.name'); + const value = token.querySelector('.value'); + const symbol = value && value.dataset.symbol ? value.dataset.symbol : ''; + let valueText = ''; + + if (value && value.innerText) { + valueText = value.innerText; + } + + if (token.className.indexOf('filtered-search-token') !== -1) { + values.push(`${name.innerText.toLowerCase()}:${symbol}${valueText}`); + } else { + values.push(name.innerText); + } + } else if (token.classList.contains('input-token')) { + const { isLastVisualTokenValid } = + gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + const input = FilteredSearchContainer.container.querySelector('.filtered-search'); + const inputValue = input && input.value; + + if (isLastVisualTokenValid) { + values.push(inputValue); + } else { + const previous = values.pop(); + values.push(`${previous}${inputValue}`); + } + } + }); + + return values.join(' '); + } + + static getSearchInput(filteredSearchInput) { + const inputValue = filteredSearchInput.value; + const { right } = gl.DropdownUtils.getInputSelectionPosition(filteredSearchInput); + + return inputValue.slice(0, right); + } + + static getInputSelectionPosition(input) { + const selectionStart = input.selectionStart; + let inputValue = input.value; + // Replace all spaces inside quote marks with underscores + // (will continue to match entire string until an end quote is found if any) + // This helps with matching the beginning & end of a token:key + inputValue = inputValue.replace(/(('[^']*'{0,1})|("[^"]*"{0,1})|:\s+)/g, str => str.replace(/\s/g, '_')); + + // Get the right position for the word selected + // Regex matches first space + let right = inputValue.slice(selectionStart).search(/\s/); + + if (right >= 0) { + right += selectionStart; + } else if (right < 0) { + right = inputValue.length; + } + + // Get the left position for the word selected + // Regex matches last non-whitespace character + let left = inputValue.slice(0, right).search(/\S+$/); + + if (selectionStart === 0) { + left = 0; + } else if (selectionStart === inputValue.length && left < 0) { + left = inputValue.length; + } else if (left < 0) { + left = selectionStart; + } + + return { + left, + right, + }; + } + } + + window.gl = window.gl || {}; + gl.DropdownUtils = DropdownUtils; +})(); diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 b/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 deleted file mode 100644 index de3fa116717..00000000000 --- a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 +++ /dev/null @@ -1,126 +0,0 @@ -(() => { - class DropdownUtils { - static getEscapedText(text) { - let escapedText = text; - const hasSpace = text.indexOf(' ') !== -1; - const hasDoubleQuote = text.indexOf('"') !== -1; - - // Encapsulate value with quotes if it has spaces - // Known side effect: values's with both single and double quotes - // won't escape properly - if (hasSpace) { - if (hasDoubleQuote) { - escapedText = `'${text}'`; - } else { - // Encapsulate singleQuotes or if it hasSpace - escapedText = `"${text}"`; - } - } - - return escapedText; - } - - static filterWithSymbol(filterSymbol, input, item) { - const updatedItem = item; - const query = gl.DropdownUtils.getSearchInput(input); - const { lastToken, searchToken } = gl.FilteredSearchTokenizer.processTokens(query); - - if (lastToken !== searchToken) { - const title = updatedItem.title.toLowerCase(); - let value = lastToken.value.toLowerCase(); - - // Removes the first character if it is a quotation so that we can search - // with multiple words - if ((value[0] === '"' || value[0] === '\'') && title.indexOf(' ') !== -1) { - value = value.slice(1); - } - - // Eg. filterSymbol = ~ for labels - const matchWithoutSymbol = lastToken.symbol === filterSymbol && title.indexOf(value) !== -1; - const match = title.indexOf(`${lastToken.symbol}${value}`) !== -1; - - updatedItem.droplab_hidden = !match && !matchWithoutSymbol; - } else { - updatedItem.droplab_hidden = false; - } - - return updatedItem; - } - - static filterHint(input, item) { - const updatedItem = item; - const query = gl.DropdownUtils.getSearchInput(input); - let { lastToken } = gl.FilteredSearchTokenizer.processTokens(query); - lastToken = lastToken.key || lastToken || ''; - - if (!lastToken || query.split('').last() === ' ') { - updatedItem.droplab_hidden = false; - } else if (lastToken) { - const split = lastToken.split(':'); - const tokenName = split[0].split(' ').last(); - - const match = updatedItem.hint.indexOf(tokenName.toLowerCase()) === -1; - updatedItem.droplab_hidden = tokenName ? match : false; - } - - return updatedItem; - } - - static setDataValueIfSelected(filter, selected) { - const dataValue = selected.getAttribute('data-value'); - - if (dataValue) { - gl.FilteredSearchDropdownManager.addWordToInput(filter, dataValue); - } - - // Return boolean based on whether it was set - return dataValue !== null; - } - - static getSearchInput(filteredSearchInput) { - const inputValue = filteredSearchInput.value; - const { right } = gl.DropdownUtils.getInputSelectionPosition(filteredSearchInput); - - return inputValue.slice(0, right); - } - - static getInputSelectionPosition(input) { - const selectionStart = input.selectionStart; - let inputValue = input.value; - // Replace all spaces inside quote marks with underscores - // (will continue to match entire string until an end quote is found if any) - // This helps with matching the beginning & end of a token:key - inputValue = inputValue.replace(/(('[^']*'{0,1})|("[^"]*"{0,1})|:\s+)/g, str => str.replace(/\s/g, '_')); - - // Get the right position for the word selected - // Regex matches first space - let right = inputValue.slice(selectionStart).search(/\s/); - - if (right >= 0) { - right += selectionStart; - } else if (right < 0) { - right = inputValue.length; - } - - // Get the left position for the word selected - // Regex matches last non-whitespace character - let left = inputValue.slice(0, right).search(/\S+$/); - - if (selectionStart === 0) { - left = 0; - } else if (selectionStart === inputValue.length && left < 0) { - left = inputValue.length; - } else if (left < 0) { - left = selectionStart; - } - - return { - left, - right, - }; - } - } - - window.gl = window.gl || {}; - gl.DropdownUtils = DropdownUtils; -})(); diff --git a/app/assets/javascripts/filtered_search/filtered_search_bundle.js b/app/assets/javascripts/filtered_search/filtered_search_bundle.js index 392f1835966..856eb6590ee 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_bundle.js +++ b/app/assets/javascripts/filtered_search/filtered_search_bundle.js @@ -1,3 +1,10 @@ -function requireAll(context) { return context.keys().map(context); } - -requireAll(require.context('./', true, /^\.\/(?!filtered_search_bundle).*\.(js|es6)$/)); +require('./dropdown_hint'); +require('./dropdown_non_user'); +require('./dropdown_user'); +require('./dropdown_utils'); +require('./filtered_search_dropdown_manager'); +require('./filtered_search_dropdown'); +require('./filtered_search_manager'); +require('./filtered_search_token_keys'); +require('./filtered_search_tokenizer'); +require('./filtered_search_visual_tokens'); diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js similarity index 92% rename from app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 rename to app/assets/javascripts/filtered_search/filtered_search_dropdown.js index fbc72a3001a..e7bf530d343 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js @@ -35,9 +35,10 @@ if (!dataValueSet) { const value = getValueFunction(selected); - gl.FilteredSearchDropdownManager.addWordToInput(this.filter, value); + gl.FilteredSearchDropdownManager.addWordToInput(this.filter, value, true); } + this.resetFilters(); this.dismissDropdown(); this.dispatchInputEvent(); } @@ -48,7 +49,11 @@ } setOffset(offset = 0) { - this.dropdown.style.left = `${offset}px`; + if (window.innerWidth > 480) { + this.dropdown.style.left = `${offset}px`; + } else { + this.dropdown.style.left = '0px'; + } } renderContent(forceShowList = false) { @@ -103,7 +108,7 @@ const hook = this.getCurrentHook(); if (hook) { - const data = hook.list.data; + const data = hook.list.data || []; const results = data.map((o) => { const updated = o; updated.droplab_hidden = false; diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js similarity index 67% rename from app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 rename to app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js index cecd3518ce3..5fbe0450bb8 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js @@ -1,12 +1,14 @@ /* global DropLab */ +import FilteredSearchContainer from './container'; (() => { class FilteredSearchDropdownManager { constructor(baseEndpoint = '', page) { + this.container = FilteredSearchContainer.container; this.baseEndpoint = baseEndpoint.replace(/\/$/, ''); this.tokenizer = gl.FilteredSearchTokenizer; this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys; - this.filteredSearchInput = document.querySelector('.filtered-search'); + this.filteredSearchInput = this.container.querySelector('.filtered-search'); this.page = page; this.setupMapping(); @@ -31,62 +33,42 @@ author: { reference: null, gl: 'DropdownUser', - element: document.querySelector('#js-dropdown-author'), + element: this.container.querySelector('#js-dropdown-author'), }, assignee: { reference: null, gl: 'DropdownUser', - element: document.querySelector('#js-dropdown-assignee'), + element: this.container.querySelector('#js-dropdown-assignee'), }, milestone: { reference: null, gl: 'DropdownNonUser', extraArguments: [`${this.baseEndpoint}/milestones.json`, '%'], - element: document.querySelector('#js-dropdown-milestone'), + element: this.container.querySelector('#js-dropdown-milestone'), }, label: { reference: null, gl: 'DropdownNonUser', extraArguments: [`${this.baseEndpoint}/labels.json`, '~'], - element: document.querySelector('#js-dropdown-label'), + element: this.container.querySelector('#js-dropdown-label'), }, hint: { reference: null, gl: 'DropdownHint', - element: document.querySelector('#js-dropdown-hint'), + element: this.container.querySelector('#js-dropdown-hint'), }, }; } - static addWordToInput(tokenName, tokenValue = '') { - const input = document.querySelector('.filtered-search'); - const inputValue = input.value; - const word = `${tokenName}:${tokenValue}`; + static addWordToInput(tokenName, tokenValue = '', clicked = false) { + const input = FilteredSearchContainer.container.querySelector('.filtered-search'); - // Get the string to replace - let newCaretPosition = input.selectionStart; - const { left, right } = gl.DropdownUtils.getInputSelectionPosition(input); + gl.FilteredSearchVisualTokens.addFilterVisualToken(tokenName, tokenValue); + input.value = ''; - input.value = `${inputValue.substr(0, left)}${word}${inputValue.substr(right)}`; - - // If we have added a tokenValue at the end of the input, - // add a space and set selection to the end - if (right >= inputValue.length && tokenValue !== '') { - input.value += ' '; - newCaretPosition = input.value.length; + if (clicked) { + gl.FilteredSearchVisualTokens.moveInputToTheRight(); } - - gl.FilteredSearchDropdownManager.updateInputCaretPosition(newCaretPosition, input); - } - - static updateInputCaretPosition(selectionStart, input) { - // Reset the position - // Sometimes can end up at end of input - input.setSelectionRange(selectionStart, selectionStart); - - const { right } = gl.DropdownUtils.getInputSelectionPosition(input); - - input.setSelectionRange(right, right); } updateCurrentDropdownOffset() { @@ -94,19 +76,14 @@ } updateDropdownOffset(key) { - if (!this.font) { - this.font = window.getComputedStyle(this.filteredSearchInput).font; - } + // Always align dropdown with the input field + let offset = this.filteredSearchInput.getBoundingClientRect().left - this.container.querySelector('.scroll-container').getBoundingClientRect().left; - const input = this.filteredSearchInput; - const inputText = input.value.slice(0, input.selectionStart); - const filterIconPadding = 27; - let offset = gl.text.getTextWidth(inputText, this.font) + filterIconPadding; - - const currentDropdownWidth = this.mapping[key].element.clientWidth === 0 ? 200 : - this.mapping[key].element.clientWidth; - const offsetMaxWidth = this.filteredSearchInput.clientWidth - currentDropdownWidth; + const maxInputWidth = 240; + const currentDropdownWidth = this.mapping[key].element.clientWidth || maxInputWidth; + // Make sure offset never exceeds the input container + const offsetMaxWidth = this.container.querySelector('.scroll-container').clientWidth - currentDropdownWidth; if (offsetMaxWidth < offset) { offset = offsetMaxWidth; } @@ -164,8 +141,8 @@ } setDropdown() { - const { lastToken, searchToken } = this.tokenizer - .processTokens(gl.DropdownUtils.getSearchInput(this.filteredSearchInput)); + const query = gl.DropdownUtils.getSearchQuery(true); + const { lastToken, searchToken } = this.tokenizer.processTokens(query); if (this.currentDropdown) { this.updateCurrentDropdownOffset(); @@ -187,6 +164,10 @@ } resetDropdowns() { + if (!this.currentDropdown) { + return; + } + // Force current dropdown to hide this.mapping[this.currentDropdown].reference.hideDropdown(); diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js new file mode 100644 index 00000000000..c6bb7fda8f2 --- /dev/null +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -0,0 +1,423 @@ +import FilteredSearchContainer from './container'; + +(() => { + class FilteredSearchManager { + constructor(page) { + this.container = FilteredSearchContainer.container; + this.filteredSearchInput = this.container.querySelector('.filtered-search'); + this.clearSearchButton = this.container.querySelector('.clear-search'); + this.tokensContainer = this.container.querySelector('.tokens-container'); + this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys; + + if (this.filteredSearchInput) { + this.tokenizer = gl.FilteredSearchTokenizer; + this.dropdownManager = new gl.FilteredSearchDropdownManager(this.filteredSearchInput.getAttribute('data-base-endpoint') || '', page); + + this.bindEvents(); + this.loadSearchParamsFromURL(); + this.dropdownManager.setDropdown(); + + this.cleanupWrapper = this.cleanup.bind(this); + document.addEventListener('beforeunload', this.cleanupWrapper); + } + } + + cleanup() { + this.unbindEvents(); + document.removeEventListener('beforeunload', this.cleanupWrapper); + } + + bindEvents() { + this.handleFormSubmit = this.handleFormSubmit.bind(this); + this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager); + this.toggleClearSearchButtonWrapper = this.toggleClearSearchButton.bind(this); + this.handleInputPlaceholderWrapper = this.handleInputPlaceholder.bind(this); + this.handleInputVisualTokenWrapper = this.handleInputVisualToken.bind(this); + this.checkForEnterWrapper = this.checkForEnter.bind(this); + this.clearSearchWrapper = this.clearSearch.bind(this); + this.checkForBackspaceWrapper = this.checkForBackspace.bind(this); + this.removeSelectedTokenWrapper = this.removeSelectedToken.bind(this); + this.unselectEditTokensWrapper = this.unselectEditTokens.bind(this); + this.editTokenWrapper = this.editToken.bind(this); + this.tokenChange = this.tokenChange.bind(this); + this.addInputContainerFocusWrapper = this.addInputContainerFocus.bind(this); + this.removeInputContainerFocusWrapper = this.removeInputContainerFocus.bind(this); + + this.filteredSearchInputForm = this.filteredSearchInput.form; + this.filteredSearchInputForm.addEventListener('submit', this.handleFormSubmit); + this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper); + this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper); + this.filteredSearchInput.addEventListener('input', this.handleInputPlaceholderWrapper); + this.filteredSearchInput.addEventListener('input', this.handleInputVisualTokenWrapper); + this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper); + this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper); + this.filteredSearchInput.addEventListener('click', this.tokenChange); + this.filteredSearchInput.addEventListener('keyup', this.tokenChange); + this.filteredSearchInput.addEventListener('focus', this.addInputContainerFocusWrapper); + this.tokensContainer.addEventListener('click', FilteredSearchManager.selectToken); + this.tokensContainer.addEventListener('dblclick', this.editTokenWrapper); + this.clearSearchButton.addEventListener('click', this.clearSearchWrapper); + document.addEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens); + document.addEventListener('click', this.unselectEditTokensWrapper); + document.addEventListener('click', this.removeInputContainerFocusWrapper); + document.addEventListener('keydown', this.removeSelectedTokenWrapper); + } + + unbindEvents() { + this.filteredSearchInputForm.removeEventListener('submit', this.handleFormSubmit); + this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper); + this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper); + this.filteredSearchInput.removeEventListener('input', this.handleInputPlaceholderWrapper); + this.filteredSearchInput.removeEventListener('input', this.handleInputVisualTokenWrapper); + this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper); + this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper); + this.filteredSearchInput.removeEventListener('click', this.tokenChange); + this.filteredSearchInput.removeEventListener('keyup', this.tokenChange); + this.filteredSearchInput.removeEventListener('focus', this.addInputContainerFocusWrapper); + this.tokensContainer.removeEventListener('click', FilteredSearchManager.selectToken); + this.tokensContainer.removeEventListener('dblclick', this.editTokenWrapper); + this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper); + document.removeEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens); + document.removeEventListener('click', this.unselectEditTokensWrapper); + document.removeEventListener('click', this.removeInputContainerFocusWrapper); + document.removeEventListener('keydown', this.removeSelectedTokenWrapper); + } + + checkForBackspace(e) { + // 8 = Backspace Key + // 46 = Delete Key + if (e.keyCode === 8 || e.keyCode === 46) { + const { lastVisualToken } = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + if (this.filteredSearchInput.value === '' && lastVisualToken) { + this.filteredSearchInput.value = gl.FilteredSearchVisualTokens.getLastTokenPartial(); + gl.FilteredSearchVisualTokens.removeLastTokenPartial(); + } + + // Reposition dropdown so that it is aligned with cursor + this.dropdownManager.updateCurrentDropdownOffset(); + } + } + + checkForEnter(e) { + if (e.keyCode === 38 || e.keyCode === 40) { + const selectionStart = this.filteredSearchInput.selectionStart; + + e.preventDefault(); + this.filteredSearchInput.setSelectionRange(selectionStart, selectionStart); + } + + if (e.keyCode === 13) { + const dropdown = this.dropdownManager.mapping[this.dropdownManager.currentDropdown]; + const dropdownEl = dropdown.element; + const activeElements = dropdownEl.querySelectorAll('.dropdown-active'); + + e.preventDefault(); + + if (!activeElements.length) { + if (this.isHandledAsync) { + e.stopImmediatePropagation(); + + this.filteredSearchInput.blur(); + this.dropdownManager.resetDropdowns(); + } else { + // Prevent droplab from opening dropdown + this.dropdownManager.destroyDroplab(); + } + + this.search(); + } + } + } + + addInputContainerFocus() { + const inputContainer = this.filteredSearchInput.closest('.filtered-search-input-container'); + + if (inputContainer) { + inputContainer.classList.add('focus'); + } + } + + removeInputContainerFocus(e) { + const inputContainer = this.filteredSearchInput.closest('.filtered-search-input-container'); + const isElementInFilteredSearch = inputContainer && inputContainer.contains(e.target); + const isElementInDynamicFilterDropdown = e.target.closest('.filter-dropdown') !== null; + const isElementInStaticFilterDropdown = e.target.closest('ul[data-dropdown]') !== null; + + if (!isElementInFilteredSearch && !isElementInDynamicFilterDropdown && + !isElementInStaticFilterDropdown && inputContainer) { + inputContainer.classList.remove('focus'); + } + } + + static selectToken(e) { + const button = e.target.closest('.selectable'); + + if (button) { + e.preventDefault(); + e.stopPropagation(); + gl.FilteredSearchVisualTokens.selectToken(button); + } + } + + unselectEditTokens(e) { + const inputContainer = this.container.querySelector('.filtered-search-input-container'); + const isElementInFilteredSearch = inputContainer && inputContainer.contains(e.target); + const isElementInFilterDropdown = e.target.closest('.filter-dropdown') !== null; + const isElementTokensContainer = e.target.classList.contains('tokens-container'); + + if ((!isElementInFilteredSearch && !isElementInFilterDropdown) || isElementTokensContainer) { + gl.FilteredSearchVisualTokens.moveInputToTheRight(); + this.dropdownManager.resetDropdowns(); + } + } + + editToken(e) { + const token = e.target.closest('.js-visual-token'); + + if (token) { + gl.FilteredSearchVisualTokens.editToken(token); + this.tokenChange(); + } + } + + toggleClearSearchButton() { + const query = gl.DropdownUtils.getSearchQuery(); + const hidden = 'hidden'; + const hasHidden = this.clearSearchButton.classList.contains(hidden); + + if (query.length === 0 && !hasHidden) { + this.clearSearchButton.classList.add(hidden); + } else if (query.length && hasHidden) { + this.clearSearchButton.classList.remove(hidden); + } + } + + handleInputPlaceholder() { + const query = gl.DropdownUtils.getSearchQuery(); + const placeholder = 'Search or filter results...'; + const currentPlaceholder = this.filteredSearchInput.placeholder; + + if (query.length === 0 && currentPlaceholder !== placeholder) { + this.filteredSearchInput.placeholder = placeholder; + } else if (query.length > 0 && currentPlaceholder !== '') { + this.filteredSearchInput.placeholder = ''; + } + } + + removeSelectedToken(e) { + // 8 = Backspace Key + // 46 = Delete Key + if (e.keyCode === 8 || e.keyCode === 46) { + gl.FilteredSearchVisualTokens.removeSelectedToken(); + this.handleInputPlaceholder(); + this.toggleClearSearchButton(); + } + } + + clearSearch(e) { + e.preventDefault(); + + this.filteredSearchInput.value = ''; + + const removeElements = []; + + [].forEach.call(this.tokensContainer.children, (t) => { + if (t.classList.contains('js-visual-token')) { + removeElements.push(t); + } + }); + + removeElements.forEach((el) => { + el.parentElement.removeChild(el); + }); + + this.clearSearchButton.classList.add('hidden'); + this.handleInputPlaceholder(); + + this.dropdownManager.resetDropdowns(); + + if (this.isHandledAsync) { + this.search(); + } + } + + handleInputVisualToken() { + const input = this.filteredSearchInput; + const { tokens, searchToken } + = gl.FilteredSearchTokenizer.processTokens(input.value); + const { isLastVisualTokenValid } + = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + if (isLastVisualTokenValid) { + tokens.forEach((t) => { + input.value = input.value.replace(`${t.key}:${t.symbol}${t.value}`, ''); + gl.FilteredSearchVisualTokens.addFilterVisualToken(t.key, `${t.symbol}${t.value}`); + }); + + const fragments = searchToken.split(':'); + if (fragments.length > 1) { + const inputValues = fragments[0].split(' '); + const tokenKey = inputValues.last(); + + if (inputValues.length > 1) { + inputValues.pop(); + const searchTerms = inputValues.join(' '); + + input.value = input.value.replace(searchTerms, ''); + gl.FilteredSearchVisualTokens.addSearchVisualToken(searchTerms); + } + + gl.FilteredSearchVisualTokens.addFilterVisualToken(tokenKey); + input.value = input.value.replace(`${tokenKey}:`, ''); + } + } else { + // Keep listening to token until we determine that the user is done typing the token value + const valueCompletedRegex = /([~%@]{0,1}".+")|([~%@]{0,1}'.+')|^((?![~%@]')(?![~%@]")(?!')(?!")).*/g; + + if (searchToken.match(valueCompletedRegex) && input.value[input.value.length - 1] === ' ') { + gl.FilteredSearchVisualTokens.addFilterVisualToken(searchToken); + + // Trim the last space as seen in the if statement above + input.value = input.value.replace(searchToken, '').trim(); + } + } + } + + handleFormSubmit(e) { + e.preventDefault(); + this.search(); + } + + loadSearchParamsFromURL() { + const params = gl.utils.getUrlParamsArray(); + const usernameParams = this.getUsernameParams(); + let hasFilteredSearch = false; + + params.forEach((p) => { + const split = p.split('='); + const keyParam = decodeURIComponent(split[0]); + const value = split[1]; + + // Check if it matches edge conditions listed in this.filteredSearchTokenKeys + const condition = this.filteredSearchTokenKeys.searchByConditionUrl(p); + + if (condition) { + hasFilteredSearch = true; + gl.FilteredSearchVisualTokens.addFilterVisualToken(condition.tokenKey, condition.value); + } else { + // Sanitize value since URL converts spaces into + + // Replace before decode so that we know what was originally + versus the encoded + + const sanitizedValue = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : value; + const match = this.filteredSearchTokenKeys.searchByKeyParam(keyParam); + + if (match) { + const indexOf = keyParam.indexOf('_'); + const sanitizedKey = indexOf !== -1 ? keyParam.slice(0, keyParam.indexOf('_')) : keyParam; + const symbol = match.symbol; + let quotationsToUse = ''; + + if (sanitizedValue.indexOf(' ') !== -1) { + // Prefer ", but use ' if required + quotationsToUse = sanitizedValue.indexOf('"') === -1 ? '"' : '\''; + } + + hasFilteredSearch = true; + gl.FilteredSearchVisualTokens.addFilterVisualToken(sanitizedKey, `${symbol}${quotationsToUse}${sanitizedValue}${quotationsToUse}`); + } else if (!match && keyParam === 'assignee_id') { + const id = parseInt(value, 10); + if (usernameParams[id]) { + hasFilteredSearch = true; + gl.FilteredSearchVisualTokens.addFilterVisualToken('assignee', `@${usernameParams[id]}`); + } + } else if (!match && keyParam === 'author_id') { + const id = parseInt(value, 10); + if (usernameParams[id]) { + hasFilteredSearch = true; + gl.FilteredSearchVisualTokens.addFilterVisualToken('author', `@${usernameParams[id]}`); + } + } else if (!match && keyParam === 'search') { + hasFilteredSearch = true; + this.filteredSearchInput.value = sanitizedValue; + } + } + }); + + if (hasFilteredSearch) { + this.clearSearchButton.classList.remove('hidden'); + this.handleInputPlaceholder(); + } + } + + search() { + const paths = []; + const { tokens, searchToken } + = this.tokenizer.processTokens(gl.DropdownUtils.getSearchQuery()); + const currentState = gl.utils.getParameterByName('state') || 'opened'; + paths.push(`state=${currentState}`); + + tokens.forEach((token) => { + const condition = this.filteredSearchTokenKeys + .searchByConditionKeyValue(token.key, token.value.toLowerCase()); + const { param } = this.filteredSearchTokenKeys.searchByKey(token.key) || {}; + const keyParam = param ? `${token.key}_${param}` : token.key; + let tokenPath = ''; + + if (condition) { + tokenPath = condition.url; + } else { + let tokenValue = token.value; + + if ((tokenValue[0] === '\'' && tokenValue[tokenValue.length - 1] === '\'') || + (tokenValue[0] === '"' && tokenValue[tokenValue.length - 1] === '"')) { + tokenValue = tokenValue.slice(1, tokenValue.length - 1); + } + + tokenPath = `${keyParam}=${encodeURIComponent(tokenValue)}`; + } + + paths.push(tokenPath); + }); + + if (searchToken) { + const sanitized = searchToken.split(' ').map(t => encodeURIComponent(t)).join('+'); + paths.push(`search=${sanitized}`); + } + + const parameterizedUrl = `?scope=all&utf8=✓&${paths.join('&')}`; + + if (this.updateObject) { + this.updateObject(parameterizedUrl); + } else { + gl.utils.visitUrl(parameterizedUrl); + } + } + + getUsernameParams() { + const usernamesById = {}; + try { + const attribute = this.filteredSearchInput.getAttribute('data-username-params'); + JSON.parse(attribute).forEach((user) => { + usernamesById[user.id] = user.username; + }); + } catch (e) { + // do nothing + } + return usernamesById; + } + + tokenChange() { + const dropdown = this.dropdownManager.mapping[this.dropdownManager.currentDropdown]; + + if (dropdown) { + const currentDropdownRef = dropdown.reference; + + this.setDropdownWrapper(); + currentDropdownRef.dispatchInputEvent(); + } + } + } + + window.gl = window.gl || {}; + gl.FilteredSearchManager = FilteredSearchManager; +})(); diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 deleted file mode 100644 index bbafead0305..00000000000 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ /dev/null @@ -1,231 +0,0 @@ -(() => { - class FilteredSearchManager { - constructor(page) { - this.filteredSearchInput = document.querySelector('.filtered-search'); - this.clearSearchButton = document.querySelector('.clear-search'); - this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys; - - if (this.filteredSearchInput) { - this.tokenizer = gl.FilteredSearchTokenizer; - this.dropdownManager = new gl.FilteredSearchDropdownManager(this.filteredSearchInput.getAttribute('data-base-endpoint') || '', page); - - this.bindEvents(); - this.loadSearchParamsFromURL(); - this.dropdownManager.setDropdown(); - - this.cleanupWrapper = this.cleanup.bind(this); - document.addEventListener('beforeunload', this.cleanupWrapper); - } - } - - cleanup() { - this.unbindEvents(); - document.removeEventListener('beforeunload', this.cleanupWrapper); - } - - bindEvents() { - this.handleFormSubmit = this.handleFormSubmit.bind(this); - this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager); - this.toggleClearSearchButtonWrapper = this.toggleClearSearchButton.bind(this); - this.checkForEnterWrapper = this.checkForEnter.bind(this); - this.clearSearchWrapper = this.clearSearch.bind(this); - this.checkForBackspaceWrapper = this.checkForBackspace.bind(this); - this.tokenChange = this.tokenChange.bind(this); - - this.filteredSearchInput.form.addEventListener('submit', this.handleFormSubmit); - this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper); - this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper); - this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper); - this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper); - this.filteredSearchInput.addEventListener('click', this.tokenChange); - this.filteredSearchInput.addEventListener('keyup', this.tokenChange); - this.clearSearchButton.addEventListener('click', this.clearSearchWrapper); - } - - unbindEvents() { - this.filteredSearchInput.form.removeEventListener('submit', this.handleFormSubmit); - this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper); - this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper); - this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper); - this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper); - this.filteredSearchInput.removeEventListener('click', this.tokenChange); - this.filteredSearchInput.removeEventListener('keyup', this.tokenChange); - this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper); - } - - checkForBackspace(e) { - // 8 = Backspace Key - // 46 = Delete Key - if (e.keyCode === 8 || e.keyCode === 46) { - // Reposition dropdown so that it is aligned with cursor - this.dropdownManager.updateCurrentDropdownOffset(); - } - } - - checkForEnter(e) { - if (e.keyCode === 38 || e.keyCode === 40) { - const selectionStart = this.filteredSearchInput.selectionStart; - - e.preventDefault(); - this.filteredSearchInput.setSelectionRange(selectionStart, selectionStart); - } - - if (e.keyCode === 13) { - const dropdown = this.dropdownManager.mapping[this.dropdownManager.currentDropdown]; - const dropdownEl = dropdown.element; - const activeElements = dropdownEl.querySelectorAll('.dropdown-active'); - - e.preventDefault(); - - if (!activeElements.length) { - // Prevent droplab from opening dropdown - this.dropdownManager.destroyDroplab(); - - this.search(); - } - } - } - - toggleClearSearchButton(e) { - if (e.target.value) { - this.clearSearchButton.classList.remove('hidden'); - } else { - this.clearSearchButton.classList.add('hidden'); - } - } - - clearSearch(e) { - e.preventDefault(); - - this.filteredSearchInput.value = ''; - this.clearSearchButton.classList.add('hidden'); - - this.dropdownManager.resetDropdowns(); - } - - handleFormSubmit(e) { - e.preventDefault(); - this.search(); - } - - loadSearchParamsFromURL() { - const params = gl.utils.getUrlParamsArray(); - const usernameParams = this.getUsernameParams(); - const inputValues = []; - - params.forEach((p) => { - const split = p.split('='); - const keyParam = decodeURIComponent(split[0]); - const value = split[1]; - - // Check if it matches edge conditions listed in this.filteredSearchTokenKeys - const condition = this.filteredSearchTokenKeys.searchByConditionUrl(p); - - if (condition) { - inputValues.push(`${condition.tokenKey}:${condition.value}`); - } else { - // Sanitize value since URL converts spaces into + - // Replace before decode so that we know what was originally + versus the encoded + - const sanitizedValue = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : value; - const match = this.filteredSearchTokenKeys.searchByKeyParam(keyParam); - - if (match) { - const indexOf = keyParam.indexOf('_'); - const sanitizedKey = indexOf !== -1 ? keyParam.slice(0, keyParam.indexOf('_')) : keyParam; - const symbol = match.symbol; - let quotationsToUse = ''; - - if (sanitizedValue.indexOf(' ') !== -1) { - // Prefer ", but use ' if required - quotationsToUse = sanitizedValue.indexOf('"') === -1 ? '"' : '\''; - } - - inputValues.push(`${sanitizedKey}:${symbol}${quotationsToUse}${sanitizedValue}${quotationsToUse}`); - } else if (!match && keyParam === 'assignee_id') { - const id = parseInt(value, 10); - if (usernameParams[id]) { - inputValues.push(`assignee:@${usernameParams[id]}`); - } - } else if (!match && keyParam === 'author_id') { - const id = parseInt(value, 10); - if (usernameParams[id]) { - inputValues.push(`author:@${usernameParams[id]}`); - } - } else if (!match && keyParam === 'search') { - inputValues.push(sanitizedValue); - } - } - }); - - // Trim the last space value - this.filteredSearchInput.value = inputValues.join(' '); - - if (inputValues.length > 0) { - this.clearSearchButton.classList.remove('hidden'); - } - } - - search() { - const paths = []; - const { tokens, searchToken } = this.tokenizer.processTokens(this.filteredSearchInput.value); - const currentState = gl.utils.getParameterByName('state') || 'opened'; - paths.push(`state=${currentState}`); - - tokens.forEach((token) => { - const condition = this.filteredSearchTokenKeys - .searchByConditionKeyValue(token.key, token.value.toLowerCase()); - const { param } = this.filteredSearchTokenKeys.searchByKey(token.key) || {}; - const keyParam = param ? `${token.key}_${param}` : token.key; - let tokenPath = ''; - - if (condition) { - tokenPath = condition.url; - } else { - let tokenValue = token.value; - - if ((tokenValue[0] === '\'' && tokenValue[tokenValue.length - 1] === '\'') || - (tokenValue[0] === '"' && tokenValue[tokenValue.length - 1] === '"')) { - tokenValue = tokenValue.slice(1, tokenValue.length - 1); - } - - tokenPath = `${keyParam}=${encodeURIComponent(tokenValue)}`; - } - - paths.push(tokenPath); - }); - - if (searchToken) { - const sanitized = searchToken.split(' ').map(t => encodeURIComponent(t)).join('+'); - paths.push(`search=${sanitized}`); - } - - const parameterizedUrl = `?scope=all&utf8=✓&${paths.join('&')}`; - - gl.utils.visitUrl(parameterizedUrl); - } - - getUsernameParams() { - const usernamesById = {}; - try { - const attribute = this.filteredSearchInput.getAttribute('data-username-params'); - JSON.parse(attribute).forEach((user) => { - usernamesById[user.id] = user.username; - }); - } catch (e) { - // do nothing - } - return usernamesById; - } - - tokenChange() { - const dropdown = this.dropdownManager.mapping[this.dropdownManager.currentDropdown]; - const currentDropdownRef = dropdown.reference; - - this.setDropdownWrapper(); - currentDropdownRef.dispatchInputEvent(); - } - } - - window.gl = window.gl || {}; - gl.FilteredSearchManager = FilteredSearchManager; -})(); diff --git a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js similarity index 95% rename from app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 rename to app/assets/javascripts/filtered_search/filtered_search_token_keys.js index e6b53cd4b55..6d5df86f2a5 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js @@ -42,6 +42,10 @@ url: 'milestone_title=%23upcoming', tokenKey: 'milestone', value: 'upcoming', + }, { + url: 'milestone_title=%23started', + tokenKey: 'milestone', + value: 'started', }, { url: 'label_name[]=No+Label', tokenKey: 'label', diff --git a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js similarity index 100% rename from app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 rename to app/assets/javascripts/filtered_search/filtered_search_tokenizer.js diff --git a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js new file mode 100644 index 00000000000..a5657fc8720 --- /dev/null +++ b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js @@ -0,0 +1,202 @@ +import FilteredSearchContainer from './container'; + +class FilteredSearchVisualTokens { + static getLastVisualTokenBeforeInput() { + const inputLi = FilteredSearchContainer.container.querySelector('.input-token'); + const lastVisualToken = inputLi && inputLi.previousElementSibling; + + return { + lastVisualToken, + isLastVisualTokenValid: lastVisualToken === null || lastVisualToken.className.indexOf('filtered-search-term') !== -1 || (lastVisualToken && lastVisualToken.querySelector('.value') !== null), + }; + } + + static unselectTokens() { + const otherTokens = FilteredSearchContainer.container.querySelectorAll('.js-visual-token .selectable.selected'); + [].forEach.call(otherTokens, t => t.classList.remove('selected')); + } + + static selectToken(tokenButton) { + const selected = tokenButton.classList.contains('selected'); + FilteredSearchVisualTokens.unselectTokens(); + + if (!selected) { + tokenButton.classList.add('selected'); + } + } + + static removeSelectedToken() { + const selected = FilteredSearchContainer.container.querySelector('.js-visual-token .selected'); + + if (selected) { + const li = selected.closest('.js-visual-token'); + li.parentElement.removeChild(li); + } + } + + static createVisualTokenElementHTML() { + return ` +
+
+
+
+ `; + } + + static addVisualTokenElement(name, value, isSearchTerm) { + const li = document.createElement('li'); + li.classList.add('js-visual-token'); + li.classList.add(isSearchTerm ? 'filtered-search-term' : 'filtered-search-token'); + + if (value) { + li.innerHTML = FilteredSearchVisualTokens.createVisualTokenElementHTML(); + li.querySelector('.value').innerText = value; + } else { + li.innerHTML = '
'; + } + li.querySelector('.name').innerText = name; + + const tokensContainer = FilteredSearchContainer.container.querySelector('.tokens-container'); + const input = FilteredSearchContainer.container.querySelector('.filtered-search'); + tokensContainer.insertBefore(li, input.parentElement); + } + + static addValueToPreviousVisualTokenElement(value) { + const { lastVisualToken, isLastVisualTokenValid } = + FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + if (!isLastVisualTokenValid && lastVisualToken.classList.contains('filtered-search-token')) { + const name = FilteredSearchVisualTokens.getLastTokenPartial(); + lastVisualToken.innerHTML = FilteredSearchVisualTokens.createVisualTokenElementHTML(); + lastVisualToken.querySelector('.name').innerText = name; + lastVisualToken.querySelector('.value').innerText = value; + } + } + + static addFilterVisualToken(tokenName, tokenValue) { + const { lastVisualToken, isLastVisualTokenValid } + = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + const addVisualTokenElement = FilteredSearchVisualTokens.addVisualTokenElement; + + if (isLastVisualTokenValid) { + addVisualTokenElement(tokenName, tokenValue, false); + } else { + const previousTokenName = lastVisualToken.querySelector('.name').innerText; + const tokensContainer = FilteredSearchContainer.container.querySelector('.tokens-container'); + tokensContainer.removeChild(lastVisualToken); + + const value = tokenValue || tokenName; + addVisualTokenElement(previousTokenName, value, false); + } + } + + static addSearchVisualToken(searchTerm) { + const { lastVisualToken } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + if (lastVisualToken && lastVisualToken.classList.contains('filtered-search-term')) { + lastVisualToken.querySelector('.name').innerText += ` ${searchTerm}`; + } else { + FilteredSearchVisualTokens.addVisualTokenElement(searchTerm, null, true); + } + } + + static getLastTokenPartial() { + const { lastVisualToken } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + if (!lastVisualToken) return ''; + + const value = lastVisualToken.querySelector('.value'); + const name = lastVisualToken.querySelector('.name'); + + const valueText = value ? value.innerText : ''; + const nameText = name ? name.innerText : ''; + + return valueText || nameText; + } + + static removeLastTokenPartial() { + const { lastVisualToken } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + if (lastVisualToken) { + const value = lastVisualToken.querySelector('.value'); + + if (value) { + const button = lastVisualToken.querySelector('.selectable'); + button.removeChild(value); + lastVisualToken.innerHTML = button.innerHTML; + } else { + lastVisualToken.closest('.tokens-container').removeChild(lastVisualToken); + } + } + } + + static tokenizeInput() { + const input = FilteredSearchContainer.container.querySelector('.filtered-search'); + const { isLastVisualTokenValid } = + gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + if (input.value) { + if (isLastVisualTokenValid) { + gl.FilteredSearchVisualTokens.addSearchVisualToken(input.value); + } else { + FilteredSearchVisualTokens.addValueToPreviousVisualTokenElement(input.value); + } + + input.value = ''; + } + } + + static editToken(token) { + const input = FilteredSearchContainer.container.querySelector('.filtered-search'); + + FilteredSearchVisualTokens.tokenizeInput(); + + // Replace token with input field + const tokenContainer = token.parentElement; + const inputLi = input.parentElement; + tokenContainer.replaceChild(inputLi, token); + + const name = token.querySelector('.name'); + const value = token.querySelector('.value'); + + if (token.classList.contains('filtered-search-token') && value) { + FilteredSearchVisualTokens.addFilterVisualToken(name.innerText); + input.value = value.innerText; + } else { + // token is a search term + input.value = name.innerText; + } + + // Opens dropdown + const inputEvent = new Event('input'); + input.dispatchEvent(inputEvent); + + // Adds cursor to input + input.focus(); + } + + static moveInputToTheRight() { + const input = FilteredSearchContainer.container.querySelector('.filtered-search'); + const inputLi = input.parentElement; + const tokenContainer = FilteredSearchContainer.container.querySelector('.tokens-container'); + + FilteredSearchVisualTokens.tokenizeInput(); + + if (!tokenContainer.lastElementChild.isEqualNode(inputLi)) { + const { isLastVisualTokenValid } = + gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); + + if (!isLastVisualTokenValid) { + const lastPartial = gl.FilteredSearchVisualTokens.getLastTokenPartial(); + gl.FilteredSearchVisualTokens.removeLastTokenPartial(); + gl.FilteredSearchVisualTokens.addSearchVisualToken(lastPartial); + } + + tokenContainer.removeChild(inputLi); + tokenContainer.appendChild(inputLi); + } + } +} + +window.gl = window.gl || {}; +gl.FilteredSearchVisualTokens = FilteredSearchVisualTokens; diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js index 730104b89f9..eec30624ff2 100644 --- a/app/assets/javascripts/flash.js +++ b/app/assets/javascripts/flash.js @@ -1,42 +1,41 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, no-param-reassign, quotes, quote-props, prefer-template, comma-dangle, max-len */ -(function() { - this.Flash = (function() { - var hideFlash; - hideFlash = function() { - return $(this).fadeOut(); - }; +window.Flash = (function() { + var hideFlash; - function Flash(message, type, parent) { - var flash, textDiv; - if (type == null) { - type = 'alert'; - } - if (parent == null) { - parent = null; - } - if (parent) { - this.flashContainer = parent.find('.flash-container'); - } else { - this.flashContainer = $('.flash-container-page'); - } - this.flashContainer.html(''); - flash = $('
', { - "class": "flash-" + type - }); - flash.on('click', hideFlash); - textDiv = $('
', { - "class": 'flash-text', - text: message - }); - textDiv.appendTo(flash); - if (this.flashContainer.parent().hasClass('content-wrapper')) { - textDiv.addClass('container-fluid container-limited'); - } - flash.appendTo(this.flashContainer); - this.flashContainer.show(); + hideFlash = function() { + return $(this).fadeOut(); + }; + + function Flash(message, type, parent) { + var flash, textDiv; + if (type == null) { + type = 'alert'; } + if (parent == null) { + parent = null; + } + if (parent) { + this.flashContainer = parent.find('.flash-container'); + } else { + this.flashContainer = $('.flash-container-page'); + } + this.flashContainer.html(''); + flash = $('
', { + "class": "flash-" + type + }); + flash.on('click', hideFlash); + textDiv = $('
', { + "class": 'flash-text', + text: message + }); + textDiv.appendTo(flash); + if (this.flashContainer.parent().hasClass('content-wrapper')) { + textDiv.addClass('container-fluid container-limited'); + } + flash.appendTo(this.flashContainer); + this.flashContainer.show(); + } - return Flash; - })(); -}).call(window); + return Flash; +})(); diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js new file mode 100644 index 00000000000..9ac4c49d697 --- /dev/null +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -0,0 +1,390 @@ +/* eslint-disable func-names, space-before-function-paren, no-template-curly-in-string, comma-dangle, object-shorthand, quotes, dot-notation, no-else-return, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-param-reassign, no-useless-escape, prefer-template, consistent-return, wrap-iife, prefer-arrow-callback, camelcase, no-unused-vars, no-useless-return, vars-on-top, max-len */ + +import emojiMap from 'emojis/digests.json'; +import emojiAliases from 'emojis/aliases.json'; +import { glEmojiTag } from '~/behaviors/gl_emoji'; + +// Creates the variables for setting up GFM auto-completion +window.gl = window.gl || {}; + +function sanitize(str) { + return str.replace(/<(?:.|\n)*?>/gm, ''); +} + +window.gl.GfmAutoComplete = { + dataSources: {}, + defaultLoadingData: ['loading'], + cachedData: {}, + isLoadingData: {}, + atTypeMap: { + ':': 'emojis', + '@': 'members', + '#': 'issues', + '!': 'mergeRequests', + '~': 'labels', + '%': 'milestones', + '/': 'commands' + }, + // Emoji + Emoji: { + templateFunction: function(name) { + return `
  • + ${name} ${glEmojiTag(name)} +
  • + `; + } + }, + // Team Members + Members: { + template: '
  • ${avatarTag} ${username} ${title}
  • ' + }, + Labels: { + template: '
  • ${title}
  • ' + }, + // Issues and MergeRequests + Issues: { + template: '
  • ${id} ${title}
  • ' + }, + // Milestones + Milestones: { + template: '
  • ${title}
  • ' + }, + Loading: { + template: '
  • Loading...
  • ' + }, + DefaultOptions: { + sorter: function(query, items, searchKey) { + this.setting.highlightFirst = this.setting.alwaysHighlightFirst || query.length > 0; + if (gl.GfmAutoComplete.isLoading(items)) { + this.setting.highlightFirst = false; + return items; + } + return $.fn.atwho["default"].callbacks.sorter(query, items, searchKey); + }, + filter: function(query, data, searchKey) { + if (gl.GfmAutoComplete.isLoading(data)) { + gl.GfmAutoComplete.fetchData(this.$inputor, this.at); + return data; + } else { + return $.fn.atwho["default"].callbacks.filter(query, data, searchKey); + } + }, + beforeInsert: function(value) { + if (value && !this.setting.skipSpecialCharacterTest) { + var withoutAt = value.substring(1); + if (withoutAt && /[^\w\d]/.test(withoutAt)) value = value.charAt() + '"' + withoutAt + '"'; + } + return value; + }, + matcher: function (flag, subtext) { + // The below is taken from At.js source + // Tweaked to commands to start without a space only if char before is a non-word character + // https://github.com/ichord/At.js + var _a, _y, regexp, match, atSymbolsWithBar, atSymbolsWithoutBar; + atSymbolsWithBar = Object.keys(this.app.controllers).join('|'); + atSymbolsWithoutBar = Object.keys(this.app.controllers).join(''); + subtext = subtext.split(/\s+/g).pop(); + flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + + _a = decodeURI("%C3%80"); + _y = decodeURI("%C3%BF"); + + regexp = new RegExp("^(?:\\B|[^a-zA-Z0-9_" + atSymbolsWithoutBar + "]|\\s)" + flag + "(?!" + atSymbolsWithBar + ")((?:[A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]|[^\\x00-\\x7a])*)$", 'gi'); + + match = regexp.exec(subtext); + + if (match) { + return match[1]; + } else { + return null; + } + } + }, + setup: function(input) { + // Add GFM auto-completion to all input fields, that accept GFM input. + this.input = input || $('.js-gfm-input'); + this.setupLifecycle(); + }, + setupLifecycle() { + this.input.each((i, input) => { + const $input = $(input); + $input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input)); + // This triggers at.js again + // Needed for slash commands with suffixes (ex: /label ~) + $input.on('inserted-commands.atwho', $input.trigger.bind($input, 'keyup')); + }); + }, + setupAtWho: function($input) { + // Emoji + $input.atwho({ + at: ':', + displayTpl: function(value) { + return value && value.name ? this.Emoji.templateFunction(value.name) : this.Loading.template; + }.bind(this), + insertTpl: ':${name}:', + skipSpecialCharacterTest: true, + data: this.defaultLoadingData, + callbacks: { + sorter: this.DefaultOptions.sorter, + beforeInsert: this.DefaultOptions.beforeInsert, + filter: this.DefaultOptions.filter + } + }); + // Team Members + $input.atwho({ + at: '@', + displayTpl: function(value) { + return value.username != null ? this.Members.template : this.Loading.template; + }.bind(this), + insertTpl: '${atwho-at}${username}', + searchKey: 'search', + alwaysHighlightFirst: true, + skipSpecialCharacterTest: true, + data: this.defaultLoadingData, + callbacks: { + sorter: this.DefaultOptions.sorter, + filter: this.DefaultOptions.filter, + beforeInsert: this.DefaultOptions.beforeInsert, + matcher: this.DefaultOptions.matcher, + beforeSave: function(members) { + return $.map(members, function(m) { + let title = ''; + if (m.username == null) { + return m; + } + title = m.name; + if (m.count) { + title += " (" + m.count + ")"; + } + + const autoCompleteAvatar = m.avatar_url || m.username.charAt(0).toUpperCase(); + const imgAvatar = `${m.username}`; + const txtAvatar = `
    ${autoCompleteAvatar}
    `; + + return { + username: m.username, + avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar, + title: sanitize(title), + search: sanitize(m.username + " " + m.name) + }; + }); + } + } + }); + $input.atwho({ + at: '#', + alias: 'issues', + searchKey: 'search', + displayTpl: function(value) { + return value.title != null ? this.Issues.template : this.Loading.template; + }.bind(this), + data: this.defaultLoadingData, + insertTpl: '${atwho-at}${id}', + callbacks: { + sorter: this.DefaultOptions.sorter, + filter: this.DefaultOptions.filter, + beforeInsert: this.DefaultOptions.beforeInsert, + matcher: this.DefaultOptions.matcher, + beforeSave: function(issues) { + return $.map(issues, function(i) { + if (i.title == null) { + return i; + } + return { + id: i.iid, + title: sanitize(i.title), + search: i.iid + " " + i.title + }; + }); + } + } + }); + $input.atwho({ + at: '%', + alias: 'milestones', + searchKey: 'search', + insertTpl: '${atwho-at}${title}', + displayTpl: function(value) { + return value.title != null ? this.Milestones.template : this.Loading.template; + }.bind(this), + data: this.defaultLoadingData, + callbacks: { + matcher: this.DefaultOptions.matcher, + sorter: this.DefaultOptions.sorter, + beforeInsert: this.DefaultOptions.beforeInsert, + filter: this.DefaultOptions.filter, + beforeSave: function(milestones) { + return $.map(milestones, function(m) { + if (m.title == null) { + return m; + } + return { + id: m.iid, + title: sanitize(m.title), + search: "" + m.title + }; + }); + } + } + }); + $input.atwho({ + at: '!', + alias: 'mergerequests', + searchKey: 'search', + displayTpl: function(value) { + return value.title != null ? this.Issues.template : this.Loading.template; + }.bind(this), + data: this.defaultLoadingData, + insertTpl: '${atwho-at}${id}', + callbacks: { + sorter: this.DefaultOptions.sorter, + filter: this.DefaultOptions.filter, + beforeInsert: this.DefaultOptions.beforeInsert, + matcher: this.DefaultOptions.matcher, + beforeSave: function(merges) { + return $.map(merges, function(m) { + if (m.title == null) { + return m; + } + return { + id: m.iid, + title: sanitize(m.title), + search: m.iid + " " + m.title + }; + }); + } + } + }); + $input.atwho({ + at: '~', + alias: 'labels', + searchKey: 'search', + data: this.defaultLoadingData, + displayTpl: function(value) { + return this.isLoading(value) ? this.Loading.template : this.Labels.template; + }.bind(this), + insertTpl: '${atwho-at}${title}', + callbacks: { + matcher: this.DefaultOptions.matcher, + beforeInsert: this.DefaultOptions.beforeInsert, + filter: this.DefaultOptions.filter, + sorter: this.DefaultOptions.sorter, + beforeSave: function(merges) { + if (gl.GfmAutoComplete.isLoading(merges)) return merges; + var sanitizeLabelTitle; + sanitizeLabelTitle = function(title) { + if (/[\w\?&]+\s+[\w\?&]+/g.test(title)) { + return "\"" + (sanitize(title)) + "\""; + } else { + return sanitize(title); + } + }; + return $.map(merges, function(m) { + return { + title: sanitize(m.title), + color: m.color, + search: "" + m.title + }; + }); + } + } + }); + // We don't instantiate the slash commands autocomplete for note and issue/MR edit forms + $input.filter('[data-supports-slash-commands="true"]').atwho({ + at: '/', + alias: 'commands', + searchKey: 'search', + skipSpecialCharacterTest: true, + data: this.defaultLoadingData, + displayTpl: function(value) { + if (this.isLoading(value)) return this.Loading.template; + var tpl = '
  • /${name}'; + if (value.aliases.length > 0) { + tpl += ' (or /<%- aliases.join(", /") %>)'; + } + if (value.params.length > 0) { + tpl += ' <%- params.join(" ") %>'; + } + if (value.description !== '') { + tpl += '<%- description %>'; + } + tpl += '
  • '; + return _.template(tpl)(value); + }.bind(this), + insertTpl: function(value) { + var tpl = "/${name} "; + var reference_prefix = null; + if (value.params.length > 0) { + reference_prefix = value.params[0][0]; + if (/^[@%~]/.test(reference_prefix)) { + tpl += '<%- reference_prefix %>'; + } + } + return _.template(tpl)({ reference_prefix: reference_prefix }); + }, + suffix: '', + callbacks: { + sorter: this.DefaultOptions.sorter, + filter: this.DefaultOptions.filter, + beforeInsert: this.DefaultOptions.beforeInsert, + beforeSave: function(commands) { + if (gl.GfmAutoComplete.isLoading(commands)) return commands; + return $.map(commands, function(c) { + var search = c.name; + if (c.aliases.length > 0) { + search = search + " " + c.aliases.join(" "); + } + return { + name: c.name, + aliases: c.aliases, + params: c.params, + description: c.description, + search: search + }; + }); + }, + matcher: function(flag, subtext, should_startWithSpace, acceptSpaceBar) { + var regexp = /(?:^|\n)\/([A-Za-z_]*)$/gi; + var match = regexp.exec(subtext); + if (match) { + return match[1]; + } else { + return null; + } + } + } + }); + return; + }, + fetchData: function($input, at) { + if (this.isLoadingData[at]) return; + this.isLoadingData[at] = true; + if (this.cachedData[at]) { + this.loadData($input, at, this.cachedData[at]); + } else if (this.atTypeMap[at] === 'emojis') { + this.loadData($input, at, Object.keys(emojiMap).concat(Object.keys(emojiAliases))); + } else { + $.getJSON(this.dataSources[this.atTypeMap[at]], (data) => { + this.loadData($input, at, data); + }).fail(() => { this.isLoadingData[at] = false; }); + } + }, + loadData: function($input, at, data) { + this.isLoadingData[at] = false; + this.cachedData[at] = data; + $input.atwho('load', at, data); + // This trigger at.js again + // otherwise we would be stuck with loading until the user types + return $input.trigger('keyup'); + }, + isLoading(data) { + var dataToInspect = data; + if (data && data.length > 0) { + dataToInspect = data[0]; + } + + var loadingState = this.defaultLoadingData[0]; + return dataToInspect && + (dataToInspect === loadingState || dataToInspect.name === loadingState); + } +}; diff --git a/app/assets/javascripts/gfm_auto_complete.js.es6 b/app/assets/javascripts/gfm_auto_complete.js.es6 deleted file mode 100644 index 60d6658dc16..00000000000 --- a/app/assets/javascripts/gfm_auto_complete.js.es6 +++ /dev/null @@ -1,383 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, no-template-curly-in-string, comma-dangle, object-shorthand, quotes, dot-notation, no-else-return, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-param-reassign, no-useless-escape, prefer-template, consistent-return, wrap-iife, prefer-arrow-callback, camelcase, no-unused-vars, no-useless-return, vars-on-top, max-len */ - -// Creates the variables for setting up GFM auto-completion -(function() { - if (window.gl == null) { - window.gl = {}; - } - - function sanitize(str) { - return str.replace(/<(?:.|\n)*?>/gm, ''); - } - - window.gl.GfmAutoComplete = { - dataSources: {}, - defaultLoadingData: ['loading'], - cachedData: {}, - isLoadingData: {}, - atTypeMap: { - ':': 'emojis', - '@': 'members', - '#': 'issues', - '!': 'mergeRequests', - '~': 'labels', - '%': 'milestones', - '/': 'commands' - }, - // Emoji - Emoji: { - template: '
  • ${name} ${name}
  • ' - }, - // Team Members - Members: { - template: '
  • ${avatarTag} ${username} ${title}
  • ' - }, - Labels: { - template: '
  • ${title}
  • ' - }, - // Issues and MergeRequests - Issues: { - template: '
  • ${id} ${title}
  • ' - }, - // Milestones - Milestones: { - template: '
  • ${title}
  • ' - }, - Loading: { - template: '
  • Loading...
  • ' - }, - DefaultOptions: { - sorter: function(query, items, searchKey) { - this.setting.highlightFirst = this.setting.alwaysHighlightFirst || query.length > 0; - if (gl.GfmAutoComplete.isLoading(items)) { - this.setting.highlightFirst = false; - return items; - } - return $.fn.atwho["default"].callbacks.sorter(query, items, searchKey); - }, - filter: function(query, data, searchKey) { - if (gl.GfmAutoComplete.isLoading(data)) { - gl.GfmAutoComplete.fetchData(this.$inputor, this.at); - return data; - } else { - return $.fn.atwho["default"].callbacks.filter(query, data, searchKey); - } - }, - beforeInsert: function(value) { - if (value && !this.setting.skipSpecialCharacterTest) { - var withoutAt = value.substring(1); - if (withoutAt && /[^\w\d]/.test(withoutAt)) value = value.charAt() + '"' + withoutAt + '"'; - } - return value; - }, - matcher: function (flag, subtext) { - // The below is taken from At.js source - // Tweaked to commands to start without a space only if char before is a non-word character - // https://github.com/ichord/At.js - var _a, _y, regexp, match, atSymbolsWithBar, atSymbolsWithoutBar; - atSymbolsWithBar = Object.keys(this.app.controllers).join('|'); - atSymbolsWithoutBar = Object.keys(this.app.controllers).join(''); - subtext = subtext.split(/\s+/g).pop(); - flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - - _a = decodeURI("%C3%80"); - _y = decodeURI("%C3%BF"); - - regexp = new RegExp("^(?:\\B|[^a-zA-Z0-9_" + atSymbolsWithoutBar + "]|\\s)" + flag + "(?!" + atSymbolsWithBar + ")((?:[A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]|[^\\x00-\\x7a])*)$", 'gi'); - - match = regexp.exec(subtext); - - if (match) { - return match[1]; - } else { - return null; - } - } - }, - setup: function(input) { - // Add GFM auto-completion to all input fields, that accept GFM input. - this.input = input || $('.js-gfm-input'); - this.setupLifecycle(); - }, - setupLifecycle() { - this.input.each((i, input) => { - const $input = $(input); - $input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input)); - // This triggers at.js again - // Needed for slash commands with suffixes (ex: /label ~) - $input.on('inserted-commands.atwho', $input.trigger.bind($input, 'keyup')); - }); - }, - setupAtWho: function($input) { - // Emoji - $input.atwho({ - at: ':', - displayTpl: function(value) { - return value.path != null ? this.Emoji.template : this.Loading.template; - }.bind(this), - insertTpl: ':${name}:', - skipSpecialCharacterTest: true, - data: this.defaultLoadingData, - callbacks: { - sorter: this.DefaultOptions.sorter, - beforeInsert: this.DefaultOptions.beforeInsert, - filter: this.DefaultOptions.filter - } - }); - // Team Members - $input.atwho({ - at: '@', - displayTpl: function(value) { - return value.username != null ? this.Members.template : this.Loading.template; - }.bind(this), - insertTpl: '${atwho-at}${username}', - searchKey: 'search', - alwaysHighlightFirst: true, - skipSpecialCharacterTest: true, - data: this.defaultLoadingData, - callbacks: { - sorter: this.DefaultOptions.sorter, - filter: this.DefaultOptions.filter, - beforeInsert: this.DefaultOptions.beforeInsert, - matcher: this.DefaultOptions.matcher, - beforeSave: function(members) { - return $.map(members, function(m) { - let title = ''; - if (m.username == null) { - return m; - } - title = m.name; - if (m.count) { - title += " (" + m.count + ")"; - } - - const autoCompleteAvatar = m.avatar_url || m.username.charAt(0).toUpperCase(); - const imgAvatar = `${m.username}`; - const txtAvatar = `
    ${autoCompleteAvatar}
    `; - - return { - username: m.username, - avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar, - title: sanitize(title), - search: sanitize(m.username + " " + m.name) - }; - }); - } - } - }); - $input.atwho({ - at: '#', - alias: 'issues', - searchKey: 'search', - displayTpl: function(value) { - return value.title != null ? this.Issues.template : this.Loading.template; - }.bind(this), - data: this.defaultLoadingData, - insertTpl: '${atwho-at}${id}', - callbacks: { - sorter: this.DefaultOptions.sorter, - filter: this.DefaultOptions.filter, - beforeInsert: this.DefaultOptions.beforeInsert, - matcher: this.DefaultOptions.matcher, - beforeSave: function(issues) { - return $.map(issues, function(i) { - if (i.title == null) { - return i; - } - return { - id: i.iid, - title: sanitize(i.title), - search: i.iid + " " + i.title - }; - }); - } - } - }); - $input.atwho({ - at: '%', - alias: 'milestones', - searchKey: 'search', - insertTpl: '${atwho-at}${title}', - displayTpl: function(value) { - return value.title != null ? this.Milestones.template : this.Loading.template; - }.bind(this), - data: this.defaultLoadingData, - callbacks: { - matcher: this.DefaultOptions.matcher, - sorter: this.DefaultOptions.sorter, - beforeInsert: this.DefaultOptions.beforeInsert, - filter: this.DefaultOptions.filter, - beforeSave: function(milestones) { - return $.map(milestones, function(m) { - if (m.title == null) { - return m; - } - return { - id: m.iid, - title: sanitize(m.title), - search: "" + m.title - }; - }); - } - } - }); - $input.atwho({ - at: '!', - alias: 'mergerequests', - searchKey: 'search', - displayTpl: function(value) { - return value.title != null ? this.Issues.template : this.Loading.template; - }.bind(this), - data: this.defaultLoadingData, - insertTpl: '${atwho-at}${id}', - callbacks: { - sorter: this.DefaultOptions.sorter, - filter: this.DefaultOptions.filter, - beforeInsert: this.DefaultOptions.beforeInsert, - matcher: this.DefaultOptions.matcher, - beforeSave: function(merges) { - return $.map(merges, function(m) { - if (m.title == null) { - return m; - } - return { - id: m.iid, - title: sanitize(m.title), - search: m.iid + " " + m.title - }; - }); - } - } - }); - $input.atwho({ - at: '~', - alias: 'labels', - searchKey: 'search', - data: this.defaultLoadingData, - displayTpl: function(value) { - return this.isLoading(value) ? this.Loading.template : this.Labels.template; - }.bind(this), - insertTpl: '${atwho-at}${title}', - callbacks: { - matcher: this.DefaultOptions.matcher, - beforeInsert: this.DefaultOptions.beforeInsert, - filter: this.DefaultOptions.filter, - sorter: this.DefaultOptions.sorter, - beforeSave: function(merges) { - if (gl.GfmAutoComplete.isLoading(merges)) return merges; - var sanitizeLabelTitle; - sanitizeLabelTitle = function(title) { - if (/[\w\?&]+\s+[\w\?&]+/g.test(title)) { - return "\"" + (sanitize(title)) + "\""; - } else { - return sanitize(title); - } - }; - return $.map(merges, function(m) { - return { - title: sanitize(m.title), - color: m.color, - search: "" + m.title - }; - }); - } - } - }); - // We don't instantiate the slash commands autocomplete for note and issue/MR edit forms - $input.filter('[data-supports-slash-commands="true"]').atwho({ - at: '/', - alias: 'commands', - searchKey: 'search', - skipSpecialCharacterTest: true, - data: this.defaultLoadingData, - displayTpl: function(value) { - if (this.isLoading(value)) return this.Loading.template; - var tpl = '
  • /${name}'; - if (value.aliases.length > 0) { - tpl += ' (or /<%- aliases.join(", /") %>)'; - } - if (value.params.length > 0) { - tpl += ' <%- params.join(" ") %>'; - } - if (value.description !== '') { - tpl += '<%- description %>'; - } - tpl += '
  • '; - return _.template(tpl)(value); - }.bind(this), - insertTpl: function(value) { - var tpl = "/${name} "; - var reference_prefix = null; - if (value.params.length > 0) { - reference_prefix = value.params[0][0]; - if (/^[@%~]/.test(reference_prefix)) { - tpl += '<%- reference_prefix %>'; - } - } - return _.template(tpl)({ reference_prefix: reference_prefix }); - }, - suffix: '', - callbacks: { - sorter: this.DefaultOptions.sorter, - filter: this.DefaultOptions.filter, - beforeInsert: this.DefaultOptions.beforeInsert, - beforeSave: function(commands) { - if (gl.GfmAutoComplete.isLoading(commands)) return commands; - return $.map(commands, function(c) { - var search = c.name; - if (c.aliases.length > 0) { - search = search + " " + c.aliases.join(" "); - } - return { - name: c.name, - aliases: c.aliases, - params: c.params, - description: c.description, - search: search - }; - }); - }, - matcher: function(flag, subtext, should_startWithSpace, acceptSpaceBar) { - var regexp = /(?:^|\n)\/([A-Za-z_]*)$/gi; - var match = regexp.exec(subtext); - if (match) { - return match[1]; - } else { - return null; - } - } - } - }); - return; - }, - fetchData: function($input, at) { - if (this.isLoadingData[at]) return; - this.isLoadingData[at] = true; - if (this.cachedData[at]) { - this.loadData($input, at, this.cachedData[at]); - } else { - $.getJSON(this.dataSources[this.atTypeMap[at]], (data) => { - this.loadData($input, at, data); - }).fail(() => { this.isLoadingData[at] = false; }); - } - }, - loadData: function($input, at, data) { - this.isLoadingData[at] = false; - this.cachedData[at] = data; - $input.atwho('load', at, data); - // This trigger at.js again - // otherwise we would be stuck with loading until the user types - return $input.trigger('keyup'); - }, - isLoading(data) { - var dataToInspect = data; - if (data && data.length > 0) { - dataToInspect = data[0]; - } - - var loadingState = this.defaultLoadingData[0]; - return dataToInspect && - (dataToInspect === loadingState || dataToInspect.name === loadingState); - } - }; -}).call(window); diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index a01662e2f9e..a03f1202a6d 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -1,850 +1,848 @@ /* eslint-disable func-names, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, prefer-rest-params, max-len, vars-on-top, wrap-iife, no-unused-vars, quotes, no-shadow, no-cond-assign, prefer-arrow-callback, no-return-assign, no-else-return, camelcase, comma-dangle, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, prefer-template, no-param-reassign, no-loop-func, no-mixed-operators */ /* global fuzzaldrinPlus */ -(function() { - var GitLabDropdown, GitLabDropdownFilter, GitLabDropdownRemote, - bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }, - indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i += 1) { if (i in this && this[i] === item) return i; } return -1; }; +var GitLabDropdown, GitLabDropdownFilter, GitLabDropdownRemote, + bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i += 1) { if (i in this && this[i] === item) return i; } return -1; }; - GitLabDropdownFilter = (function() { - var ARROW_KEY_CODES, BLUR_KEYCODES, HAS_VALUE_CLASS; +GitLabDropdownFilter = (function() { + var ARROW_KEY_CODES, BLUR_KEYCODES, HAS_VALUE_CLASS; - BLUR_KEYCODES = [27, 40]; + BLUR_KEYCODES = [27, 40]; - ARROW_KEY_CODES = [38, 40]; + ARROW_KEY_CODES = [38, 40]; - HAS_VALUE_CLASS = "has-value"; + HAS_VALUE_CLASS = "has-value"; - function GitLabDropdownFilter(input, options) { - var $clearButton, $inputContainer, ref, timeout; - this.input = input; - this.options = options; - this.filterInputBlur = (ref = this.options.filterInputBlur) != null ? ref : true; - $inputContainer = this.input.parent(); - $clearButton = $inputContainer.find('.js-dropdown-input-clear'); - $clearButton.on('click', (function(_this) { - // Clear click - return function(e) { + function GitLabDropdownFilter(input, options) { + var $clearButton, $inputContainer, ref, timeout; + this.input = input; + this.options = options; + this.filterInputBlur = (ref = this.options.filterInputBlur) != null ? ref : true; + $inputContainer = this.input.parent(); + $clearButton = $inputContainer.find('.js-dropdown-input-clear'); + $clearButton.on('click', (function(_this) { + // Clear click + return function(e) { + e.preventDefault(); + e.stopPropagation(); + return _this.input.val('').trigger('input').focus(); + }; + })(this)); + // Key events + timeout = ""; + this.input + .on('keydown', function (e) { + var keyCode = e.which; + if (keyCode === 13 && !options.elIsInput) { e.preventDefault(); - e.stopPropagation(); - return _this.input.val('').trigger('input').focus(); - }; - })(this)); - // Key events - timeout = ""; - this.input - .on('keydown', function (e) { - var keyCode = e.which; - if (keyCode === 13 && !options.elIsInput) { - e.preventDefault(); - } - }) - .on('input', function() { - if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) { - $inputContainer.addClass(HAS_VALUE_CLASS); - } else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) { - $inputContainer.removeClass(HAS_VALUE_CLASS); - } - // Only filter asynchronously only if option remote is set - if (this.options.remote) { - clearTimeout(timeout); - return timeout = setTimeout(function() { - $inputContainer.parent().addClass('is-loading'); - - return this.options.query(this.input.val(), function(data) { - $inputContainer.parent().removeClass('is-loading'); - return this.options.callback(data); - }.bind(this)); - }.bind(this), 250); - } else { - return this.filter(this.input.val()); - } - }.bind(this)); - } - - GitLabDropdownFilter.prototype.shouldBlur = function(keyCode) { - return BLUR_KEYCODES.indexOf(keyCode) >= 0; - }; - - GitLabDropdownFilter.prototype.filter = function(search_text) { - var data, elements, group, key, results, tmp; - if (this.options.onFilter) { - this.options.onFilter(search_text); - } - data = this.options.data(); - if ((data != null) && !this.options.filterByText) { - results = data; - if (search_text !== '') { - // When data is an array of objects therefore [object Array] e.g. - // [ - // { prop: 'foo' }, - // { prop: 'baz' } - // ] - if (_.isArray(data)) { - results = fuzzaldrinPlus.filter(data, search_text, { - key: this.options.keys - }); - } else { - // If data is grouped therefore an [object Object]. e.g. - // { - // groupName1: [ - // { prop: 'foo' }, - // { prop: 'baz' } - // ], - // groupName2: [ - // { prop: 'abc' }, - // { prop: 'def' } - // ] - // } - if (gl.utils.isObject(data)) { - results = {}; - for (key in data) { - group = data[key]; - tmp = fuzzaldrinPlus.filter(group, search_text, { - key: this.options.keys - }); - if (tmp.length) { - results[key] = tmp.map(function(item) { - return item; - }); - } - } - } - } } - return this.options.callback(results); - } else { - elements = this.options.elements(); - if (search_text) { - return elements.each(function() { - var $el, matches; - $el = $(this); - matches = fuzzaldrinPlus.match($el.text().trim(), search_text); - if (!$el.is('.dropdown-header')) { - if (matches.length) { - return $el.show().removeClass('option-hidden'); - } else { - return $el.hide().addClass('option-hidden'); - } - } + }) + .on('input', function() { + if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) { + $inputContainer.addClass(HAS_VALUE_CLASS); + } else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) { + $inputContainer.removeClass(HAS_VALUE_CLASS); + } + // Only filter asynchronously only if option remote is set + if (this.options.remote) { + clearTimeout(timeout); + return timeout = setTimeout(function() { + $inputContainer.parent().addClass('is-loading'); + + return this.options.query(this.input.val(), function(data) { + $inputContainer.parent().removeClass('is-loading'); + return this.options.callback(data); + }.bind(this)); + }.bind(this), 250); + } else { + return this.filter(this.input.val()); + } + }.bind(this)); + } + + GitLabDropdownFilter.prototype.shouldBlur = function(keyCode) { + return BLUR_KEYCODES.indexOf(keyCode) !== -1; + }; + + GitLabDropdownFilter.prototype.filter = function(search_text) { + var data, elements, group, key, results, tmp; + if (this.options.onFilter) { + this.options.onFilter(search_text); + } + data = this.options.data(); + if ((data != null) && !this.options.filterByText) { + results = data; + if (search_text !== '') { + // When data is an array of objects therefore [object Array] e.g. + // [ + // { prop: 'foo' }, + // { prop: 'baz' } + // ] + if (_.isArray(data)) { + results = fuzzaldrinPlus.filter(data, search_text, { + key: this.options.keys }); } else { - return elements.show().removeClass('option-hidden'); + // If data is grouped therefore an [object Object]. e.g. + // { + // groupName1: [ + // { prop: 'foo' }, + // { prop: 'baz' } + // ], + // groupName2: [ + // { prop: 'abc' }, + // { prop: 'def' } + // ] + // } + if (gl.utils.isObject(data)) { + results = {}; + for (key in data) { + group = data[key]; + tmp = fuzzaldrinPlus.filter(group, search_text, { + key: this.options.keys + }); + if (tmp.length) { + results[key] = tmp.map(function(item) { + return item; + }); + } + } + } } } - }; - - return GitLabDropdownFilter; - })(); - - GitLabDropdownRemote = (function() { - function GitLabDropdownRemote(dataEndpoint, options) { - this.dataEndpoint = dataEndpoint; - this.options = options; + return this.options.callback(results); + } else { + elements = this.options.elements(); + if (search_text) { + return elements.each(function() { + var $el, matches; + $el = $(this); + matches = fuzzaldrinPlus.match($el.text().trim(), search_text); + if (!$el.is('.dropdown-header')) { + if (matches.length) { + return $el.show().removeClass('option-hidden'); + } else { + return $el.hide().addClass('option-hidden'); + } + } + }); + } else { + return elements.show().removeClass('option-hidden'); + } } + }; - GitLabDropdownRemote.prototype.execute = function() { - if (typeof this.dataEndpoint === "string") { - return this.fetchData(); - } else if (typeof this.dataEndpoint === "function") { - if (this.options.beforeSend) { - this.options.beforeSend(); - } - return this.dataEndpoint("", (function(_this) { - // Fetch the data by calling the data funcfion - return function(data) { - if (_this.options.success) { - _this.options.success(data); - } - if (_this.options.beforeSend) { - return _this.options.beforeSend(); - } - }; - })(this)); + return GitLabDropdownFilter; +})(); + +GitLabDropdownRemote = (function() { + function GitLabDropdownRemote(dataEndpoint, options) { + this.dataEndpoint = dataEndpoint; + this.options = options; + } + + GitLabDropdownRemote.prototype.execute = function() { + if (typeof this.dataEndpoint === "string") { + return this.fetchData(); + } else if (typeof this.dataEndpoint === "function") { + if (this.options.beforeSend) { + this.options.beforeSend(); } - }; + return this.dataEndpoint("", (function(_this) { + // Fetch the data by calling the data funcfion + return function(data) { + if (_this.options.success) { + _this.options.success(data); + } + if (_this.options.beforeSend) { + return _this.options.beforeSend(); + } + }; + })(this)); + } + }; - GitLabDropdownRemote.prototype.fetchData = function() { - return $.ajax({ - url: this.dataEndpoint, - dataType: this.options.dataType, - beforeSend: (function(_this) { + GitLabDropdownRemote.prototype.fetchData = function() { + return $.ajax({ + url: this.dataEndpoint, + dataType: this.options.dataType, + beforeSend: (function(_this) { + return function() { + if (_this.options.beforeSend) { + return _this.options.beforeSend(); + } + }; + })(this), + success: (function(_this) { + return function(data) { + if (_this.options.success) { + return _this.options.success(data); + } + }; + })(this) + }); + // Fetch the data through ajax if the data is a string + }; + + return GitLabDropdownRemote; +})(); + +GitLabDropdown = (function() { + var ACTIVE_CLASS, FILTER_INPUT, INDETERMINATE_CLASS, LOADING_CLASS, PAGE_TWO_CLASS, NON_SELECTABLE_CLASSES, SELECTABLE_CLASSES, CURSOR_SELECT_SCROLL_PADDING, currentIndex; + + LOADING_CLASS = "is-loading"; + + PAGE_TWO_CLASS = "is-page-two"; + + ACTIVE_CLASS = "is-active"; + + INDETERMINATE_CLASS = "is-indeterminate"; + + currentIndex = -1; + + NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; + + SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ", .option-hidden)"; + + CURSOR_SELECT_SCROLL_PADDING = 5; + + FILTER_INPUT = '.dropdown-input .dropdown-input-field'; + + function GitLabDropdown(el1, options) { + var searchFields, selector, self; + this.el = el1; + this.options = options; + this.updateLabel = bind(this.updateLabel, this); + this.hidden = bind(this.hidden, this); + this.opened = bind(this.opened, this); + this.shouldPropagate = bind(this.shouldPropagate, this); + self = this; + selector = $(this.el).data("target"); + this.dropdown = selector != null ? $(selector) : $(this.el).parent(); + // Set Defaults + this.filterInput = this.options.filterInput || this.getElement(FILTER_INPUT); + this.highlight = !!this.options.highlight; + this.filterInputBlur = this.options.filterInputBlur != null + ? this.options.filterInputBlur + : true; + // If no input is passed create a default one + self = this; + // If selector was passed + if (_.isString(this.filterInput)) { + this.filterInput = this.getElement(this.filterInput); + } + searchFields = this.options.search ? this.options.search.fields : []; + 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)) { + this.fullData = this.options.data; + currentIndex = -1; + this.parseData(this.options.data); + this.focusTextInput(); + } else { + this.remote = new GitLabDropdownRemote(this.options.data, { + dataType: this.options.dataType, + beforeSend: this.toggleLoading.bind(this), + success: (function(_this) { + return function(data) { + _this.fullData = data; + _this.parseData(_this.fullData); + _this.focusTextInput(); + if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val() && _this.filter.input.val().trim() !== '') { + return _this.filter.input.trigger('input'); + } + }; + // Remote data + })(this) + }); + } + } + // Init filterable + if (this.options.filterable) { + this.filter = new GitLabDropdownFilter(this.filterInput, { + elIsInput: $(this.el).is('input'), + filterInputBlur: this.filterInputBlur, + filterByText: this.options.filterByText, + onFilter: this.options.onFilter, + remote: this.options.filterRemote, + query: this.options.data, + keys: searchFields, + elements: (function(_this) { return function() { - if (_this.options.beforeSend) { - return _this.options.beforeSend(); + selector = '.dropdown-content li:not(' + NON_SELECTABLE_CLASSES + ')'; + if (_this.dropdown.find('.dropdown-toggle-page').length) { + selector = ".dropdown-page-one " + selector; } + return $(selector); }; })(this), - success: (function(_this) { + data: (function(_this) { + return function() { + return _this.fullData; + }; + })(this), + callback: (function(_this) { return function(data) { - if (_this.options.success) { - return _this.options.success(data); + _this.parseData(data); + if (_this.filterInput.val() !== '') { + selector = SELECTABLE_CLASSES; + if (_this.dropdown.find('.dropdown-toggle-page').length) { + selector = ".dropdown-page-one " + selector; + } + if ($(_this.el).is('input')) { + currentIndex = -1; + } else { + $(selector, _this.dropdown).first().find('a').addClass('is-focused'); + currentIndex = 0; + } } }; })(this) }); - // Fetch the data through ajax if the data is a string - }; - - return GitLabDropdownRemote; - })(); - - GitLabDropdown = (function() { - var ACTIVE_CLASS, FILTER_INPUT, INDETERMINATE_CLASS, LOADING_CLASS, PAGE_TWO_CLASS, NON_SELECTABLE_CLASSES, SELECTABLE_CLASSES, CURSOR_SELECT_SCROLL_PADDING, currentIndex; - - LOADING_CLASS = "is-loading"; - - PAGE_TWO_CLASS = "is-page-two"; - - ACTIVE_CLASS = "is-active"; - - INDETERMINATE_CLASS = "is-indeterminate"; - - currentIndex = -1; - - NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; - - SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ", .option-hidden)"; - - CURSOR_SELECT_SCROLL_PADDING = 5; - - FILTER_INPUT = '.dropdown-input .dropdown-input-field'; - - function GitLabDropdown(el1, options) { - var searchFields, selector, self; - this.el = el1; - this.options = options; - this.updateLabel = bind(this.updateLabel, this); - this.hidden = bind(this.hidden, this); - this.opened = bind(this.opened, this); - this.shouldPropagate = bind(this.shouldPropagate, this); - self = this; - selector = $(this.el).data("target"); - this.dropdown = selector != null ? $(selector) : $(this.el).parent(); - // Set Defaults - this.filterInput = this.options.filterInput || this.getElement(FILTER_INPUT); - this.highlight = !!this.options.highlight; - this.filterInputBlur = this.options.filterInputBlur != null - ? this.options.filterInputBlur - : true; - // If no input is passed create a default one - self = this; - // If selector was passed - if (_.isString(this.filterInput)) { - this.filterInput = this.getElement(this.filterInput); + } + // Event listeners + this.dropdown.on("shown.bs.dropdown", this.opened); + this.dropdown.on("hidden.bs.dropdown", this.hidden); + $(this.el).on("update.label", this.updateLabel); + this.dropdown.on("click", ".dropdown-menu, .dropdown-menu-close", this.shouldPropagate); + this.dropdown.on('keyup', (function(_this) { + return function(e) { + // Escape key + if (e.which === 27) { + return $('.dropdown-menu-close', _this.dropdown).trigger('click'); + } + }; + })(this)); + this.dropdown.on('blur', 'a', (function(_this) { + return function(e) { + var $dropdownMenu, $relatedTarget; + if (e.relatedTarget != null) { + $relatedTarget = $(e.relatedTarget); + $dropdownMenu = $relatedTarget.closest('.dropdown-menu'); + if ($dropdownMenu.length === 0) { + return _this.dropdown.removeClass('open'); + } + } + }; + })(this)); + if (this.dropdown.find(".dropdown-toggle-page").length) { + this.dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on("click", (function(_this) { + return function(e) { + e.preventDefault(); + e.stopPropagation(); + return _this.togglePage(); + }; + })(this)); + } + if (this.options.selectable) { + selector = ".dropdown-content a"; + if (this.dropdown.find(".dropdown-toggle-page").length) { + selector = ".dropdown-page-one .dropdown-content a"; } - searchFields = this.options.search ? this.options.search.fields : []; - 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)) { - this.fullData = this.options.data; - currentIndex = -1; - this.parseData(this.options.data); - this.focusTextInput(); - } else { - this.remote = new GitLabDropdownRemote(this.options.data, { - dataType: this.options.dataType, - beforeSend: this.toggleLoading.bind(this), - success: (function(_this) { - return function(data) { - _this.fullData = data; - _this.parseData(_this.fullData); - _this.focusTextInput(); - if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val() && _this.filter.input.val().trim() !== '') { - return _this.filter.input.trigger('input'); - } - }; - // Remote data - })(this) + this.dropdown.on("click", selector, function(e) { + var $el, selected, selectedObj, isMarking; + $el = $(this); + selected = self.rowClicked($el); + selectedObj = selected ? selected[0] : null; + isMarking = selected ? selected[1] : null; + if (self.options.clicked) { + self.options.clicked(selectedObj, $el, e, isMarking); + } + + // Update label right after all modifications in dropdown has been done + if (self.options.toggleLabel) { + self.updateLabel(selectedObj, $el, self); + } + + $el.trigger('blur'); + }); + } + } + + // Finds an element inside wrapper element + GitLabDropdown.prototype.getElement = function(selector) { + return this.dropdown.find(selector); + }; + + GitLabDropdown.prototype.toggleLoading = function() { + return $('.dropdown-menu', this.dropdown).toggleClass(LOADING_CLASS); + }; + + GitLabDropdown.prototype.togglePage = function() { + var menu; + menu = $('.dropdown-menu', this.dropdown); + if (menu.hasClass(PAGE_TWO_CLASS)) { + if (this.remote) { + this.remote.execute(); + } + } + menu.toggleClass(PAGE_TWO_CLASS); + // Focus first visible input on active page + return this.dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus(); + }; + + GitLabDropdown.prototype.parseData = function(data) { + var full_html, groupData, html, name; + this.renderedData = data; + if (this.options.filterable && data.length === 0) { + // render no matching results + html = [this.noResults()]; + } else { + // Handle array groups + if (gl.utils.isObject(data)) { + html = []; + for (name in data) { + groupData = data[name]; + html.push(this.renderItem({ + header: name + // Add header for each group + }, name)); + this.renderData(groupData, name).map(function(item) { + return html.push(item); }); } + } else { + // Render each row + html = this.renderData(data); } - // Init filterable - if (this.options.filterable) { - this.filter = new GitLabDropdownFilter(this.filterInput, { - elIsInput: $(this.el).is('input'), - filterInputBlur: this.filterInputBlur, - filterByText: this.options.filterByText, - onFilter: this.options.onFilter, - remote: this.options.filterRemote, - query: this.options.data, - keys: searchFields, - elements: (function(_this) { - return function() { - selector = '.dropdown-content li:not(' + NON_SELECTABLE_CLASSES + ')'; - if (_this.dropdown.find('.dropdown-toggle-page').length) { - selector = ".dropdown-page-one " + selector; - } - return $(selector); - }; - })(this), - data: (function(_this) { - return function() { - return _this.fullData; - }; - })(this), - callback: (function(_this) { - return function(data) { - _this.parseData(data); - if (_this.filterInput.val() !== '') { - selector = SELECTABLE_CLASSES; - if (_this.dropdown.find('.dropdown-toggle-page').length) { - selector = ".dropdown-page-one " + selector; - } - if ($(_this.el).is('input')) { - currentIndex = -1; - } else { - $(selector, _this.dropdown).first().find('a').addClass('is-focused'); - currentIndex = 0; - } - } - }; - })(this) - }); + } + // Render the full menu + full_html = this.renderMenu(html); + return this.appendMenu(full_html); + }; + + GitLabDropdown.prototype.renderData = function(data, group) { + if (group == null) { + group = false; + } + return data.map((function(_this) { + return function(obj, index) { + return _this.renderItem(obj, group, index); + }; + })(this)); + }; + + GitLabDropdown.prototype.shouldPropagate = function(e) { + var $target; + if (this.options.multiSelect) { + $target = $(e.target); + if ($target && !$target.hasClass('dropdown-menu-close') && + !$target.hasClass('dropdown-menu-close-icon') && + !$target.data('is-link')) { + e.stopPropagation(); + return false; + } else { + return true; } - // Event listeners - this.dropdown.on("shown.bs.dropdown", this.opened); - this.dropdown.on("hidden.bs.dropdown", this.hidden); - $(this.el).on("update.label", this.updateLabel); - this.dropdown.on("click", ".dropdown-menu, .dropdown-menu-close", this.shouldPropagate); - this.dropdown.on('keyup', (function(_this) { - return function(e) { - // Escape key - if (e.which === 27) { - return $('.dropdown-menu-close', _this.dropdown).trigger('click'); - } - }; - })(this)); - this.dropdown.on('blur', 'a', (function(_this) { - return function(e) { - var $dropdownMenu, $relatedTarget; - if (e.relatedTarget != null) { - $relatedTarget = $(e.relatedTarget); - $dropdownMenu = $relatedTarget.closest('.dropdown-menu'); - if ($dropdownMenu.length === 0) { - return _this.dropdown.removeClass('open'); - } - } - }; - })(this)); - if (this.dropdown.find(".dropdown-toggle-page").length) { - this.dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on("click", (function(_this) { - return function(e) { - e.preventDefault(); - e.stopPropagation(); - return _this.togglePage(); - }; - })(this)); - } - if (this.options.selectable) { - selector = ".dropdown-content a"; - if (this.dropdown.find(".dropdown-toggle-page").length) { - selector = ".dropdown-page-one .dropdown-content a"; + } + }; + + GitLabDropdown.prototype.opened = function(e) { + var contentHtml; + this.resetRows(); + this.addArrowKeyEvent(); + + // Makes indeterminate items effective + if (this.fullData && this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) { + this.parseData(this.fullData); + } + contentHtml = $('.dropdown-content', this.dropdown).html(); + if (this.remote && contentHtml === "") { + this.remote.execute(); + } else { + this.focusTextInput(); + } + + if (this.options.showMenuAbove) { + this.positionMenuAbove(); + } + + if (this.options.opened) { + this.options.opened.call(this, e); + } + + return this.dropdown.trigger('shown.gl.dropdown'); + }; + + GitLabDropdown.prototype.positionMenuAbove = function() { + var $button = $(this.el); + var $menu = this.dropdown.find('.dropdown-menu'); + + $menu.css('top', ($button.height() + $menu.height()) * -1); + }; + + GitLabDropdown.prototype.hidden = function(e) { + var $input; + this.resetRows(); + this.removeArrayKeyEvent(); + $input = this.dropdown.find(".dropdown-input-field"); + if (this.options.filterable) { + $input.blur(); + } + if (this.dropdown.find(".dropdown-toggle-page").length) { + $('.dropdown-menu', this.dropdown).removeClass(PAGE_TWO_CLASS); + } + if (this.options.hidden) { + this.options.hidden.call(this, e); + } + return this.dropdown.trigger('hidden.gl.dropdown'); + }; + + // Render the full menu + GitLabDropdown.prototype.renderMenu = function(html) { + if (this.options.renderMenu) { + return this.options.renderMenu(html); + } else { + var ul = document.createElement('ul'); + + for (var i = 0; i < html.length; i += 1) { + var el = html[i]; + + if (el instanceof jQuery) { + el = el.get(0); } - this.dropdown.on("click", selector, function(e) { - var $el, selected, selectedObj, isMarking; - $el = $(this); - selected = self.rowClicked($el); - selectedObj = selected ? selected[0] : null; - isMarking = selected ? selected[1] : null; - if (self.options.clicked) { - self.options.clicked(selectedObj, $el, e, isMarking); - } - // Update label right after all modifications in dropdown has been done - if (self.options.toggleLabel) { - self.updateLabel(selectedObj, $el, self); - } + if (typeof el === 'string') { + ul.innerHTML += el; + } else { + ul.appendChild(el); + } + } - $el.trigger('blur'); - }); + return ul; + } + }; + + // Append the menu into the dropdown + GitLabDropdown.prototype.appendMenu = function(html) { + return this.clearMenu().append(html); + }; + + GitLabDropdown.prototype.clearMenu = function() { + var selector; + selector = '.dropdown-content'; + if (this.dropdown.find(".dropdown-toggle-page").length) { + selector = ".dropdown-page-one .dropdown-content"; + } + + return $(selector, this.dropdown).empty(); + }; + + GitLabDropdown.prototype.renderItem = function(data, group, index) { + var field, fieldName, html, selected, text, url, value; + if (group == null) { + group = false; + } + if (index == null) { + // Render the row + index = false; + } + html = document.createElement('li'); + if (data === 'divider' || data === 'separator') { + html.className = data; + return html; + } + // Header + if (data.header != null) { + html.className = 'dropdown-header'; + html.innerHTML = data.header; + return html; + } + if (this.options.renderRow) { + // Call the render function + html = this.options.renderRow.call(this.options, data, this); + } else { + if (!selected) { + value = this.options.id ? this.options.id(data) : data.id; + fieldName = this.options.fieldName; + + if (value) { value = value.toString().replace(/'/g, '\\\''); } + + field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']"); + if (field.length) { + selected = true; + } + } + // Set URL + if (this.options.url != null) { + url = this.options.url(data); + } else { + url = data.url != null ? data.url : '#'; + } + // Set Text + if (this.options.text != null) { + text = this.options.text(data); + } else { + text = data.text != null ? data.text : ''; + } + if (this.highlight) { + text = this.highlightTextMatches(text, this.filterInput.val()); + } + // Create the list item & the link + var link = document.createElement('a'); + + link.href = url; + link.innerHTML = text; + + if (selected) { + link.className = 'is-active'; + } + + if (group) { + link.dataset.group = group; + link.dataset.index = index; + } + + html.appendChild(link); + } + return html; + }; + + GitLabDropdown.prototype.highlightTextMatches = function(text, term) { + var occurrences; + occurrences = fuzzaldrinPlus.match(text, term); + return text.split('').map(function(character, i) { + if (indexOf.call(occurrences, i) !== -1) { + return "" + character + ""; + } else { + return character; + } + }).join(''); + }; + + GitLabDropdown.prototype.noResults = function() { + var html; + return html = ""; + }; + + GitLabDropdown.prototype.rowClicked = function(el) { + var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value, isMarking; + + fieldName = this.options.fieldName; + isInput = $(this.el).is('input'); + if (this.renderedData) { + groupName = el.data('group'); + if (groupName) { + selectedIndex = el.data('index'); + selectedObject = this.renderedData[groupName][selectedIndex]; + } else { + selectedIndex = el.closest('li').index(); + selectedObject = this.renderedData[selectedIndex]; } } - // Finds an element inside wrapper element - GitLabDropdown.prototype.getElement = function(selector) { - return this.dropdown.find(selector); - }; - - GitLabDropdown.prototype.toggleLoading = function() { - return $('.dropdown-menu', this.dropdown).toggleClass(LOADING_CLASS); - }; - - GitLabDropdown.prototype.togglePage = function() { - var menu; - menu = $('.dropdown-menu', this.dropdown); - if (menu.hasClass(PAGE_TWO_CLASS)) { - if (this.remote) { - this.remote.execute(); - } - } - menu.toggleClass(PAGE_TWO_CLASS); - // Focus first visible input on active page - return this.dropdown.find('[class^="dropdown-page-"]:visible :text:visible:first').focus(); - }; - - GitLabDropdown.prototype.parseData = function(data) { - var full_html, groupData, html, name; - this.renderedData = data; - if (this.options.filterable && data.length === 0) { - // render no matching results - html = [this.noResults()]; - } else { - // Handle array groups - if (gl.utils.isObject(data)) { - html = []; - for (name in data) { - groupData = data[name]; - html.push(this.renderItem({ - header: name - // Add header for each group - }, name)); - this.renderData(groupData, name).map(function(item) { - return html.push(item); - }); - } - } else { - // Render each row - html = this.renderData(data); - } - } - // Render the full menu - full_html = this.renderMenu(html); - return this.appendMenu(full_html); - }; - - GitLabDropdown.prototype.renderData = function(data, group) { - if (group == null) { - group = false; - } - return data.map((function(_this) { - return function(obj, index) { - return _this.renderItem(obj, group, index); - }; - })(this)); - }; - - GitLabDropdown.prototype.shouldPropagate = function(e) { - var $target; - if (this.options.multiSelect) { - $target = $(e.target); - if ($target && !$target.hasClass('dropdown-menu-close') && - !$target.hasClass('dropdown-menu-close-icon') && - !$target.data('is-link')) { - e.stopPropagation(); - return false; - } else { - return true; - } - } - }; - - GitLabDropdown.prototype.opened = function(e) { - var contentHtml; - this.resetRows(); - this.addArrowKeyEvent(); - - // Makes indeterminate items effective - if (this.fullData && this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) { - this.parseData(this.fullData); - } - contentHtml = $('.dropdown-content', this.dropdown).html(); - if (this.remote && contentHtml === "") { - this.remote.execute(); - } else { - this.focusTextInput(); - } - - if (this.options.showMenuAbove) { - this.positionMenuAbove(); - } - - if (this.options.opened) { - this.options.opened.call(this, e); - } - - return this.dropdown.trigger('shown.gl.dropdown'); - }; - - GitLabDropdown.prototype.positionMenuAbove = function() { - var $button = $(this.el); - var $menu = this.dropdown.find('.dropdown-menu'); - - $menu.css('top', ($button.height() + $menu.height()) * -1); - }; - - GitLabDropdown.prototype.hidden = function(e) { - var $input; - this.resetRows(); - this.removeArrayKeyEvent(); - $input = this.dropdown.find(".dropdown-input-field"); - if (this.options.filterable) { - $input.blur(); - } - if (this.dropdown.find(".dropdown-toggle-page").length) { - $('.dropdown-menu', this.dropdown).removeClass(PAGE_TWO_CLASS); - } - if (this.options.hidden) { - this.options.hidden.call(this, e); - } - return this.dropdown.trigger('hidden.gl.dropdown'); - }; - - // Render the full menu - GitLabDropdown.prototype.renderMenu = function(html) { - if (this.options.renderMenu) { - return this.options.renderMenu(html); - } else { - var ul = document.createElement('ul'); - - for (var i = 0; i < html.length; i += 1) { - var el = html[i]; - - if (el instanceof jQuery) { - el = el.get(0); - } - - if (typeof el === 'string') { - ul.innerHTML += el; - } else { - ul.appendChild(el); - } - } - - return ul; - } - }; - - // Append the menu into the dropdown - GitLabDropdown.prototype.appendMenu = function(html) { - return this.clearMenu().append(html); - }; - - GitLabDropdown.prototype.clearMenu = function() { - var selector; - selector = '.dropdown-content'; - if (this.dropdown.find(".dropdown-toggle-page").length) { - selector = ".dropdown-page-one .dropdown-content"; - } - - return $(selector, this.dropdown).empty(); - }; - - GitLabDropdown.prototype.renderItem = function(data, group, index) { - var field, fieldName, html, selected, text, url, value; - if (group == null) { - group = false; - } - if (index == null) { - // Render the row - index = false; - } - html = document.createElement('li'); - if (data === 'divider' || data === 'separator') { - html.className = data; - return html; - } - // Header - if (data.header != null) { - html.className = 'dropdown-header'; - html.innerHTML = data.header; - return html; - } - if (this.options.renderRow) { - // Call the render function - html = this.options.renderRow.call(this.options, data, this); - } else { - if (!selected) { - value = this.options.id ? this.options.id(data) : data.id; - fieldName = this.options.fieldName; - - if (value) { value = value.toString().replace(/'/g, '\\\''); } - - field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']"); - if (field.length) { - selected = true; - } - } - // Set URL - if (this.options.url != null) { - url = this.options.url(data); - } else { - url = data.url != null ? data.url : '#'; - } - // Set Text - if (this.options.text != null) { - text = this.options.text(data); - } else { - text = data.text != null ? data.text : ''; - } - if (this.highlight) { - text = this.highlightTextMatches(text, this.filterInput.val()); - } - // Create the list item & the link - var link = document.createElement('a'); - - link.href = url; - link.innerHTML = text; - - if (selected) { - link.className = 'is-active'; - } - - if (group) { - link.dataset.group = group; - link.dataset.index = index; - } - - html.appendChild(link); - } - return html; - }; - - GitLabDropdown.prototype.highlightTextMatches = function(text, term) { - var occurrences; - occurrences = fuzzaldrinPlus.match(text, term); - return text.split('').map(function(character, i) { - if (indexOf.call(occurrences, i) >= 0) { - return "" + character + ""; - } else { - return character; - } - }).join(''); - }; - - GitLabDropdown.prototype.noResults = function() { - var html; - return html = ""; - }; - - GitLabDropdown.prototype.rowClicked = function(el) { - var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value, isMarking; - - fieldName = this.options.fieldName; - isInput = $(this.el).is('input'); - if (this.renderedData) { - groupName = el.data('group'); - if (groupName) { - selectedIndex = el.data('index'); - selectedObject = this.renderedData[groupName][selectedIndex]; - } else { - selectedIndex = el.closest('li').index(); - selectedObject = this.renderedData[selectedIndex]; - } - } - - if (this.options.vue) { - if (el.hasClass(ACTIVE_CLASS)) { - el.removeClass(ACTIVE_CLASS); - } else { - el.addClass(ACTIVE_CLASS); - } - - return [selectedObject]; - } - - field = []; - value = this.options.id - ? this.options.id(selectedObject, el) - : selectedObject.id; - if (isInput) { - field = $(this.el); - } else if (value) { - field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, '\\\'') + "']"); - } - - if (this.options.isSelectable && !this.options.isSelectable(selectedObject, el)) { - return; - } - + if (this.options.vue) { if (el.hasClass(ACTIVE_CLASS)) { - isMarking = false; el.removeClass(ACTIVE_CLASS); - if (field && field.length) { - this.clearField(field, isInput); - } - } else if (el.hasClass(INDETERMINATE_CLASS)) { - isMarking = true; + } else { el.addClass(ACTIVE_CLASS); - el.removeClass(INDETERMINATE_CLASS); - if (field && field.length && value == null) { - this.clearField(field, isInput); + } + + return [selectedObject]; + } + + field = []; + value = this.options.id + ? this.options.id(selectedObject, el) + : selectedObject.id; + if (isInput) { + field = $(this.el); + } else if (value) { + field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, '\\\'') + "']"); + } + + if (this.options.isSelectable && !this.options.isSelectable(selectedObject, el)) { + return; + } + + if (el.hasClass(ACTIVE_CLASS)) { + isMarking = false; + el.removeClass(ACTIVE_CLASS); + if (field && field.length) { + this.clearField(field, isInput); + } + } else if (el.hasClass(INDETERMINATE_CLASS)) { + isMarking = true; + el.addClass(ACTIVE_CLASS); + el.removeClass(INDETERMINATE_CLASS); + if (field && field.length && value == null) { + this.clearField(field, isInput); + } + if ((!field || !field.length) && fieldName) { + this.addInput(fieldName, value, selectedObject); + } + } else { + isMarking = true; + if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) { + this.dropdown.find("." + ACTIVE_CLASS).removeClass(ACTIVE_CLASS); + if (!isInput) { + this.dropdown.parent().find("input[name='" + fieldName + "']").remove(); } + } + if (field && field.length && value == null) { + this.clearField(field, isInput); + } + // Toggle active class for the tick mark + el.addClass(ACTIVE_CLASS); + if (value != null) { if ((!field || !field.length) && fieldName) { this.addInput(fieldName, value, selectedObject); - } - } else { - isMarking = true; - if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) { - this.dropdown.find("." + ACTIVE_CLASS).removeClass(ACTIVE_CLASS); - if (!isInput) { - this.dropdown.parent().find("input[name='" + fieldName + "']").remove(); - } - } - if (field && field.length && value == null) { - this.clearField(field, isInput); - } - // Toggle active class for the tick mark - el.addClass(ACTIVE_CLASS); - if (value != null) { - if ((!field || !field.length) && fieldName) { - this.addInput(fieldName, value, selectedObject); - } else if (field && field.length) { - field.val(value).trigger('change'); - } + } else if (field && field.length) { + field.val(value).trigger('change'); } } + } - return [selectedObject, isMarking]; - }; - - GitLabDropdown.prototype.focusTextInput = function() { - if (this.options.filterable) { this.filterInput.focus(); } - }; - - GitLabDropdown.prototype.addInput = function(fieldName, value, selectedObject) { - var $input; - // Create hidden input for form - $input = $('').attr('type', 'hidden').attr('name', fieldName).val(value); - if (this.options.inputId != null) { - $input.attr('id', this.options.inputId); - } - return this.dropdown.before($input); - }; - - GitLabDropdown.prototype.selectRowAtIndex = function(index) { - var $el, selector; - // If we pass an option index - if (typeof index !== "undefined") { - selector = SELECTABLE_CLASSES + ":eq(" + index + ") a"; - } else { - selector = ".dropdown-content .is-focused"; - } - if (this.dropdown.find(".dropdown-toggle-page").length) { - selector = ".dropdown-page-one " + selector; - } - // simulate a click on the first link - $el = $(selector, this.dropdown); - if ($el.length) { - var href = $el.attr('href'); - if (href && href !== '#') { - gl.utils.visitUrl(href); - } else { - $el.first().trigger('click'); - } - } - }; - - GitLabDropdown.prototype.addArrowKeyEvent = function() { - var $input, ARROW_KEY_CODES, selector; - ARROW_KEY_CODES = [38, 40]; - $input = this.dropdown.find(".dropdown-input-field"); - selector = SELECTABLE_CLASSES; - if (this.dropdown.find(".dropdown-toggle-page").length) { - selector = ".dropdown-page-one " + selector; - } - return $('body').on('keydown', (function(_this) { - return function(e) { - var $listItems, PREV_INDEX, currentKeyCode; - currentKeyCode = e.which; - if (ARROW_KEY_CODES.indexOf(currentKeyCode) >= 0) { - e.preventDefault(); - e.stopImmediatePropagation(); - PREV_INDEX = currentIndex; - $listItems = $(selector, _this.dropdown); - // if @options.filterable - // $input.blur() - if (currentKeyCode === 40) { - // Move down - if (currentIndex < ($listItems.length - 1)) { - currentIndex += 1; - } - } else if (currentKeyCode === 38) { - // Move up - if (currentIndex > 0) { - currentIndex -= 1; - } - } - if (currentIndex !== PREV_INDEX) { - _this.highlightRowAtIndex($listItems, currentIndex); - } - return false; - } - if (currentKeyCode === 13 && currentIndex !== -1) { - e.preventDefault(); - _this.selectRowAtIndex(); - } - }; - })(this)); - }; - - GitLabDropdown.prototype.removeArrayKeyEvent = function() { - return $('body').off('keydown'); - }; - - GitLabDropdown.prototype.resetRows = function resetRows() { - currentIndex = -1; - $('.is-focused', this.dropdown).removeClass('is-focused'); - }; - - GitLabDropdown.prototype.highlightRowAtIndex = function($listItems, index) { - 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'); - // Update the class for the row at the specific index - $listItem = $listItems.eq(index); - $listItem.find('a:first-child').addClass("is-focused"); - // Dropdown content scroll area - $dropdownContent = $listItem.closest('.dropdown-content'); - dropdownScrollTop = $dropdownContent.scrollTop(); - dropdownContentHeight = $dropdownContent.outerHeight(); - dropdownContentTop = $dropdownContent.prop('offsetTop'); - dropdownContentBottom = dropdownContentTop + dropdownContentHeight; - // Get the offset bottom of the list item - listItemHeight = $listItem.outerHeight(); - listItemTop = $listItem.prop('offsetTop'); - listItemBottom = listItemTop + listItemHeight; - if (!index) { - // Scroll the dropdown content to the top - $dropdownContent.scrollTop(0); - } else if (index === ($listItems.length - 1)) { - // Scroll the dropdown content to the bottom - $dropdownContent.scrollTop($dropdownContent.prop('scrollHeight')); - } else if (listItemBottom > (dropdownContentBottom + dropdownScrollTop)) { - // Scroll the dropdown content down - $dropdownContent.scrollTop(listItemBottom - dropdownContentBottom + CURSOR_SELECT_SCROLL_PADDING); - } else if (listItemTop < (dropdownContentTop + dropdownScrollTop)) { - // Scroll the dropdown content up - return $dropdownContent.scrollTop(listItemTop - dropdownContentTop - CURSOR_SELECT_SCROLL_PADDING); - } - }; - - GitLabDropdown.prototype.updateLabel = function(selected, el, instance) { - if (selected == null) { - selected = null; - } - if (el == null) { - el = null; - } - if (instance == null) { - instance = null; - } - return $(this.el).find(".dropdown-toggle-text").text(this.options.toggleLabel(selected, el, instance)); - }; - - GitLabDropdown.prototype.clearField = function(field, isInput) { - return isInput ? field.val('') : field.remove(); - }; - - return GitLabDropdown; - })(); - - $.fn.glDropdown = function(opts) { - return this.each(function() { - if (!$.data(this, 'glDropdown')) { - return $.data(this, 'glDropdown', new GitLabDropdown(this, opts)); - } - }); + return [selectedObject, isMarking]; }; -}).call(window); + + GitLabDropdown.prototype.focusTextInput = function() { + if (this.options.filterable) { this.filterInput.focus(); } + }; + + GitLabDropdown.prototype.addInput = function(fieldName, value, selectedObject) { + var $input; + // Create hidden input for form + $input = $('').attr('type', 'hidden').attr('name', fieldName).val(value); + if (this.options.inputId != null) { + $input.attr('id', this.options.inputId); + } + return this.dropdown.before($input); + }; + + GitLabDropdown.prototype.selectRowAtIndex = function(index) { + var $el, selector; + // If we pass an option index + if (typeof index !== "undefined") { + selector = SELECTABLE_CLASSES + ":eq(" + index + ") a"; + } else { + selector = ".dropdown-content .is-focused"; + } + if (this.dropdown.find(".dropdown-toggle-page").length) { + selector = ".dropdown-page-one " + selector; + } + // simulate a click on the first link + $el = $(selector, this.dropdown); + if ($el.length) { + var href = $el.attr('href'); + if (href && href !== '#') { + gl.utils.visitUrl(href); + } else { + $el.first().trigger('click'); + } + } + }; + + GitLabDropdown.prototype.addArrowKeyEvent = function() { + var $input, ARROW_KEY_CODES, selector; + ARROW_KEY_CODES = [38, 40]; + $input = this.dropdown.find(".dropdown-input-field"); + selector = SELECTABLE_CLASSES; + if (this.dropdown.find(".dropdown-toggle-page").length) { + selector = ".dropdown-page-one " + selector; + } + return $('body').on('keydown', (function(_this) { + return function(e) { + var $listItems, PREV_INDEX, currentKeyCode; + currentKeyCode = e.which; + if (ARROW_KEY_CODES.indexOf(currentKeyCode) !== -1) { + e.preventDefault(); + e.stopImmediatePropagation(); + PREV_INDEX = currentIndex; + $listItems = $(selector, _this.dropdown); + // if @options.filterable + // $input.blur() + if (currentKeyCode === 40) { + // Move down + if (currentIndex < ($listItems.length - 1)) { + currentIndex += 1; + } + } else if (currentKeyCode === 38) { + // Move up + if (currentIndex > 0) { + currentIndex -= 1; + } + } + if (currentIndex !== PREV_INDEX) { + _this.highlightRowAtIndex($listItems, currentIndex); + } + return false; + } + if (currentKeyCode === 13 && currentIndex !== -1) { + e.preventDefault(); + _this.selectRowAtIndex(); + } + }; + })(this)); + }; + + GitLabDropdown.prototype.removeArrayKeyEvent = function() { + return $('body').off('keydown'); + }; + + GitLabDropdown.prototype.resetRows = function resetRows() { + currentIndex = -1; + $('.is-focused', this.dropdown).removeClass('is-focused'); + }; + + GitLabDropdown.prototype.highlightRowAtIndex = function($listItems, index) { + 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'); + // Update the class for the row at the specific index + $listItem = $listItems.eq(index); + $listItem.find('a:first-child').addClass("is-focused"); + // Dropdown content scroll area + $dropdownContent = $listItem.closest('.dropdown-content'); + dropdownScrollTop = $dropdownContent.scrollTop(); + dropdownContentHeight = $dropdownContent.outerHeight(); + dropdownContentTop = $dropdownContent.prop('offsetTop'); + dropdownContentBottom = dropdownContentTop + dropdownContentHeight; + // Get the offset bottom of the list item + listItemHeight = $listItem.outerHeight(); + listItemTop = $listItem.prop('offsetTop'); + listItemBottom = listItemTop + listItemHeight; + if (!index) { + // Scroll the dropdown content to the top + $dropdownContent.scrollTop(0); + } else if (index === ($listItems.length - 1)) { + // Scroll the dropdown content to the bottom + $dropdownContent.scrollTop($dropdownContent.prop('scrollHeight')); + } else if (listItemBottom > (dropdownContentBottom + dropdownScrollTop)) { + // Scroll the dropdown content down + $dropdownContent.scrollTop(listItemBottom - dropdownContentBottom + CURSOR_SELECT_SCROLL_PADDING); + } else if (listItemTop < (dropdownContentTop + dropdownScrollTop)) { + // Scroll the dropdown content up + return $dropdownContent.scrollTop(listItemTop - dropdownContentTop - CURSOR_SELECT_SCROLL_PADDING); + } + }; + + GitLabDropdown.prototype.updateLabel = function(selected, el, instance) { + if (selected == null) { + selected = null; + } + if (el == null) { + el = null; + } + if (instance == null) { + instance = null; + } + return $(this.el).find(".dropdown-toggle-text").text(this.options.toggleLabel(selected, el, instance)); + }; + + GitLabDropdown.prototype.clearField = function(field, isInput) { + return isInput ? field.val('') : field.remove(); + }; + + return GitLabDropdown; +})(); + +$.fn.glDropdown = function(opts) { + return this.each(function() { + if (!$.data(this, 'glDropdown')) { + return $.data(this, 'glDropdown', new GitLabDropdown(this, opts)); + } + }); +}; diff --git a/app/assets/javascripts/gl_field_error.js b/app/assets/javascripts/gl_field_error.js new file mode 100644 index 00000000000..76de249ac3b --- /dev/null +++ b/app/assets/javascripts/gl_field_error.js @@ -0,0 +1,162 @@ +/** + * This class overrides the browser's validation error bubbles, displaying custom + * error messages for invalid fields instead. To begin validating any form, add the + * class `gl-show-field-errors` to the form element, and ensure error messages are + * declared in each inputs' `title` attribute. If no title is declared for an invalid + * field the user attempts to submit, "This field is required." will be shown by default. + * + * Opt not to validate certain fields by adding the class `gl-field-error-ignore` to the input. + * + * Set a custom error anchor for error message to be injected after with the + * class `gl-field-error-anchor` + * + * Examples: + * + * Basic: + * + *
    + * + *
    + * + * Ignore specific inputs (e.g. UsernameValidator): + * + *
    + *
    + * + *
    + *
    + * + * Custom Error Anchor (allows error message to be injected after specified element): + * + *
    + *
    + * + * // Error message typically injected here + *
    + * // Error message now injected here + *
    + * + */ + +/** + * Regex Patterns in use: + * + * Only alphanumeric: : "[a-zA-Z0-9]+" + * No special characters : "[a-zA-Z0-9-_]+", + * + */ + +const errorMessageClass = 'gl-field-error'; +const inputErrorClass = 'gl-field-error-outline'; +const errorAnchorSelector = '.gl-field-error-anchor'; +const ignoreInputSelector = '.gl-field-error-ignore'; + +class GlFieldError { + constructor({ input, formErrors }) { + this.inputElement = $(input); + this.inputDomElement = this.inputElement.get(0); + this.form = formErrors; + this.errorMessage = this.inputElement.attr('title') || 'This field is required.'; + this.fieldErrorElement = $(`

    ${this.errorMessage}

    `); + + this.state = { + valid: false, + empty: true, + }; + + this.initFieldValidation(); + } + + initFieldValidation() { + const customErrorAnchor = this.inputElement.parents(errorAnchorSelector); + const errorAnchor = customErrorAnchor.length ? customErrorAnchor : this.inputElement; + + // hidden when injected into DOM + errorAnchor.after(this.fieldErrorElement); + this.inputElement.off('invalid').on('invalid', this.handleInvalidSubmit.bind(this)); + this.scopedSiblings = this.safelySelectSiblings(); + } + + safelySelectSiblings() { + // Apply `ignoreSelector` in markup to siblings whose visibility should not be toggled + const unignoredSiblings = this.inputElement.siblings(`p:not(${ignoreInputSelector})`); + const parentContainer = this.inputElement.parent('.form-group'); + + // Only select siblings when they're scoped within a form-group with one input + const safelyScoped = parentContainer.length && parentContainer.find('input').length === 1; + + return safelyScoped ? unignoredSiblings : this.fieldErrorElement; + } + + renderValidity() { + this.renderClear(); + + if (this.state.valid) { + this.renderValid(); + } else if (this.state.empty) { + this.renderEmpty(); + } else if (!this.state.valid) { + this.renderInvalid(); + } + } + + handleInvalidSubmit(event) { + event.preventDefault(); + const currentValue = this.accessCurrentValue(); + this.state.valid = false; + this.state.empty = currentValue === ''; + + this.renderValidity(); + this.form.focusOnFirstInvalid.apply(this.form); + // For UX, wait til after first invalid submission to check each keyup + this.inputElement.off('keyup.fieldValidator') + .on('keyup.fieldValidator', this.updateValidity.bind(this)); + } + + /* Get or set current input value */ + accessCurrentValue(newVal) { + return newVal ? this.inputElement.val(newVal) : this.inputElement.val(); + } + + getInputValidity() { + return this.inputDomElement.validity.valid; + } + + updateValidity() { + const inputVal = this.accessCurrentValue(); + this.state.empty = !inputVal.length; + this.state.valid = this.getInputValidity(); + this.renderValidity(); + } + + renderValid() { + return this.renderClear(); + } + + renderEmpty() { + return this.renderInvalid(); + } + + renderInvalid() { + this.inputElement.addClass(inputErrorClass); + this.scopedSiblings.hide(); + return this.fieldErrorElement.show(); + } + + renderClear() { + const inputVal = this.accessCurrentValue(); + if (!inputVal.split(' ').length) { + const trimmedInput = inputVal.trim(); + this.accessCurrentValue(trimmedInput); + } + this.inputElement.removeClass(inputErrorClass); + this.scopedSiblings.hide(); + this.fieldErrorElement.hide(); + } +} + +window.gl = window.gl || {}; +window.gl.GlFieldError = GlFieldError; diff --git a/app/assets/javascripts/gl_field_error.js.es6 b/app/assets/javascripts/gl_field_error.js.es6 deleted file mode 100644 index f7cbecc0385..00000000000 --- a/app/assets/javascripts/gl_field_error.js.es6 +++ /dev/null @@ -1,164 +0,0 @@ -/* eslint-disable no-param-reassign */ -((global) => { - /* - * This class overrides the browser's validation error bubbles, displaying custom - * error messages for invalid fields instead. To begin validating any form, add the - * class `gl-show-field-errors` to the form element, and ensure error messages are - * declared in each inputs' `title` attribute. If no title is declared for an invalid - * field the user attempts to submit, "This field is required." will be shown by default. - * - * Opt not to validate certain fields by adding the class `gl-field-error-ignore` to the input. - * - * Set a custom error anchor for error message to be injected after with the - * class `gl-field-error-anchor` - * - * Examples: - * - * Basic: - * - *
    - * - *
    - * - * Ignore specific inputs (e.g. UsernameValidator): - * - *
    - *
    - * - *
    - *
    - * - * Custom Error Anchor (allows error message to be injected after specified element): - * - *
    - *
    - * - * // Error message typically injected here - *
    - * // Error message now injected here - *
    - * - * */ - - /* - * Regex Patterns in use: - * - * Only alphanumeric: : "[a-zA-Z0-9]+" - * No special characters : "[a-zA-Z0-9-_]+", - * - * */ - - const errorMessageClass = 'gl-field-error'; - const inputErrorClass = 'gl-field-error-outline'; - const errorAnchorSelector = '.gl-field-error-anchor'; - const ignoreInputSelector = '.gl-field-error-ignore'; - - class GlFieldError { - constructor({ input, formErrors }) { - this.inputElement = $(input); - this.inputDomElement = this.inputElement.get(0); - this.form = formErrors; - this.errorMessage = this.inputElement.attr('title') || 'This field is required.'; - this.fieldErrorElement = $(`

    ${this.errorMessage}

    `); - - this.state = { - valid: false, - empty: true, - }; - - this.initFieldValidation(); - } - - initFieldValidation() { - const customErrorAnchor = this.inputElement.parents(errorAnchorSelector); - const errorAnchor = customErrorAnchor.length ? customErrorAnchor : this.inputElement; - - // hidden when injected into DOM - errorAnchor.after(this.fieldErrorElement); - this.inputElement.off('invalid').on('invalid', this.handleInvalidSubmit.bind(this)); - this.scopedSiblings = this.safelySelectSiblings(); - } - - safelySelectSiblings() { - // Apply `ignoreSelector` in markup to siblings whose visibility should not be toggled - const unignoredSiblings = this.inputElement.siblings(`p:not(${ignoreInputSelector})`); - const parentContainer = this.inputElement.parent('.form-group'); - - // Only select siblings when they're scoped within a form-group with one input - const safelyScoped = parentContainer.length && parentContainer.find('input').length === 1; - - return safelyScoped ? unignoredSiblings : this.fieldErrorElement; - } - - renderValidity() { - this.renderClear(); - - if (this.state.valid) { - this.renderValid(); - } else if (this.state.empty) { - this.renderEmpty(); - } else if (!this.state.valid) { - this.renderInvalid(); - } - } - - handleInvalidSubmit(event) { - event.preventDefault(); - const currentValue = this.accessCurrentValue(); - this.state.valid = false; - this.state.empty = currentValue === ''; - - this.renderValidity(); - this.form.focusOnFirstInvalid.apply(this.form); - // For UX, wait til after first invalid submission to check each keyup - this.inputElement.off('keyup.fieldValidator') - .on('keyup.fieldValidator', this.updateValidity.bind(this)); - } - - /* Get or set current input value */ - accessCurrentValue(newVal) { - return newVal ? this.inputElement.val(newVal) : this.inputElement.val(); - } - - getInputValidity() { - return this.inputDomElement.validity.valid; - } - - updateValidity() { - const inputVal = this.accessCurrentValue(); - this.state.empty = !inputVal.length; - this.state.valid = this.getInputValidity(); - this.renderValidity(); - } - - renderValid() { - return this.renderClear(); - } - - renderEmpty() { - return this.renderInvalid(); - } - - renderInvalid() { - this.inputElement.addClass(inputErrorClass); - this.scopedSiblings.hide(); - return this.fieldErrorElement.show(); - } - - renderClear() { - const inputVal = this.accessCurrentValue(); - if (!inputVal.split(' ').length) { - const trimmedInput = inputVal.trim(); - this.accessCurrentValue(trimmedInput); - } - this.inputElement.removeClass(inputErrorClass); - this.scopedSiblings.hide(); - this.fieldErrorElement.hide(); - } - } - - global.GlFieldError = GlFieldError; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/gl_field_errors.js b/app/assets/javascripts/gl_field_errors.js new file mode 100644 index 00000000000..636258ec555 --- /dev/null +++ b/app/assets/javascripts/gl_field_errors.js @@ -0,0 +1,47 @@ +/* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign */ + +require('./gl_field_error'); + +const customValidationFlag = 'gl-field-error-ignore'; + +class GlFieldErrors { + constructor(form) { + this.form = $(form); + this.state = { + inputs: [], + valid: false + }; + this.initValidators(); + } + + initValidators () { + // register selectors here as needed + const validateSelectors = [':text', ':password', '[type=email]'] + .map((selector) => `input${selector}`).join(','); + + this.state.inputs = this.form.find(validateSelectors).toArray() + .filter((input) => !input.classList.contains(customValidationFlag)) + .map((input) => new window.gl.GlFieldError({ input, formErrors: this })); + + this.form.on('submit', this.catchInvalidFormSubmit); + } + + /* Neccessary to prevent intercept and override invalid form submit + * because Safari & iOS quietly allow form submission when form is invalid + * and prevents disabling of invalid submit button by application.js */ + + catchInvalidFormSubmit (event) { + if (!event.currentTarget.checkValidity()) { + event.preventDefault(); + event.stopPropagation(); + } + } + + focusOnFirstInvalid () { + const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0]; + firstInvalid.inputElement.focus(); + } +} + +window.gl = window.gl || {}; +window.gl.GlFieldErrors = GlFieldErrors; diff --git a/app/assets/javascripts/gl_field_errors.js.es6 b/app/assets/javascripts/gl_field_errors.js.es6 deleted file mode 100644 index e9add115429..00000000000 --- a/app/assets/javascripts/gl_field_errors.js.es6 +++ /dev/null @@ -1,48 +0,0 @@ -/* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign */ - -require('./gl_field_error'); - -((global) => { - const customValidationFlag = 'gl-field-error-ignore'; - - class GlFieldErrors { - constructor(form) { - this.form = $(form); - this.state = { - inputs: [], - valid: false - }; - this.initValidators(); - } - - initValidators () { - // register selectors here as needed - const validateSelectors = [':text', ':password', '[type=email]'] - .map((selector) => `input${selector}`).join(','); - - this.state.inputs = this.form.find(validateSelectors).toArray() - .filter((input) => !input.classList.contains(customValidationFlag)) - .map((input) => new global.GlFieldError({ input, formErrors: this })); - - this.form.on('submit', this.catchInvalidFormSubmit); - } - - /* Neccessary to prevent intercept and override invalid form submit - * because Safari & iOS quietly allow form submission when form is invalid - * and prevents disabling of invalid submit button by application.js */ - - catchInvalidFormSubmit (event) { - if (!event.currentTarget.checkValidity()) { - event.preventDefault(); - event.stopPropagation(); - } - } - - focusOnFirstInvalid () { - const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0]; - firstInvalid.inputElement.focus(); - } - } - - global.GlFieldErrors = GlFieldErrors; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js new file mode 100644 index 00000000000..e7c98e16581 --- /dev/null +++ b/app/assets/javascripts/gl_form.js @@ -0,0 +1,90 @@ +/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-new, max-len */ +/* global GitLab */ +/* global DropzoneInput */ +/* global autosize */ + +window.gl = window.gl || {}; + +function GLForm(form) { + this.form = form; + this.textarea = this.form.find('textarea.js-gfm-input'); + // Before we start, we should clean up any previous data for this form + this.destroy(); + // Setup the form + this.setupForm(); + this.form.data('gl-form', this); +} + +GLForm.prototype.destroy = function() { + // Clean form listeners + this.clearEventListeners(); + return this.form.data('gl-form', null); +}; + +GLForm.prototype.setupForm = function() { + var isNewForm; + isNewForm = this.form.is(':not(.gfm-form)'); + this.form.removeClass('js-new-note-form'); + if (isNewForm) { + this.form.find('.div-dropzone').remove(); + this.form.addClass('gfm-form'); + // remove notify commit author checkbox for non-commit notes + gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button')); + gl.GfmAutoComplete.setup(this.form.find('.js-gfm-input')); + new DropzoneInput(this.form); + autosize(this.textarea); + // form and textarea event listeners + this.addEventListeners(); + } + gl.text.init(this.form); + // hide discard button + this.form.find('.js-note-discard').hide(); + this.form.show(); + if (this.isAutosizeable) this.setupAutosize(); +}; + +GLForm.prototype.setupAutosize = function () { + this.textarea.off('autosize:resized') + .on('autosize:resized', this.setHeightData.bind(this)); + + this.textarea.off('mouseup.autosize') + .on('mouseup.autosize', this.destroyAutosize.bind(this)); + + setTimeout(() => { + autosize(this.textarea); + this.textarea.css('resize', 'vertical'); + }, 0); +}; + +GLForm.prototype.setHeightData = function () { + this.textarea.data('height', this.textarea.outerHeight()); +}; + +GLForm.prototype.destroyAutosize = function () { + const outerHeight = this.textarea.outerHeight(); + + if (this.textarea.data('height') === outerHeight) return; + + autosize.destroy(this.textarea); + + this.textarea.data('height', outerHeight); + this.textarea.outerHeight(outerHeight); + this.textarea.css('max-height', window.outerHeight); +}; + +GLForm.prototype.clearEventListeners = function() { + this.textarea.off('focus'); + this.textarea.off('blur'); + return gl.text.removeListeners(this.form); +}; + +GLForm.prototype.addEventListeners = function() { + this.textarea.on('focus', function() { + return $(this).closest('.md-area').addClass('is-focused'); + }); + return this.textarea.on('blur', function() { + return $(this).closest('.md-area').removeClass('is-focused'); + }); +}; + +window.gl.GLForm = GLForm; diff --git a/app/assets/javascripts/gl_form.js.es6 b/app/assets/javascripts/gl_form.js.es6 deleted file mode 100644 index 0b446ff364a..00000000000 --- a/app/assets/javascripts/gl_form.js.es6 +++ /dev/null @@ -1,92 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-new, max-len */ -/* global GitLab */ -/* global DropzoneInput */ -/* global autosize */ - -(() => { - const global = window.gl || (window.gl = {}); - - function GLForm(form) { - this.form = form; - this.textarea = this.form.find('textarea.js-gfm-input'); - // Before we start, we should clean up any previous data for this form - this.destroy(); - // Setup the form - this.setupForm(); - this.form.data('gl-form', this); - } - - GLForm.prototype.destroy = function() { - // Clean form listeners - this.clearEventListeners(); - return this.form.data('gl-form', null); - }; - - GLForm.prototype.setupForm = function() { - var isNewForm; - isNewForm = this.form.is(':not(.gfm-form)'); - this.form.removeClass('js-new-note-form'); - if (isNewForm) { - this.form.find('.div-dropzone').remove(); - this.form.addClass('gfm-form'); - // remove notify commit author checkbox for non-commit notes - gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button')); - gl.GfmAutoComplete.setup(this.form.find('.js-gfm-input')); - new DropzoneInput(this.form); - autosize(this.textarea); - // form and textarea event listeners - this.addEventListeners(); - } - gl.text.init(this.form); - // hide discard button - this.form.find('.js-note-discard').hide(); - this.form.show(); - if (this.isAutosizeable) this.setupAutosize(); - }; - - GLForm.prototype.setupAutosize = function () { - this.textarea.off('autosize:resized') - .on('autosize:resized', this.setHeightData.bind(this)); - - this.textarea.off('mouseup.autosize') - .on('mouseup.autosize', this.destroyAutosize.bind(this)); - - setTimeout(() => { - autosize(this.textarea); - this.textarea.css('resize', 'vertical'); - }, 0); - }; - - GLForm.prototype.setHeightData = function () { - this.textarea.data('height', this.textarea.outerHeight()); - }; - - GLForm.prototype.destroyAutosize = function () { - const outerHeight = this.textarea.outerHeight(); - - if (this.textarea.data('height') === outerHeight) return; - - autosize.destroy(this.textarea); - - this.textarea.data('height', outerHeight); - this.textarea.outerHeight(outerHeight); - this.textarea.css('max-height', window.outerHeight); - }; - - GLForm.prototype.clearEventListeners = function() { - this.textarea.off('focus'); - this.textarea.off('blur'); - return gl.text.removeListeners(this.form); - }; - - GLForm.prototype.addEventListeners = function() { - this.textarea.on('focus', function() { - return $(this).closest('.md-area').addClass('is-focused'); - }); - return this.textarea.on('blur', function() { - return $(this).closest('.md-area').removeClass('is-focused'); - }); - }; - - global.GLForm = GLForm; -})(); diff --git a/app/assets/javascripts/graphs/graphs_bundle.js b/app/assets/javascripts/graphs/graphs_bundle.js index 4f7777aa5bc..a433c7ba8f0 100644 --- a/app/assets/javascripts/graphs/graphs_bundle.js +++ b/app/assets/javascripts/graphs/graphs_bundle.js @@ -1,3 +1,6 @@ -// require everything else in this directory -function requireAll(context) { return context.keys().map(context); } -requireAll(require.context('.', false, /^\.\/(?!graphs_bundle).*\.(js|es6)$/)); +import Chart from 'vendor/Chart'; +import ContributorsStatGraph from './stat_graph_contributors'; + +// export to global scope +window.Chart = Chart; +window.ContributorsStatGraph = ContributorsStatGraph; diff --git a/app/assets/javascripts/graphs/stat_graph.js b/app/assets/javascripts/graphs/stat_graph.js deleted file mode 100644 index 75a53aae33c..00000000000 --- a/app/assets/javascripts/graphs/stat_graph.js +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-return-assign, max-len */ -(function() { - this.StatGraph = (function() { - function StatGraph() {} - - StatGraph.log = {}; - - StatGraph.get_log = function() { - return this.log; - }; - - StatGraph.set_log = function(data) { - return this.log = data; - }; - - return StatGraph; - })(); -}).call(window); diff --git a/app/assets/javascripts/graphs/stat_graph_contributors.js b/app/assets/javascripts/graphs/stat_graph_contributors.js index bbfb467ad50..c6be4c9e8fe 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors.js @@ -1,116 +1,111 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign */ -/* global ContributorsGraph */ -/* global ContributorsAuthorGraph */ -/* global ContributorsMasterGraph */ -/* global ContributorsStatGraphUtil */ -/* global d3 */ +/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign, no-shadow */ -window.d3 = require('d3'); +import d3 from 'd3'; +import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph'; +import ContributorsStatGraphUtil from './stat_graph_contributors_util'; -(function() { - this.ContributorsStatGraph = (function() { - function ContributorsStatGraph() {} +export default (function() { + function ContributorsStatGraph() {} - ContributorsStatGraph.prototype.init = function(log) { - var author_commits, total_commits; - this.parsed_log = ContributorsStatGraphUtil.parse_log(log); - this.set_current_field("commits"); - total_commits = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field); - author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field); - this.add_master_graph(total_commits); - this.add_authors_graph(author_commits); - return this.change_date_header(); - }; + ContributorsStatGraph.prototype.init = function(log) { + var author_commits, total_commits; + this.parsed_log = ContributorsStatGraphUtil.parse_log(log); + this.set_current_field("commits"); + total_commits = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field); + author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field); + this.add_master_graph(total_commits); + this.add_authors_graph(author_commits); + return this.change_date_header(); + }; - ContributorsStatGraph.prototype.add_master_graph = function(total_data) { - this.master_graph = new ContributorsMasterGraph(total_data); - return this.master_graph.draw(); - }; + ContributorsStatGraph.prototype.add_master_graph = function(total_data) { + this.master_graph = new ContributorsMasterGraph(total_data); + return this.master_graph.draw(); + }; - ContributorsStatGraph.prototype.add_authors_graph = function(author_data) { - var limited_author_data; - this.authors = []; - limited_author_data = author_data.slice(0, 100); - return _.each(limited_author_data, (function(_this) { - return function(d) { - var author_graph, author_header; - author_header = _this.create_author_header(d); - $(".contributors-list").append(author_header); - _this.authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates); - return author_graph.draw(); - }; - })(this)); - }; + ContributorsStatGraph.prototype.add_authors_graph = function(author_data) { + var limited_author_data; + this.authors = []; + limited_author_data = author_data.slice(0, 100); + return _.each(limited_author_data, (function(_this) { + return function(d) { + var author_graph, author_header; + author_header = _this.create_author_header(d); + $(".contributors-list").append(author_header); + _this.authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates); + return author_graph.draw(); + }; + })(this)); + }; - ContributorsStatGraph.prototype.format_author_commit_info = function(author) { - var commits; - commits = $('', { - "class": 'graph-author-commits-count' - }); - commits.text(author.commits + " commits"); - return $('').append(commits); - }; + ContributorsStatGraph.prototype.format_author_commit_info = function(author) { + var commits; + commits = $('', { + "class": 'graph-author-commits-count' + }); + commits.text(author.commits + " commits"); + return $('').append(commits); + }; - ContributorsStatGraph.prototype.create_author_header = function(author) { - var author_commit_info, author_commit_info_span, author_email, author_name, list_item; - list_item = $('
  • ', { - "class": 'person', - style: 'display: block;' - }); - author_name = $('

    ' + author.author_name + '

    '); - author_email = $('

    ' + author.author_email + '

    '); - author_commit_info_span = $('', { - "class": 'commits' - }); - author_commit_info = this.format_author_commit_info(author); - author_commit_info_span.html(author_commit_info); - list_item.append(author_name); - list_item.append(author_email); - list_item.append(author_commit_info_span); - return list_item; - }; + ContributorsStatGraph.prototype.create_author_header = function(author) { + var author_commit_info, author_commit_info_span, author_email, author_name, list_item; + list_item = $('
  • ', { + "class": 'person', + style: 'display: block;' + }); + author_name = $('

    ' + author.author_name + '

    '); + author_email = $('

    ' + author.author_email + '

    '); + author_commit_info_span = $('', { + "class": 'commits' + }); + author_commit_info = this.format_author_commit_info(author); + author_commit_info_span.html(author_commit_info); + list_item.append(author_name); + list_item.append(author_email); + list_item.append(author_commit_info_span); + return list_item; + }; - ContributorsStatGraph.prototype.redraw_master = function() { - var total_data; - total_data = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field); - this.master_graph.set_data(total_data); - return this.master_graph.redraw(); - }; + ContributorsStatGraph.prototype.redraw_master = function() { + var total_data; + total_data = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field); + this.master_graph.set_data(total_data); + return this.master_graph.redraw(); + }; - ContributorsStatGraph.prototype.redraw_authors = function() { - var author_commits, x_domain; - $("ol").html(""); - x_domain = ContributorsGraph.prototype.x_domain; - author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field, x_domain); - return _.each(author_commits, (function(_this) { - return function(d) { - _this.redraw_author_commit_info(d); - $(_this.authors[d.author_name].list_item).appendTo("ol"); - _this.authors[d.author_name].set_data(d.dates); - return _this.authors[d.author_name].redraw(); - }; - })(this)); - }; + ContributorsStatGraph.prototype.redraw_authors = function() { + var author_commits, x_domain; + $("ol").html(""); + x_domain = ContributorsGraph.prototype.x_domain; + author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field, x_domain); + return _.each(author_commits, (function(_this) { + return function(d) { + _this.redraw_author_commit_info(d); + $(_this.authors[d.author_name].list_item).appendTo("ol"); + _this.authors[d.author_name].set_data(d.dates); + return _this.authors[d.author_name].redraw(); + }; + })(this)); + }; - ContributorsStatGraph.prototype.set_current_field = function(field) { - return this.field = field; - }; + ContributorsStatGraph.prototype.set_current_field = function(field) { + return this.field = field; + }; - ContributorsStatGraph.prototype.change_date_header = function() { - var print, print_date_format, x_domain; - x_domain = ContributorsGraph.prototype.x_domain; - print_date_format = d3.time.format("%B %e %Y"); - print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]); - return $("#date_header").text(print); - }; + ContributorsStatGraph.prototype.change_date_header = function() { + var print, print_date_format, x_domain; + x_domain = ContributorsGraph.prototype.x_domain; + print_date_format = d3.time.format("%B %e %Y"); + print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1]); + return $("#date_header").text(print); + }; - ContributorsStatGraph.prototype.redraw_author_commit_info = function(author) { - var author_commit_info, author_list_item; - author_list_item = $(this.authors[author.author_name].list_item); - author_commit_info = this.format_author_commit_info(author); - return author_list_item.find("span").html(author_commit_info); - }; + ContributorsStatGraph.prototype.redraw_author_commit_info = function(author) { + var author_commit_info, author_list_item; + author_list_item = $(this.authors[author.author_name].list_item); + author_commit_info = this.format_author_commit_info(author); + return author_list_item.find("span").html(author_commit_info); + }; - return ContributorsStatGraph; - })(); -}).call(window); + return ContributorsStatGraph; +})(); diff --git a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js index 228771da4ee..521bc77db66 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js @@ -1,276 +1,272 @@ -/* eslint-disable func-names, space-before-function-paren, one-var, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return */ -/* global d3 */ -/* global ContributorsGraph */ +/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, newline-per-chained-call, no-else-return, no-shadow */ -window.d3 = require('d3'); +import d3 from 'd3'; -(function() { - var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }, - extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; +const bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; +const extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; +const hasProp = {}.hasOwnProperty; - this.ContributorsGraph = (function() { - function ContributorsGraph() {} +export const ContributorsGraph = (function() { + function ContributorsGraph() {} - ContributorsGraph.prototype.MARGIN = { - top: 20, - right: 20, - bottom: 30, - left: 50 - }; + ContributorsGraph.prototype.MARGIN = { + top: 20, + right: 20, + bottom: 30, + left: 50 + }; - ContributorsGraph.prototype.x_domain = null; + ContributorsGraph.prototype.x_domain = null; - ContributorsGraph.prototype.y_domain = null; + ContributorsGraph.prototype.y_domain = null; - ContributorsGraph.prototype.dates = []; + ContributorsGraph.prototype.dates = []; - ContributorsGraph.set_x_domain = function(data) { - return ContributorsGraph.prototype.x_domain = data; - }; + ContributorsGraph.set_x_domain = function(data) { + return ContributorsGraph.prototype.x_domain = data; + }; - ContributorsGraph.set_y_domain = function(data) { - return ContributorsGraph.prototype.y_domain = [ - 0, d3.max(data, function(d) { - return d.commits = d.commits || d.additions || d.deletions; - }) - ]; - }; + ContributorsGraph.set_y_domain = function(data) { + return ContributorsGraph.prototype.y_domain = [ + 0, d3.max(data, function(d) { + return d.commits = d.commits || d.additions || d.deletions; + }) + ]; + }; - ContributorsGraph.init_x_domain = function(data) { - return ContributorsGraph.prototype.x_domain = d3.extent(data, function(d) { - return d.date; - }); - }; + ContributorsGraph.init_x_domain = function(data) { + return ContributorsGraph.prototype.x_domain = d3.extent(data, function(d) { + return d.date; + }); + }; - ContributorsGraph.init_y_domain = function(data) { - return ContributorsGraph.prototype.y_domain = [ - 0, d3.max(data, function(d) { - return d.commits = d.commits || d.additions || d.deletions; - }) - ]; - }; + ContributorsGraph.init_y_domain = function(data) { + return ContributorsGraph.prototype.y_domain = [ + 0, d3.max(data, function(d) { + return d.commits = d.commits || d.additions || d.deletions; + }) + ]; + }; - ContributorsGraph.init_domain = function(data) { - ContributorsGraph.init_x_domain(data); - return ContributorsGraph.init_y_domain(data); - }; + ContributorsGraph.init_domain = function(data) { + ContributorsGraph.init_x_domain(data); + return ContributorsGraph.init_y_domain(data); + }; - ContributorsGraph.set_dates = function(data) { - return ContributorsGraph.prototype.dates = data; - }; + ContributorsGraph.set_dates = function(data) { + return ContributorsGraph.prototype.dates = data; + }; - ContributorsGraph.prototype.set_x_domain = function() { - return this.x.domain(this.x_domain); - }; + ContributorsGraph.prototype.set_x_domain = function() { + return this.x.domain(this.x_domain); + }; - ContributorsGraph.prototype.set_y_domain = function() { - return this.y.domain(this.y_domain); - }; + ContributorsGraph.prototype.set_y_domain = function() { + return this.y.domain(this.y_domain); + }; - ContributorsGraph.prototype.set_domain = function() { - this.set_x_domain(); - return this.set_y_domain(); - }; + ContributorsGraph.prototype.set_domain = function() { + this.set_x_domain(); + return this.set_y_domain(); + }; - ContributorsGraph.prototype.create_scale = function(width, height) { - this.x = d3.time.scale().range([0, width]).clamp(true); - return this.y = d3.scale.linear().range([height, 0]).nice(); - }; + ContributorsGraph.prototype.create_scale = function(width, height) { + this.x = d3.time.scale().range([0, width]).clamp(true); + return this.y = d3.scale.linear().range([height, 0]).nice(); + }; - ContributorsGraph.prototype.draw_x_axis = function() { - return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0, " + this.height + ")").call(this.x_axis); - }; + ContributorsGraph.prototype.draw_x_axis = function() { + return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0, " + this.height + ")").call(this.x_axis); + }; - ContributorsGraph.prototype.draw_y_axis = function() { - return this.svg.append("g").attr("class", "y axis").call(this.y_axis); - }; + ContributorsGraph.prototype.draw_y_axis = function() { + return this.svg.append("g").attr("class", "y axis").call(this.y_axis); + }; - ContributorsGraph.prototype.set_data = function(data) { - return this.data = data; - }; + ContributorsGraph.prototype.set_data = function(data) { + return this.data = data; + }; - return ContributorsGraph; - })(); + return ContributorsGraph; +})(); - this.ContributorsMasterGraph = (function(superClass) { - extend(ContributorsMasterGraph, superClass); +export const ContributorsMasterGraph = (function(superClass) { + extend(ContributorsMasterGraph, superClass); - function ContributorsMasterGraph(data1) { - this.data = data1; - this.update_content = bind(this.update_content, this); - this.width = $('.content').width() - 70; - this.height = 200; - this.x = null; - this.y = null; - this.x_axis = null; - this.y_axis = null; - this.area = null; - this.svg = null; - this.brush = null; - this.x_max_domain = null; + function ContributorsMasterGraph(data1) { + this.data = data1; + this.update_content = bind(this.update_content, this); + this.width = $('.content').width() - 70; + this.height = 200; + this.x = null; + this.y = null; + this.x_axis = null; + this.y_axis = null; + this.area = null; + this.svg = null; + this.brush = null; + this.x_max_domain = null; + } + + ContributorsMasterGraph.prototype.process_dates = function(data) { + var dates; + dates = this.get_dates(data); + this.parse_dates(data); + return ContributorsGraph.set_dates(dates); + }; + + ContributorsMasterGraph.prototype.get_dates = function(data) { + return _.pluck(data, 'date'); + }; + + ContributorsMasterGraph.prototype.parse_dates = function(data) { + var parseDate; + parseDate = d3.time.format("%Y-%m-%d").parse; + return data.forEach(function(d) { + return d.date = parseDate(d.date); + }); + }; + + ContributorsMasterGraph.prototype.create_scale = function() { + return ContributorsMasterGraph.__super__.create_scale.call(this, this.width, this.height); + }; + + ContributorsMasterGraph.prototype.create_axes = function() { + this.x_axis = d3.svg.axis().scale(this.x).orient("bottom"); + return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); + }; + + ContributorsMasterGraph.prototype.create_svg = function() { + return this.svg = d3.select("#contributors-master").append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "tint-box").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); + }; + + ContributorsMasterGraph.prototype.create_area = function(x, y) { + return this.area = d3.svg.area().x(function(d) { + return x(d.date); + }).y0(this.height).y1(function(d) { + d.commits = d.commits || d.additions || d.deletions; + return y(d.commits); + }).interpolate("basis"); + }; + + ContributorsMasterGraph.prototype.create_brush = function() { + return this.brush = d3.svg.brush().x(this.x).on("brushend", this.update_content); + }; + + ContributorsMasterGraph.prototype.draw_path = function(data) { + return this.svg.append("path").datum(data).attr("class", "area").attr("d", this.area); + }; + + ContributorsMasterGraph.prototype.add_brush = function() { + return this.svg.append("g").attr("class", "selection").call(this.brush).selectAll("rect").attr("height", this.height); + }; + + ContributorsMasterGraph.prototype.update_content = function() { + ContributorsGraph.set_x_domain(this.brush.empty() ? this.x_max_domain : this.brush.extent()); + return $("#brush_change").trigger('change'); + }; + + ContributorsMasterGraph.prototype.draw = function() { + this.process_dates(this.data); + this.create_scale(); + this.create_axes(); + ContributorsGraph.init_domain(this.data); + this.x_max_domain = this.x_domain; + this.set_domain(); + this.create_area(this.x, this.y); + this.create_svg(); + this.create_brush(); + this.draw_path(this.data); + this.draw_x_axis(); + this.draw_y_axis(); + return this.add_brush(); + }; + + ContributorsMasterGraph.prototype.redraw = function() { + this.process_dates(this.data); + ContributorsGraph.set_y_domain(this.data); + this.set_y_domain(); + this.svg.select("path").datum(this.data); + this.svg.select("path").attr("d", this.area); + return this.svg.select(".y.axis").call(this.y_axis); + }; + + return ContributorsMasterGraph; +})(ContributorsGraph); + +export const ContributorsAuthorGraph = (function(superClass) { + extend(ContributorsAuthorGraph, superClass); + + function ContributorsAuthorGraph(data1) { + this.data = data1; + // Don't split graph size in half for mobile devices. + if ($(window).width() < 768) { + this.width = $('.content').width() - 80; + } else { + this.width = ($('.content').width() / 2) - 100; } + this.height = 200; + this.x = null; + this.y = null; + this.x_axis = null; + this.y_axis = null; + this.area = null; + this.svg = null; + this.list_item = null; + } - ContributorsMasterGraph.prototype.process_dates = function(data) { - var dates; - dates = this.get_dates(data); - this.parse_dates(data); - return ContributorsGraph.set_dates(dates); - }; + ContributorsAuthorGraph.prototype.create_scale = function() { + return ContributorsAuthorGraph.__super__.create_scale.call(this, this.width, this.height); + }; - ContributorsMasterGraph.prototype.get_dates = function(data) { - return _.pluck(data, 'date'); - }; + ContributorsAuthorGraph.prototype.create_axes = function() { + this.x_axis = d3.svg.axis().scale(this.x).orient("bottom").ticks(8); + return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); + }; - ContributorsMasterGraph.prototype.parse_dates = function(data) { + ContributorsAuthorGraph.prototype.create_area = function(x, y) { + return this.area = d3.svg.area().x(function(d) { var parseDate; parseDate = d3.time.format("%Y-%m-%d").parse; - return data.forEach(function(d) { - return d.date = parseDate(d.date); - }); - }; + return x(parseDate(d)); + }).y0(this.height).y1((function(_this) { + return function(d) { + if (_this.data[d] != null) { + return y(_this.data[d]); + } else { + return y(0); + } + }; + })(this)).interpolate("basis"); + }; - ContributorsMasterGraph.prototype.create_scale = function() { - return ContributorsMasterGraph.__super__.create_scale.call(this, this.width, this.height); - }; + ContributorsAuthorGraph.prototype.create_svg = function() { + this.list_item = d3.selectAll(".person")[0].pop(); + return this.svg = d3.select(this.list_item).append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "spark").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); + }; - ContributorsMasterGraph.prototype.create_axes = function() { - this.x_axis = d3.svg.axis().scale(this.x).orient("bottom"); - return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); - }; + ContributorsAuthorGraph.prototype.draw_path = function(data) { + return this.svg.append("path").datum(data).attr("class", "area-contributor").attr("d", this.area); + }; - ContributorsMasterGraph.prototype.create_svg = function() { - return this.svg = d3.select("#contributors-master").append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "tint-box").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); - }; + ContributorsAuthorGraph.prototype.draw = function() { + this.create_scale(); + this.create_axes(); + this.set_domain(); + this.create_area(this.x, this.y); + this.create_svg(); + this.draw_path(this.dates); + this.draw_x_axis(); + return this.draw_y_axis(); + }; - ContributorsMasterGraph.prototype.create_area = function(x, y) { - return this.area = d3.svg.area().x(function(d) { - return x(d.date); - }).y0(this.height).y1(function(d) { - d.commits = d.commits || d.additions || d.deletions; - return y(d.commits); - }).interpolate("basis"); - }; + ContributorsAuthorGraph.prototype.redraw = function() { + this.set_domain(); + this.svg.select("path").datum(this.dates); + this.svg.select("path").attr("d", this.area); + this.svg.select(".x.axis").call(this.x_axis); + return this.svg.select(".y.axis").call(this.y_axis); + }; - ContributorsMasterGraph.prototype.create_brush = function() { - return this.brush = d3.svg.brush().x(this.x).on("brushend", this.update_content); - }; - - ContributorsMasterGraph.prototype.draw_path = function(data) { - return this.svg.append("path").datum(data).attr("class", "area").attr("d", this.area); - }; - - ContributorsMasterGraph.prototype.add_brush = function() { - return this.svg.append("g").attr("class", "selection").call(this.brush).selectAll("rect").attr("height", this.height); - }; - - ContributorsMasterGraph.prototype.update_content = function() { - ContributorsGraph.set_x_domain(this.brush.empty() ? this.x_max_domain : this.brush.extent()); - return $("#brush_change").trigger('change'); - }; - - ContributorsMasterGraph.prototype.draw = function() { - this.process_dates(this.data); - this.create_scale(); - this.create_axes(); - ContributorsGraph.init_domain(this.data); - this.x_max_domain = this.x_domain; - this.set_domain(); - this.create_area(this.x, this.y); - this.create_svg(); - this.create_brush(); - this.draw_path(this.data); - this.draw_x_axis(); - this.draw_y_axis(); - return this.add_brush(); - }; - - ContributorsMasterGraph.prototype.redraw = function() { - this.process_dates(this.data); - ContributorsGraph.set_y_domain(this.data); - this.set_y_domain(); - this.svg.select("path").datum(this.data); - this.svg.select("path").attr("d", this.area); - return this.svg.select(".y.axis").call(this.y_axis); - }; - - return ContributorsMasterGraph; - })(ContributorsGraph); - - this.ContributorsAuthorGraph = (function(superClass) { - extend(ContributorsAuthorGraph, superClass); - - function ContributorsAuthorGraph(data1) { - this.data = data1; - // Don't split graph size in half for mobile devices. - if ($(window).width() < 768) { - this.width = $('.content').width() - 80; - } else { - this.width = ($('.content').width() / 2) - 100; - } - this.height = 200; - this.x = null; - this.y = null; - this.x_axis = null; - this.y_axis = null; - this.area = null; - this.svg = null; - this.list_item = null; - } - - ContributorsAuthorGraph.prototype.create_scale = function() { - return ContributorsAuthorGraph.__super__.create_scale.call(this, this.width, this.height); - }; - - ContributorsAuthorGraph.prototype.create_axes = function() { - this.x_axis = d3.svg.axis().scale(this.x).orient("bottom").ticks(8); - return this.y_axis = d3.svg.axis().scale(this.y).orient("left").ticks(5); - }; - - ContributorsAuthorGraph.prototype.create_area = function(x, y) { - return this.area = d3.svg.area().x(function(d) { - var parseDate; - parseDate = d3.time.format("%Y-%m-%d").parse; - return x(parseDate(d)); - }).y0(this.height).y1((function(_this) { - return function(d) { - if (_this.data[d] != null) { - return y(_this.data[d]); - } else { - return y(0); - } - }; - })(this)).interpolate("basis"); - }; - - ContributorsAuthorGraph.prototype.create_svg = function() { - this.list_item = d3.selectAll(".person")[0].pop(); - return this.svg = d3.select(this.list_item).append("svg").attr("width", this.width + this.MARGIN.left + this.MARGIN.right).attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom).attr("class", "spark").append("g").attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")"); - }; - - ContributorsAuthorGraph.prototype.draw_path = function(data) { - return this.svg.append("path").datum(data).attr("class", "area-contributor").attr("d", this.area); - }; - - ContributorsAuthorGraph.prototype.draw = function() { - this.create_scale(); - this.create_axes(); - this.set_domain(); - this.create_area(this.x, this.y); - this.create_svg(); - this.draw_path(this.dates); - this.draw_x_axis(); - return this.draw_y_axis(); - }; - - ContributorsAuthorGraph.prototype.redraw = function() { - this.set_domain(); - this.svg.select("path").datum(this.dates); - this.svg.select("path").attr("d", this.area); - this.svg.select(".x.axis").call(this.x_axis); - return this.svg.select(".y.axis").call(this.y_axis); - }; - - return ContributorsAuthorGraph; - })(ContributorsGraph); -}).call(window); + return ContributorsAuthorGraph; +})(ContributorsGraph); diff --git a/app/assets/javascripts/graphs/stat_graph_contributors_util.js b/app/assets/javascripts/graphs/stat_graph_contributors_util.js index 7954c583598..c583757f3f2 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors_util.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors_util.js @@ -1,138 +1,137 @@ /* eslint-disable func-names, space-before-function-paren, object-shorthand, no-var, one-var, camelcase, one-var-declaration-per-line, comma-dangle, no-param-reassign, no-return-assign, quotes, prefer-arrow-callback, wrap-iife, consistent-return, no-unused-vars, max-len, no-cond-assign, no-else-return, max-len */ -(function() { - window.ContributorsStatGraphUtil = { - parse_log: function(log) { - var by_author, by_email, data, entry, i, len, total, normalized_email; - total = {}; - by_author = {}; - by_email = {}; - for (i = 0, len = log.length; i < len; i += 1) { - entry = log[i]; - if (total[entry.date] == null) { - this.add_date(entry.date, total); - } - normalized_email = entry.author_email.toLowerCase(); - data = by_author[entry.author_name] || by_email[normalized_email]; - if (data == null) { - data = this.add_author(entry, by_author, by_email); - } - if (!data[entry.date]) { - this.add_date(entry.date, data); - } - this.store_data(entry, total[entry.date], data[entry.date]); + +export default { + parse_log: function(log) { + var by_author, by_email, data, entry, i, len, total, normalized_email; + total = {}; + by_author = {}; + by_email = {}; + for (i = 0, len = log.length; i < len; i += 1) { + entry = log[i]; + if (total[entry.date] == null) { + this.add_date(entry.date, total); } - total = _.toArray(total); - by_author = _.toArray(by_author); - return { - total: total, - by_author: by_author - }; - }, - add_date: function(date, collection) { - collection[date] = {}; - return collection[date].date = date; - }, - add_author: function(author, by_author, by_email) { - var data, normalized_email; - data = {}; - data.author_name = author.author_name; - data.author_email = author.author_email; - normalized_email = author.author_email.toLowerCase(); - by_author[author.author_name] = data; - by_email[normalized_email] = data; - return data; - }, - store_data: function(entry, total, by_author) { - this.store_commits(total, by_author); - this.store_additions(entry, total, by_author); - return this.store_deletions(entry, total, by_author); - }, - store_commits: function(total, by_author) { - this.add(total, "commits", 1); - return this.add(by_author, "commits", 1); - }, - add: function(collection, field, value) { - if (collection[field] == null) { - collection[field] = 0; + normalized_email = entry.author_email.toLowerCase(); + data = by_author[entry.author_name] || by_email[normalized_email]; + if (data == null) { + data = this.add_author(entry, by_author, by_email); } - return collection[field] += value; - }, - store_additions: function(entry, total, by_author) { - if (entry.additions == null) { - entry.additions = 0; - } - this.add(total, "additions", entry.additions); - return this.add(by_author, "additions", entry.additions); - }, - store_deletions: function(entry, total, by_author) { - if (entry.deletions == null) { - entry.deletions = 0; - } - this.add(total, "deletions", entry.deletions); - return this.add(by_author, "deletions", entry.deletions); - }, - get_total_data: function(parsed_log, field) { - var log, total_data; - log = parsed_log.total; - total_data = this.pick_field(log, field); - return _.sortBy(total_data, function(d) { - return d.date; - }); - }, - pick_field: function(log, field) { - var total_data; - total_data = []; - _.each(log, function(d) { - return total_data.push(_.pick(d, [field, 'date'])); - }); - return total_data; - }, - get_author_data: function(parsed_log, field, date_range) { - var author_data, log; - if (date_range == null) { - date_range = null; - } - log = parsed_log.by_author; - author_data = []; - _.each(log, (function(_this) { - return function(log_entry) { - var parsed_log_entry; - parsed_log_entry = _this.parse_log_entry(log_entry, field, date_range); - if (!_.isEmpty(parsed_log_entry.dates)) { - return author_data.push(parsed_log_entry); - } - }; - })(this)); - return _.sortBy(author_data, function(d) { - return d[field]; - }).reverse(); - }, - parse_log_entry: function(log_entry, field, date_range) { - var parsed_entry; - parsed_entry = {}; - parsed_entry.author_name = log_entry.author_name; - parsed_entry.author_email = log_entry.author_email; - parsed_entry.dates = {}; - parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0; - _.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) { - return function(value, key) { - if (_this.in_range(value.date, date_range)) { - parsed_entry.dates[value.date] = value[field]; - parsed_entry.commits += value.commits; - parsed_entry.additions += value.additions; - return parsed_entry.deletions += value.deletions; - } - }; - })(this)); - return parsed_entry; - }, - in_range: function(date, date_range) { - var ref; - if (date_range === null || (date_range[0] <= (ref = new Date(date)) && ref <= date_range[1])) { - return true; - } else { - return false; + if (!data[entry.date]) { + this.add_date(entry.date, data); } + this.store_data(entry, total[entry.date], data[entry.date]); } - }; -}).call(window); + total = _.toArray(total); + by_author = _.toArray(by_author); + return { + total: total, + by_author: by_author + }; + }, + add_date: function(date, collection) { + collection[date] = {}; + return collection[date].date = date; + }, + add_author: function(author, by_author, by_email) { + var data, normalized_email; + data = {}; + data.author_name = author.author_name; + data.author_email = author.author_email; + normalized_email = author.author_email.toLowerCase(); + by_author[author.author_name] = data; + by_email[normalized_email] = data; + return data; + }, + store_data: function(entry, total, by_author) { + this.store_commits(total, by_author); + this.store_additions(entry, total, by_author); + return this.store_deletions(entry, total, by_author); + }, + store_commits: function(total, by_author) { + this.add(total, "commits", 1); + return this.add(by_author, "commits", 1); + }, + add: function(collection, field, value) { + if (collection[field] == null) { + collection[field] = 0; + } + return collection[field] += value; + }, + store_additions: function(entry, total, by_author) { + if (entry.additions == null) { + entry.additions = 0; + } + this.add(total, "additions", entry.additions); + return this.add(by_author, "additions", entry.additions); + }, + store_deletions: function(entry, total, by_author) { + if (entry.deletions == null) { + entry.deletions = 0; + } + this.add(total, "deletions", entry.deletions); + return this.add(by_author, "deletions", entry.deletions); + }, + get_total_data: function(parsed_log, field) { + var log, total_data; + log = parsed_log.total; + total_data = this.pick_field(log, field); + return _.sortBy(total_data, function(d) { + return d.date; + }); + }, + pick_field: function(log, field) { + var total_data; + total_data = []; + _.each(log, function(d) { + return total_data.push(_.pick(d, [field, 'date'])); + }); + return total_data; + }, + get_author_data: function(parsed_log, field, date_range) { + var author_data, log; + if (date_range == null) { + date_range = null; + } + log = parsed_log.by_author; + author_data = []; + _.each(log, (function(_this) { + return function(log_entry) { + var parsed_log_entry; + parsed_log_entry = _this.parse_log_entry(log_entry, field, date_range); + if (!_.isEmpty(parsed_log_entry.dates)) { + return author_data.push(parsed_log_entry); + } + }; + })(this)); + return _.sortBy(author_data, function(d) { + return d[field]; + }).reverse(); + }, + parse_log_entry: function(log_entry, field, date_range) { + var parsed_entry; + parsed_entry = {}; + parsed_entry.author_name = log_entry.author_name; + parsed_entry.author_email = log_entry.author_email; + parsed_entry.dates = {}; + parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0; + _.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) { + return function(value, key) { + if (_this.in_range(value.date, date_range)) { + parsed_entry.dates[value.date] = value[field]; + parsed_entry.commits += value.commits; + parsed_entry.additions += value.additions; + return parsed_entry.deletions += value.deletions; + } + }; + })(this)); + return parsed_entry; + }, + in_range: function(date, date_range) { + var ref; + if (date_range === null || (date_range[0] <= (ref = new Date(date)) && ref <= date_range[1])) { + return true; + } else { + return false; + } + } +}; diff --git a/app/assets/javascripts/group_avatar.js b/app/assets/javascripts/group_avatar.js index c5cb273c5b2..f03b47b1c1d 100644 --- a/app/assets/javascripts/group_avatar.js +++ b/app/assets/javascripts/group_avatar.js @@ -1,20 +1,19 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, no-var, one-var, one-var-declaration-per-line, no-useless-escape, max-len */ -(function() { - this.GroupAvatar = (function() { - function GroupAvatar() { - $('.js-choose-group-avatar-button').on("click", function() { - var form; - form = $(this).closest("form"); - return form.find(".js-group-avatar-input").click(); - }); - $('.js-group-avatar-input').on("change", function() { - var filename, form; - form = $(this).closest("form"); - filename = $(this).val().replace(/^.*[\\\/]/, ''); - return form.find(".js-avatar-filename").text(filename); - }); - } - return GroupAvatar; - })(); -}).call(window); +window.GroupAvatar = (function() { + function GroupAvatar() { + $('.js-choose-group-avatar-button').on("click", function() { + var form; + form = $(this).closest("form"); + return form.find(".js-group-avatar-input").click(); + }); + $('.js-group-avatar-input').on("change", function() { + var filename, form; + form = $(this).closest("form"); + filename = $(this).val().replace(/^.*[\\\/]/, ''); + return form.find(".js-avatar-filename").text(filename); + }); + } + + return GroupAvatar; +})(); diff --git a/app/assets/javascripts/group_label_subscription.js b/app/assets/javascripts/group_label_subscription.js new file mode 100644 index 00000000000..7dc9ce898e8 --- /dev/null +++ b/app/assets/javascripts/group_label_subscription.js @@ -0,0 +1,52 @@ +/* eslint-disable func-names, object-shorthand, comma-dangle, wrap-iife, space-before-function-paren, no-param-reassign, max-len */ + +class GroupLabelSubscription { + constructor(container) { + const $container = $(container); + this.$dropdown = $container.find('.dropdown'); + this.$subscribeButtons = $container.find('.js-subscribe-button'); + this.$unsubscribeButtons = $container.find('.js-unsubscribe-button'); + + this.$subscribeButtons.on('click', this.subscribe.bind(this)); + this.$unsubscribeButtons.on('click', this.unsubscribe.bind(this)); + } + + unsubscribe(event) { + event.preventDefault(); + + const url = this.$unsubscribeButtons.attr('data-url'); + + $.ajax({ + type: 'POST', + url: url + }).done(() => { + this.toggleSubscriptionButtons(); + this.$unsubscribeButtons.removeAttr('data-url'); + }); + } + + subscribe(event) { + event.preventDefault(); + + const $btn = $(event.currentTarget); + const url = $btn.attr('data-url'); + + this.$unsubscribeButtons.attr('data-url', url); + + $.ajax({ + type: 'POST', + url: url + }).done(() => { + this.toggleSubscriptionButtons(); + }); + } + + toggleSubscriptionButtons() { + this.$dropdown.toggleClass('hidden'); + this.$subscribeButtons.toggleClass('hidden'); + this.$unsubscribeButtons.toggleClass('hidden'); + } +} + +window.gl = window.gl || {}; +window.gl.GroupLabelSubscription = GroupLabelSubscription; diff --git a/app/assets/javascripts/group_label_subscription.js.es6 b/app/assets/javascripts/group_label_subscription.js.es6 deleted file mode 100644 index 15e695e81cf..00000000000 --- a/app/assets/javascripts/group_label_subscription.js.es6 +++ /dev/null @@ -1,53 +0,0 @@ -/* eslint-disable func-names, object-shorthand, comma-dangle, wrap-iife, space-before-function-paren, no-param-reassign, max-len */ - -(function(global) { - class GroupLabelSubscription { - constructor(container) { - const $container = $(container); - this.$dropdown = $container.find('.dropdown'); - this.$subscribeButtons = $container.find('.js-subscribe-button'); - this.$unsubscribeButtons = $container.find('.js-unsubscribe-button'); - - this.$subscribeButtons.on('click', this.subscribe.bind(this)); - this.$unsubscribeButtons.on('click', this.unsubscribe.bind(this)); - } - - unsubscribe(event) { - event.preventDefault(); - - const url = this.$unsubscribeButtons.attr('data-url'); - - $.ajax({ - type: 'POST', - url: url - }).done(() => { - this.toggleSubscriptionButtons(); - this.$unsubscribeButtons.removeAttr('data-url'); - }); - } - - subscribe(event) { - event.preventDefault(); - - const $btn = $(event.currentTarget); - const url = $btn.attr('data-url'); - - this.$unsubscribeButtons.attr('data-url', url); - - $.ajax({ - type: 'POST', - url: url - }).done(() => { - this.toggleSubscriptionButtons(); - }); - } - - toggleSubscriptionButtons() { - this.$dropdown.toggleClass('hidden'); - this.$subscribeButtons.toggleClass('hidden'); - this.$unsubscribeButtons.toggleClass('hidden'); - } - } - - global.GroupLabelSubscription = GroupLabelSubscription; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/group_name.js b/app/assets/javascripts/group_name.js new file mode 100644 index 00000000000..6a028f299b1 --- /dev/null +++ b/app/assets/javascripts/group_name.js @@ -0,0 +1,40 @@ +const GROUP_LIMIT = 2; + +export default class GroupName { + constructor() { + this.titleContainer = document.querySelector('.title'); + this.groups = document.querySelectorAll('.group-path'); + this.groupTitle = document.querySelector('.group-title'); + this.toggle = null; + this.isHidden = false; + this.init(); + } + + init() { + if (this.groups.length > GROUP_LIMIT) { + this.groups[this.groups.length - 1].classList.remove('hidable'); + this.addToggle(); + } + this.render(); + } + + addToggle() { + const header = document.querySelector('.header-content'); + this.toggle = document.createElement('button'); + this.toggle.className = 'text-expander group-name-toggle'; + this.toggle.setAttribute('aria-label', 'Toggle full path'); + this.toggle.innerHTML = '...'; + this.toggle.addEventListener('click', this.toggleGroups.bind(this)); + header.insertBefore(this.toggle, this.titleContainer); + this.toggleGroups(); + } + + toggleGroups() { + this.isHidden = !this.isHidden; + this.groupTitle.classList.toggle('is-hidden'); + } + + render() { + this.titleContainer.classList.remove('initializing'); + } +} diff --git a/app/assets/javascripts/groups_list.js b/app/assets/javascripts/groups_list.js new file mode 100644 index 00000000000..56a8cbf6d03 --- /dev/null +++ b/app/assets/javascripts/groups_list.js @@ -0,0 +1,18 @@ +import FilterableList from './filterable_list'; + +/** + * Makes search request for groups when user types a value in the search input. + * Updates the html content of the page with the received one. + */ +export default class GroupsList { + constructor() { + const form = document.querySelector('form#group-filter-form'); + const filter = document.querySelector('.js-groups-list-filter'); + const holder = document.querySelector('.js-groups-list-holder'); + + if (form && filter && holder) { + const list = new FilterableList(form, filter, holder); + list.initSearch(); + } + } +} diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js index 6b937e7fa0f..e5dfa30edab 100644 --- a/app/assets/javascripts/groups_select.js +++ b/app/assets/javascripts/groups_select.js @@ -1,71 +1,69 @@ /* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, one-var, camelcase, one-var-declaration-per-line, quotes, object-shorthand, prefer-arrow-callback, comma-dangle, consistent-return, yoda, prefer-rest-params, prefer-spread, no-unused-vars, prefer-template, max-len */ /* global Api */ -(function() { - var slice = [].slice; +var slice = [].slice; - this.GroupsSelect = (function() { - function GroupsSelect() { - $('.ajax-groups-select').each((function(_this) { - return function(i, select) { - var all_available, skip_groups; - all_available = $(select).data('all-available'); - skip_groups = $(select).data('skip-groups') || []; - return $(select).select2({ - placeholder: "Search for a group", - multiple: $(select).hasClass('multiselect'), - minimumInputLength: 0, - query: function(query) { - var options = { all_available: all_available, skip_groups: skip_groups }; - return Api.groups(query.term, options, function(groups) { - var data; - data = { - results: groups - }; - return query.callback(data); - }); - }, - initSelection: function(element, callback) { - var id; - id = $(element).val(); - if (id !== "") { - return Api.group(id, callback); - } - }, - formatResult: function() { - var args; - args = 1 <= arguments.length ? slice.call(arguments, 0) : []; - return _this.formatResult.apply(_this, args); - }, - formatSelection: function() { - var args; - args = 1 <= arguments.length ? slice.call(arguments, 0) : []; - return _this.formatSelection.apply(_this, args); - }, - dropdownCssClass: "ajax-groups-dropdown", - // we do not want to escape markup since we are displaying html in results - escapeMarkup: function(m) { - return m; +window.GroupsSelect = (function() { + function GroupsSelect() { + $('.ajax-groups-select').each((function(_this) { + return function(i, select) { + var all_available, skip_groups; + all_available = $(select).data('all-available'); + skip_groups = $(select).data('skip-groups') || []; + return $(select).select2({ + placeholder: "Search for a group", + multiple: $(select).hasClass('multiselect'), + minimumInputLength: 0, + query: function(query) { + var options = { all_available: all_available, skip_groups: skip_groups }; + return Api.groups(query.term, options, function(groups) { + var data; + data = { + results: groups + }; + return query.callback(data); + }); + }, + initSelection: function(element, callback) { + var id; + id = $(element).val(); + if (id !== "") { + return Api.group(id, callback); } - }); - }; - })(this)); + }, + formatResult: function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return _this.formatResult.apply(_this, args); + }, + formatSelection: function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return _this.formatSelection.apply(_this, args); + }, + dropdownCssClass: "ajax-groups-dropdown", + // we do not want to escape markup since we are displaying html in results + escapeMarkup: function(m) { + return m; + } + }); + }; + })(this)); + } + + GroupsSelect.prototype.formatResult = function(group) { + var avatar; + if (group.avatar_url) { + avatar = group.avatar_url; + } else { + avatar = gon.default_avatar_url; } + return "
    " + group.full_name + "
    " + group.full_path + "
    "; + }; - GroupsSelect.prototype.formatResult = function(group) { - var avatar; - if (group.avatar_url) { - avatar = group.avatar_url; - } else { - avatar = gon.default_avatar_url; - } - return "
    " + group.full_name + "
    " + group.full_path + "
    "; - }; + GroupsSelect.prototype.formatSelection = function(group) { + return group.full_name; + }; - GroupsSelect.prototype.formatSelection = function(group) { - return group.full_name; - }; - - return GroupsSelect; - })(); -}).call(window); + return GroupsSelect; +})(); diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index a853c3aeb1f..34f44dad7a5 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -1,8 +1,7 @@ -/* eslint-disable wrap-iife, func-names, space-before-function-paren, prefer-arrow-callback, no-var, max-len */ -(function() { - $(document).on('todo:toggle', function(e, count) { - var $todoPendingCount = $('.todos-pending-count'); - $todoPendingCount.text(gl.text.highCountTrim(count)); - $todoPendingCount.toggleClass('hidden', count === 0); - }); -})(); +/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var */ + +$(document).on('todo:toggle', function(e, count) { + var $todoPendingCount = $('.todos-pending-count'); + $todoPendingCount.text(gl.text.highCountTrim(count)); + $todoPendingCount.toggleClass('hidden', count === 0); +}); diff --git a/app/assets/javascripts/issuable.js.es6 b/app/assets/javascripts/issuable.js similarity index 98% rename from app/assets/javascripts/issuable.js.es6 rename to app/assets/javascripts/issuable.js index 8df86f68218..3bfce32768a 100644 --- a/app/assets/javascripts/issuable.js.es6 +++ b/app/assets/javascripts/issuable.js @@ -116,7 +116,7 @@ formData = $.param(formData); formAction = form.attr('action'); issuesUrl = formAction; - issuesUrl += "" + (formAction.indexOf('?') < 0 ? '?' : '&'); + issuesUrl += "" + (formAction.indexOf('?') === -1 ? '?' : '&'); issuesUrl += formData; return gl.utils.visitUrl(issuesUrl); }; diff --git a/app/assets/javascripts/issuable/issuable_bundle.js.es6 b/app/assets/javascripts/issuable/issuable_bundle.js similarity index 100% rename from app/assets/javascripts/issuable/issuable_bundle.js.es6 rename to app/assets/javascripts/issuable/issuable_bundle.js diff --git a/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js similarity index 94% rename from app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6 rename to app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js index bf27fbac5d7..357b3487ca9 100644 --- a/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js @@ -1,4 +1,6 @@ /* global Vue */ +import stopwatchSvg from 'icons/_icon_stopwatch.svg'; + require('../../../lib/utils/pretty_time'); (() => { @@ -11,7 +13,6 @@ require('../../../lib/utils/pretty_time'); 'showNoTimeTrackingState', 'timeSpentHumanReadable', 'timeEstimateHumanReadable', - 'stopwatchSvg', ], methods: { abbreviateTime(timeStr) { @@ -20,7 +21,7 @@ require('../../../lib/utils/pretty_time'); }, template: `
  • " + user.name + "
  • "; @@ -248,7 +262,7 @@ } } // split into three parts so we can remove the username section if nessesary - listWithName = "
  • " + img + " " + user.name + " "; + listWithName = "
  • " + img + " " + user.name + " "; listWithUserName = " " + username + " "; listClosingTags = "
  • "; if (username === '') { diff --git a/app/assets/javascripts/version_check_image.js b/app/assets/javascripts/version_check_image.js new file mode 100644 index 00000000000..d4f716acb72 --- /dev/null +++ b/app/assets/javascripts/version_check_image.js @@ -0,0 +1,10 @@ +class VersionCheckImage { + static bindErrorEvent(imageElement) { + imageElement.off('error').on('error', () => imageElement.hide()); + } +} + +window.gl = window.gl || {}; +gl.VersionCheckImage = VersionCheckImage; + +module.exports = VersionCheckImage; diff --git a/app/assets/javascripts/version_check_image.js.es6 b/app/assets/javascripts/version_check_image.js.es6 deleted file mode 100644 index 1fa2b5ac399..00000000000 --- a/app/assets/javascripts/version_check_image.js.es6 +++ /dev/null @@ -1,10 +0,0 @@ -(() => { - class VersionCheckImage { - static bindErrorEvent(imageElement) { - imageElement.off('error').on('error', () => imageElement.hide()); - } - } - - window.gl = window.gl || {}; - gl.VersionCheckImage = VersionCheckImage; -})(); diff --git a/app/assets/javascripts/visibility_select.js.es6 b/app/assets/javascripts/visibility_select.js similarity index 100% rename from app/assets/javascripts/visibility_select.js.es6 rename to app/assets/javascripts/visibility_select.js diff --git a/app/assets/javascripts/vue_pipelines_index/components/async_button.js b/app/assets/javascripts/vue_pipelines_index/components/async_button.js new file mode 100644 index 00000000000..aaebf29d8ae --- /dev/null +++ b/app/assets/javascripts/vue_pipelines_index/components/async_button.js @@ -0,0 +1,92 @@ +/* eslint-disable no-new, no-alert */ +/* global Flash */ +import '~/flash'; +import eventHub from '../event_hub'; + +export default { + props: { + endpoint: { + type: String, + required: true, + }, + + service: { + type: Object, + required: true, + }, + + title: { + type: String, + required: true, + }, + + icon: { + type: String, + required: true, + }, + + cssClass: { + type: String, + required: true, + }, + + confirmActionMessage: { + type: String, + required: false, + }, + }, + + data() { + return { + isLoading: false, + }; + }, + + computed: { + iconClass() { + return `fa fa-${this.icon}`; + }, + + buttonClass() { + return `btn has-tooltip ${this.cssClass}`; + }, + }, + + methods: { + onClick() { + if (this.confirmActionMessage && confirm(this.confirmActionMessage)) { + this.makeRequest(); + } else if (!this.confirmActionMessage) { + this.makeRequest(); + } + }, + + makeRequest() { + this.isLoading = true; + + this.service.postAction(this.endpoint) + .then(() => { + this.isLoading = false; + eventHub.$emit('refreshPipelines'); + }) + .catch(() => { + this.isLoading = false; + new Flash('An error occured while making the request.'); + }); + }, + }, + + template: ` +