diff options
184 files changed, 3435 insertions, 939 deletions
diff --git a/.eslintignore b/.eslintignore index b4bfa5a1f7a..c742b08c005 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,7 +1,9 @@ +/builds/ /coverage/ /coverage-javascript/ /node_modules/ /public/ /tmp/ /vendor/ -/builds/ +karma.config.js +webpack.config.js diff --git a/.eslintrc b/.eslintrc index e13f76b213c..8bab73bbe16 100644 --- a/.eslintrc +++ b/.eslintrc @@ -15,6 +15,8 @@ "filenames" ], "rules": { - "filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"] + "filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"], + "import/no-extraneous-dependencies": "off", + "import/no-unresolved": "off" } } diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 68690ff33da..6d77d94637a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -108,11 +108,14 @@ setup-test-env: <<: *dedicated-runner stage: prepare script: + - npm install + - bundle exec rake webpack:compile - bundle exec rake assets:precompile 2>/dev/null - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' artifacts: expire_in: 7d paths: + - node_modules - public/assets - tmp/tests @@ -233,7 +236,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21 script: - bundle exec $CI_BUILD_NAME -rubocop: +rubocop: <<: *ruby-static-analysis <<: *dedicated-runner stage: test @@ -292,18 +295,17 @@ rake db:seed_fu: paths: - log/development.log -teaspoon: +karma: cache: paths: - vendor/ruby - - node_modules/ + - node_modules stage: test <<: *use-db <<: *dedicated-runner script: - - npm install - npm link istanbul - - rake teaspoon + - rake karma artifacts: name: coverage-javascript expire_in: 31d @@ -445,7 +447,7 @@ pages: <<: *dedicated-runner dependencies: - coverage - - teaspoon + - karma - lint:javascript:report script: - mv public/ .public/ diff --git a/.rubocop.yml b/.rubocop.yml index bf2b2d8afc2..cfff42e5c99 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -17,6 +17,7 @@ AllCops: # Exclude some GitLab files Exclude: - 'vendor/**/*' + - 'node_modules/**/*' - 'db/*' - 'db/fixtures/**/*' - 'tmp/**/*' @@ -219,6 +219,7 @@ gem 'oj', '~> 2.17.4' gem 'chronic', '~> 0.10.2' gem 'chronic_duration', '~> 0.10.6' +gem 'webpack-rails', '~> 0.9.9' gem 'sassc-rails', '~> 1.3.0' gem 'coffee-rails', '~> 4.1.0' gem 'uglifier', '~> 2.7.2' @@ -291,13 +292,9 @@ group :development, :test do gem 'capybara-screenshot', '~> 1.0.0' gem 'poltergeist', '~> 1.9.0' - gem 'teaspoon', '~> 1.1.0' - gem 'teaspoon-jasmine', '~> 2.2.0' - gem 'spring', '~> 1.7.0' gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-spinach', '~> 1.1.0' - gem 'spring-commands-teaspoon', '~> 0.0.2' gem 'rubocop', '~> 0.46.0', require: false gem 'rubocop-rspec', '~> 1.9.1', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 4d025683b20..7ec1f2df5e9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -735,8 +735,6 @@ GEM spring (>= 0.9.1) spring-commands-spinach (1.1.0) spring (>= 0.9.1) - spring-commands-teaspoon (0.0.2) - spring (>= 0.9.1) sprockets (3.7.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -760,10 +758,6 @@ GEM sys-filesystem (1.1.6) ffi sysexits (1.2.0) - teaspoon (1.1.5) - railties (>= 3.2.5, < 6) - teaspoon-jasmine (2.2.0) - teaspoon (>= 1.0.0) temple (0.7.7) test_after_commit (0.4.2) activerecord (>= 3.2) @@ -815,6 +809,8 @@ GEM webmock (1.21.0) addressable (>= 2.3.6) crack (>= 0.3.2) + webpack-rails (0.9.9) + rails (>= 3.2.0) websocket-driver (0.6.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) @@ -994,14 +990,11 @@ DEPENDENCIES spring (~> 1.7.0) spring-commands-rspec (~> 1.0.4) spring-commands-spinach (~> 1.1.0) - spring-commands-teaspoon (~> 0.0.2) sprockets (~> 3.7.0) sprockets-es6 (~> 0.9.2) stackprof (~> 0.2.10) state_machines-activerecord (~> 0.4.0) sys-filesystem (~> 1.1.6) - teaspoon (~> 1.1.0) - teaspoon-jasmine (~> 2.2.0) test_after_commit (~> 0.4.2) thin (~> 1.7.0) timecop (~> 0.8.0) @@ -1017,6 +1010,7 @@ DEPENDENCIES vmstat (~> 2.3.0) web-console (~> 2.0) webmock (~> 1.21.0) + webpack-rails (~> 0.9.9) wikicloth (= 0.8.1) BUNDLED WITH @@ -4,4 +4,5 @@ # web: RAILS_ENV=development bin/web start_foreground worker: RAILS_ENV=development bin/background_jobs start_foreground +webpack: npm run dev-server # mail_room: bundle exec mail_room -q -c config/mail_room.yml diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index f0615481ed2..98042106111 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, quotes, consistent-return, prefer-arrow-callback, comma-dangle, object-shorthand, no-new, max-len */ +/* 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 */ @@ -6,62 +6,59 @@ /* global AwardsHandler */ /* global Aside */ -// This is a manifest file that'll be compiled into including all the files listed below. -// Add new JavaScript code in separate files in this directory and they'll automatically -// be included in the compiled file accessible from http://example.com/assets/application.js -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// the compiled file. -// -/*= require jquery2 */ -/*= require jquery-ui/autocomplete */ -/*= require jquery-ui/datepicker */ -/*= require jquery-ui/draggable */ -/*= require jquery-ui/effect-highlight */ -/*= require jquery-ui/sortable */ -/*= require jquery_ujs */ -/*= require jquery.endless-scroll */ -/*= require jquery.highlight */ -/*= require jquery.waitforimages */ -/*= require jquery.atwho */ -/*= require jquery.scrollTo */ -/*= require jquery.turbolinks */ -/*= require js.cookie */ -/*= require turbolinks */ -/*= require autosave */ -/*= require bootstrap/affix */ -/*= require bootstrap/alert */ -/*= require bootstrap/button */ -/*= require bootstrap/collapse */ -/*= require bootstrap/dropdown */ -/*= require bootstrap/modal */ -/*= require bootstrap/scrollspy */ -/*= require bootstrap/tab */ -/*= require bootstrap/transition */ -/*= require bootstrap/tooltip */ -/*= require bootstrap/popover */ -/*= require select2 */ -/*= require underscore */ -/*= require dropzone */ -/*= require mousetrap */ -/*= require mousetrap/pause */ -/*= require shortcuts */ -/*= require shortcuts_navigation */ -/*= require shortcuts_dashboard_navigation */ -/*= require shortcuts_issuable */ -/*= require shortcuts_network */ -/*= require jquery.nicescroll */ -/*= require date.format */ -/*= require_directory ./behaviors */ -/*= require_directory ./blob */ -/*= require_directory ./templates */ -/*= require_directory ./commit */ -/*= require_directory ./extensions */ -/*= require_directory ./lib/utils */ -/*= require_directory ./u2f */ -/*= require_directory ./droplab */ -/*= require_directory . */ -/*= require fuzzaldrin-plus */ -/*= require es6-promise.auto */ +function requireAll(context) { return context.keys().map(context); } + +window.$ = window.jQuery = require('jquery'); +require('jquery-ui/ui/autocomplete'); +require('jquery-ui/ui/datepicker'); +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'); +require('vendor/jquery.turbolinks'); +window.Cookies = require('vendor/js.cookie'); +require('vendor/turbolinks'); +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._ = require('underscore'); +window.Dropzone = require('dropzone'); +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|es6)$/)); +require('vendor/fuzzaldrin-plus'); +window.ES6Promise = require('vendor/es6-promise.auto'); +window.ES6Promise.polyfill(); (function () { document.addEventListener('page:fetch', function () { diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index 107a7978a87..db9df8cdd3c 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -1,11 +1,13 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, spaced-comment, 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, radix, keyword-spacing, space-before-blocks, brace-style, no-underscore-dangle, no-plusplus, no-return-assign, camelcase, padded-blocks */ /* global Cookies */ +var emojiAliases = require('emoji-aliases'); + (function() { this.AwardsHandler = (function() { var FROM_SENTENCE_REGEX = /(?:, and | and |, )/; //For separating lists produced by ruby's Array#toSentence function AwardsHandler() { - this.aliases = gl.emojiAliases(); + this.aliases = emojiAliases; $(document).off('click', '.js-add-award').on('click', '.js-add-award', (function(_this) { return function(e) { e.stopPropagation(); diff --git a/app/assets/javascripts/behaviors/autosize.js b/app/assets/javascripts/behaviors/autosize.js index c62a4c5a456..9b5cd25989d 100644 --- a/app/assets/javascripts/behaviors/autosize.js +++ b/app/assets/javascripts/behaviors/autosize.js @@ -1,8 +1,8 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, consistent-return, padded-blocks, max-len */ /* global autosize */ -/*= require jquery.ba-resize */ -/*= require autosize */ +var autosize = require('vendor/autosize'); +require('vendor/jquery.ba-resize'); (function() { $(function() { diff --git a/app/assets/javascripts/behaviors/quick_submit.js b/app/assets/javascripts/behaviors/quick_submit.js index 586f941a6e3..4f43e8baf42 100644 --- a/app/assets/javascripts/behaviors/quick_submit.js +++ b/app/assets/javascripts/behaviors/quick_submit.js @@ -6,7 +6,7 @@ // "Meta+Enter" (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, the form // is submitted. // -/*= require extensions/jquery */ +require('../extensions/jquery'); // // ### Example Markup diff --git a/app/assets/javascripts/behaviors/requires_input.js b/app/assets/javascripts/behaviors/requires_input.js index 72362988b2e..28bc06c5d76 100644 --- a/app/assets/javascripts/behaviors/requires_input.js +++ b/app/assets/javascripts/behaviors/requires_input.js @@ -4,7 +4,7 @@ // When called on a form with input fields with the `required` attribute, the // form's submit button will be disabled until all required fields have values. // -/*= require extensions/jquery */ +require('../extensions/jquery'); // // ### Example Markup diff --git a/app/assets/javascripts/blob/blob_ci_yaml.js.es6 b/app/assets/javascripts/blob/blob_ci_yaml.js.es6 index 57bd13eecf8..a548509ee0d 100644 --- a/app/assets/javascripts/blob/blob_ci_yaml.js.es6 +++ b/app/assets/javascripts/blob/blob_ci_yaml.js.es6 @@ -1,7 +1,8 @@ /* eslint-disable padded-blocks, no-param-reassign, comma-dangle */ /* global Api */ -/*= require blob/template_selector */ +require('./template_selector'); + ((global) => { class BlobCiYamlSelector extends gl.TemplateSelector { diff --git a/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 b/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 index bdf95017613..d4f60cc6ecd 100644 --- a/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 +++ b/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 @@ -1,5 +1,6 @@ /* global Api */ -/*= require blob/template_selector */ + +require('./template_selector'); (() => { const global = window.gl || (window.gl = {}); diff --git a/app/assets/javascripts/blob/blob_gitignore_selector.js b/app/assets/javascripts/blob/blob_gitignore_selector.js index 15563e429a0..82a198ad825 100644 --- a/app/assets/javascripts/blob/blob_gitignore_selector.js +++ b/app/assets/javascripts/blob/blob_gitignore_selector.js @@ -1,7 +1,7 @@ /* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, padded-blocks */ /* global Api */ -/*= require blob/template_selector */ +require('./template_selector'); (function() { var 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; }, diff --git a/app/assets/javascripts/blob/blob_license_selector.js b/app/assets/javascripts/blob/blob_license_selector.js index d9c6f65a083..4c3ca20e25d 100644 --- a/app/assets/javascripts/blob/blob_license_selector.js +++ b/app/assets/javascripts/blob/blob_license_selector.js @@ -1,7 +1,7 @@ /* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, comma-dangle, padded-blocks */ /* global Api */ -/*= require blob/template_selector */ +require('./template_selector'); (function() { var 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; }, diff --git a/app/assets/javascripts/blob_edit/blob_edit_bundle.js b/app/assets/javascripts/blob_edit/blob_edit_bundle.js index 8c40e36a80a..9c523d3b22e 100644 --- a/app/assets/javascripts/blob_edit/blob_edit_bundle.js +++ b/app/assets/javascripts/blob_edit/blob_edit_bundle.js @@ -2,7 +2,7 @@ /* global EditBlob */ /* global NewCommitForm */ -/*= require_tree . */ +require('./edit_blob'); (function() { $(function() { diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6 index 2c9ab61c94d..9f454486efc 100644 --- a/app/assets/javascripts/boards/boards_bundle.js.es6 +++ b/app/assets/javascripts/boards/boards_bundle.js.es6 @@ -1,19 +1,21 @@ -/* eslint-disable one-var, indent, quote-props, comma-dangle, space-before-function-paren */ +/* eslint-disable one-var, indent, quote-props, comma-dangle, space-before-function-paren, import/newline-after-import, no-multi-spaces, max-len */ /* global Vue */ /* global BoardService */ -//= require vue -//= require vue-resource -//= require Sortable -//= require_tree ./models -//= require_tree ./stores -//= require_tree ./services -//= require_tree ./mixins -//= require_tree ./filters -//= require ./components/board -//= require ./components/board_sidebar -//= require ./components/new_list_dropdown -//= require ./vue_resource_interceptor +function requireAll(context) { return context.keys().map(context); } + +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); +window.Sortable = require('vendor/Sortable'); +requireAll(require.context('./models', true, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./stores', true, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./services', true, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./mixins', true, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./filters', true, /^\.\/.*\.(js|es6)$/)); +require('./components/board'); +require('./components/board_sidebar'); +require('./components/new_list_dropdown'); +require('./vue_resource_interceptor'); $(() => { const $boardApp = document.getElementById('board-app'), diff --git a/app/assets/javascripts/boards/components/board.js.es6 b/app/assets/javascripts/boards/components/board.js.es6 index 8d1a0f482f9..b3ca4aa90a7 100644 --- a/app/assets/javascripts/boards/components/board.js.es6 +++ b/app/assets/javascripts/boards/components/board.js.es6 @@ -2,9 +2,9 @@ /* global Vue */ /* global Sortable */ -//= require ./board_blank_state -//= require ./board_delete -//= require ./board_list +require('./board_blank_state'); +require('./board_delete'); +require('./board_list'); (() => { const Store = gl.issueBoards.BoardsStore; diff --git a/app/assets/javascripts/boards/components/board_list.js.es6 b/app/assets/javascripts/boards/components/board_list.js.es6 index 6711930622b..d896076d4af 100644 --- a/app/assets/javascripts/boards/components/board_list.js.es6 +++ b/app/assets/javascripts/boards/components/board_list.js.es6 @@ -2,8 +2,8 @@ /* global Vue */ /* global Sortable */ -//= require ./board_card -//= require ./board_new_issue +require('./board_card'); +require('./board_new_issue'); (() => { const Store = gl.issueBoards.BoardsStore; diff --git a/app/assets/javascripts/copy_to_clipboard.js b/app/assets/javascripts/copy_to_clipboard.js index 6a13f38588d..0a6f95e96ec 100644 --- a/app/assets/javascripts/copy_to_clipboard.js +++ b/app/assets/javascripts/copy_to_clipboard.js @@ -1,7 +1,7 @@ /* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, prefer-arrow-callback, padded-blocks, max-len */ /* global Clipboard */ -/*= require clipboard */ +window.Clipboard = require('vendor/clipboard'); (function() { var genericError, genericSuccess, showTooltip; diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 index 2f810a69758..c41c57c1dcd 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 @@ -2,9 +2,12 @@ /* global Cookies */ /* global Flash */ -//= require vue -//= require_tree ./svg -//= require_tree . +window.Vue = require('vue'); +window.Cookies = require('vendor/js.cookie'); + +function requireAll(context) { return context.keys().map(context); } +requireAll(require.context('./svg', false, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('.', true, /^\.\/(?!cycle_analytics_bundle).*\.(js|es6)$/)); $(() => { const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed'; diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 index 840b5aa922e..0a25b8f1ccd 100644 --- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 +++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 @@ -1,14 +1,16 @@ -/* eslint-disable func-names, comma-dangle, new-cap, no-new */ +/* eslint-disable func-names, comma-dangle, new-cap, no-new, import/newline-after-import, no-multi-spaces, max-len */ /* global Vue */ /* global ResolveCount */ -//= require vue -//= require vue-resource -//= require_directory ./models -//= require_directory ./stores -//= require_directory ./services -//= require_directory ./mixins -//= require_directory ./components +function requireAll(context) { return context.keys().map(context); } + +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); +requireAll(require.context('./models', false, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./stores', false, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./services', false, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./mixins', false, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./components', false, /^\.\/.*\.(js|es6)$/)); $(() => { const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn'; diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js index 56cb39be642..b280ab88c8d 100644 --- a/app/assets/javascripts/dropzone_input.js +++ b/app/assets/javascripts/dropzone_input.js @@ -1,7 +1,7 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, one-var, no-var, one-var-declaration-per-line, no-unused-vars, camelcase, quotes, no-useless-concat, prefer-template, quote-props, comma-dangle, object-shorthand, consistent-return, no-plusplus, prefer-arrow-callback, padded-blocks */ /* global Dropzone */ -/*= require preview_markdown */ +require('./preview_markdown'); (function() { this.DropzoneInput = (function() { diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6 index 8b6fafb6104..c1f3fe58f33 100644 --- a/app/assets/javascripts/environments/components/environment.js.es6 +++ b/app/assets/javascripts/environments/components/environment.js.es6 @@ -2,10 +2,10 @@ /* global Vue */ /* global EnvironmentsService */ -//= require vue -//= require vue-resource -//= require_tree ../services/ -//= require ./environment_item +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); +require('../services/environments_service'); +require('./environment_item'); (() => { window.gl = window.gl || {}; diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6 index 81468f4d3bc..ed1c78945db 100644 --- a/app/assets/javascripts/environments/components/environment_actions.js.es6 +++ b/app/assets/javascripts/environments/components/environment_actions.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/components/environment_external_url.js.es6 b/app/assets/javascripts/environments/components/environment_external_url.js.es6 index 6592c1b5f0f..28cc0022d17 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.js.es6 +++ b/app/assets/javascripts/environments/components/environment_external_url.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 0e6bc3fdb2c..521873b14b4 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,14 +1,15 @@ /* global Vue */ /* global timeago */ -/*= require timeago */ -/*= require lib/utils/text_utility */ -/*= require vue_common_component/commit */ -/*= require ./environment_actions */ -/*= require ./environment_external_url */ -/*= require ./environment_stop */ -/*= require ./environment_rollback */ -/*= require ./environment_terminal_button */ +window.Vue = require('vue'); +window.timeago = require('vendor/timeago'); +require('../../lib/utils/text_utility'); +require('../../vue_common_component/commit'); +require('./environment_actions'); +require('./environment_external_url'); +require('./environment_stop'); +require('./environment_rollback'); +require('./environment_terminal_button'); (() => { /** diff --git a/app/assets/javascripts/environments/components/environment_rollback.js.es6 b/app/assets/javascripts/environments/components/environment_rollback.js.es6 index b52298b4a88..5938340a128 100644 --- a/app/assets/javascripts/environments/components/environment_rollback.js.es6 +++ b/app/assets/javascripts/environments/components/environment_rollback.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/components/environment_stop.js.es6 b/app/assets/javascripts/environments/components/environment_stop.js.es6 index 0a29f2f36e9..be9526989a0 100644 --- a/app/assets/javascripts/environments/components/environment_stop.js.es6 +++ b/app/assets/javascripts/environments/components/environment_stop.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 b/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 index 050184ba497..a3ad063f7cb 100644 --- a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 +++ b/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 9f24a6a4f88..58f4c6eadb2 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -1,8 +1,8 @@ -//= require vue -//= require_tree ./stores/ -//= require ./components/environment -//= require ./vue_resource_interceptor +window.Vue = require('vue'); +require('./stores/environments_store'); +require('./components/environment'); +require('./vue_resource_interceptor'); $(() => { window.gl = window.gl || {}; diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6 index 575a45d9802..fab8d977f58 100644 --- a/app/assets/javascripts/environments/services/environments_service.js.es6 +++ b/app/assets/javascripts/environments/services/environments_service.js.es6 @@ -1,5 +1,6 @@ /* globals Vue */ /* eslint-disable no-unused-vars, no-param-reassign */ + class EnvironmentsService { constructor(root) { diff --git a/app/assets/javascripts/extensions/array.js.es6 b/app/assets/javascripts/extensions/array.js.es6 index 717566a4715..8956e303488 100644 --- a/app/assets/javascripts/extensions/array.js.es6 +++ b/app/assets/javascripts/extensions/array.js.es6 @@ -1,4 +1,7 @@ -/* eslint-disable no-extend-native, func-names, space-before-function-paren, semi, space-infix-ops, max-len */ +/* eslint-disable no-extend-native, func-names, space-before-function-paren, semi, space-infix-ops, strict, max-len */ + +'use strict'; + Array.prototype.first = function() { return this[0]; } diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 index 63c20f57520..bf4826b778e 100644 --- a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 @@ -1,4 +1,4 @@ -/*= require filtered_search/filtered_search_dropdown */ +require('./filtered_search_dropdown'); /* global droplabFilter */ diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 index f06c3fc9c6f..fe7a8ef84b5 100644 --- a/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 @@ -1,4 +1,4 @@ -/*= require filtered_search/filtered_search_dropdown */ +require('./filtered_search_dropdown'); /* global droplabAjax */ /* global droplabFilter */ diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_user.js.es6 index e80d266ae89..00295402e21 100644 --- a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_user.js.es6 @@ -1,4 +1,4 @@ -/*= require filtered_search/filtered_search_dropdown */ +require('./filtered_search_dropdown'); /* global droplabAjaxFilter */ diff --git a/app/assets/javascripts/filtered_search/filtered_search_bundle.js b/app/assets/javascripts/filtered_search/filtered_search_bundle.js index d188718c5f3..392f1835966 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_bundle.js +++ b/app/assets/javascripts/filtered_search/filtered_search_bundle.js @@ -1,7 +1,3 @@ - // This is a manifest file that'll be compiled into including all the files listed below. - // Add new JavaScript code in separate files in this directory and they'll automatically - // be included in the compiled file accessible from http://example.com/assets/application.js - // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the - // the compiled file. - // - /*= require_tree . */ +function requireAll(context) { return context.keys().map(context); } + +requireAll(require.context('./', true, /^\.\/(?!filtered_search_bundle).*\.(js|es6)$/)); diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index 00859728c30..df660a9a300 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -251,7 +251,7 @@ _this.fullData = data; _this.parseData(_this.fullData); _this.focusTextInput(); - if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val().trim() !== '') { + if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val() && _this.filter.input.val().trim() !== '') { return _this.filter.input.trigger('input'); } }; diff --git a/app/assets/javascripts/gl_field_errors.js.es6 b/app/assets/javascripts/gl_field_errors.js.es6 index 63f9cafa8d0..8b46c4e378f 100644 --- a/app/assets/javascripts/gl_field_errors.js.es6 +++ b/app/assets/javascripts/gl_field_errors.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign, padded-blocks */ -//= require gl_field_error +require('./gl_field_error'); ((global) => { const customValidationFlag = 'gl-field-error-ignore'; diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index 04814fa0843..34244813b4b 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -3,6 +3,8 @@ /* global DropzoneInput */ /* global autosize */ +var autosize = require('vendor/autosize'); + (function() { this.GLForm = (function() { function GLForm(form) { diff --git a/app/assets/javascripts/graphs/graphs_bundle.js b/app/assets/javascripts/graphs/graphs_bundle.js index 32c26349da0..4f7777aa5bc 100644 --- a/app/assets/javascripts/graphs/graphs_bundle.js +++ b/app/assets/javascripts/graphs/graphs_bundle.js @@ -1,12 +1,3 @@ -/* eslint-disable func-names, space-before-function-paren */ -// This is a manifest file that'll be compiled into including all the files listed below. -// Add new JavaScript code in separate files in this directory and they'll automatically -// be included in the compiled file accessible from http://example.com/assets/application.js -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// the compiled file. -// -/*= require_tree . */ - -(function() { - -}).call(this); +// require everything else in this directory +function requireAll(context) { return context.keys().map(context); } +requireAll(require.context('.', false, /^\.\/(?!graphs_bundle).*\.(js|es6)$/)); diff --git a/app/assets/javascripts/graphs/stat_graph_contributors.js b/app/assets/javascripts/graphs/stat_graph_contributors.js index 2d08a7c6ac3..c702ce2743d 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors.js @@ -5,7 +5,7 @@ /* global ContributorsStatGraphUtil */ /* global d3 */ -/*= require d3 */ +window.d3 = require('d3'); (function() { this.ContributorsStatGraph = (function() { diff --git a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js index 9c5e9381e52..3b7370bd8f6 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js @@ -2,7 +2,7 @@ /* global d3 */ /* global ContributorsGraph */ -/*= require d3 */ +window.d3 = require('d3'); (function() { var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index c7cbf9ca44b..9dd14b4c2ed 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -1,6 +1,5 @@ /* eslint-disable wrap-iife, func-names, space-before-function-paren, padded-blocks, prefer-arrow-callback, no-var, max-len */ (function() { - $(document).on('todo:toggle', function(e, count) { var $todoPendingCount = $('.todos-pending-count'); $todoPendingCount.text(gl.text.addDelimiter(count)); diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index 61e8531153b..97e03ede0e5 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -1,9 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, padded-blocks, max-len */ /* global Flash */ -/*= require flash */ -/*= require jquery.waitforimages */ -/*= require task_list */ +require('./flash'); +require('vendor/jquery.waitforimages'); +require('vendor/task_list'); (function() { var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; diff --git a/app/assets/javascripts/lib/chart.js b/app/assets/javascripts/lib/chart.js index d8ad5aaeffe..9b011d89e93 100644 --- a/app/assets/javascripts/lib/chart.js +++ b/app/assets/javascripts/lib/chart.js @@ -1,7 +1,3 @@ /* eslint-disable func-names, space-before-function-paren */ -/*= require Chart */ - -(function() { - -}).call(this); +window.Chart = require('vendor/Chart'); diff --git a/app/assets/javascripts/lib/d3.js b/app/assets/javascripts/lib/d3.js index 57e7986576c..a9dd32edbed 100644 --- a/app/assets/javascripts/lib/d3.js +++ b/app/assets/javascripts/lib/d3.js @@ -1,7 +1,3 @@ /* eslint-disable func-names, space-before-function-paren */ -/*= require d3 */ - -(function() { - -}).call(this); +window.d3 = require('d3'); diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index e8e502694d6..f859fc9c0da 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -2,8 +2,8 @@ /* global timeago */ /* global dateFormat */ -/*= require timeago */ -/*= require date.format */ +window.timeago = require('vendor/timeago'); +window.dateFormat = require('vendor/date.format'); (function() { (function(w) { diff --git a/app/assets/javascripts/lib/utils/emoji_aliases.js.erb b/app/assets/javascripts/lib/utils/emoji_aliases.js.erb deleted file mode 100644 index aeb86c9fa5b..00000000000 --- a/app/assets/javascripts/lib/utils/emoji_aliases.js.erb +++ /dev/null @@ -1,6 +0,0 @@ -(function() { - gl.emojiAliases = function() { - return JSON.parse('<%= Gitlab::AwardEmoji.aliases.to_json %>'); - }; - -}).call(this); diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js index 9af89b79f84..e7351173610 100644 --- a/app/assets/javascripts/line_highlighter.js +++ b/app/assets/javascripts/line_highlighter.js @@ -4,7 +4,7 @@ // // Handles single- and multi-line selection and highlight for blob views. // -/*= require jquery.scrollTo */ +require('vendor/jquery.scrollTo'); // // ### Example Markup diff --git a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 index 83520702f9b..92fad17cf00 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 +++ b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 @@ -2,14 +2,14 @@ /* global Vue */ /* global Flash */ -//= require vue -//= require ./merge_conflict_store -//= require ./merge_conflict_service -//= require ./mixins/line_conflict_utils -//= require ./mixins/line_conflict_actions -//= require ./components/diff_file_editor -//= require ./components/inline_conflict_lines -//= require ./components/parallel_conflict_lines +window.Vue = require('vue'); +require('./merge_conflict_store'); +require('./merge_conflict_service'); +require('./mixins/line_conflict_utils'); +require('./mixins/line_conflict_actions'); +require('./components/diff_file_editor'); +require('./components/inline_conflict_lines'); +require('./components/parallel_conflict_lines'); $(() => { const INTERACTIVE_RESOLVE_MODE = 'interactive'; diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index 244c2f6746c..19526157410 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -1,9 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, dot-notation, quote-props, comma-dangle, object-shorthand, padded-blocks, max-len, prefer-arrow-callback */ /* global MergeRequestTabs */ -/*= require jquery.waitforimages */ -/*= require task_list */ -/*= require merge_request_tabs */ +require('vendor/jquery.waitforimages'); +require('vendor/task_list'); +require('./merge_request_tabs'); (function() { var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js.es6 index 4c8c28af755..e8577c87d99 100644 --- a/app/assets/javascripts/merge_request_tabs.js.es6 +++ b/app/assets/javascripts/merge_request_tabs.js.es6 @@ -1,11 +1,11 @@ /* eslint-disable no-new, class-methods-use-this */ /* global Breakpoints */ /* global Cookies */ -/* global DiffNotesApp */ /* global Flash */ -/*= require js.cookie */ -/*= require breakpoints */ +require('./breakpoints'); +window.Cookies = require('vendor/js.cookie'); +require('./flash'); /* eslint-disable max-len */ // MergeRequestTabs diff --git a/app/assets/javascripts/merge_request_widget.js.es6 b/app/assets/javascripts/merge_request_widget.js.es6 index 0305aeb07d9..c3a4306316b 100644 --- a/app/assets/javascripts/merge_request_widget.js.es6 +++ b/app/assets/javascripts/merge_request_widget.js.es6 @@ -4,6 +4,8 @@ /* global merge_request_widget */ /* global Turbolinks */ +require('./smart_interval'); + ((global) => { var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; diff --git a/app/assets/javascripts/network/network_bundle.js b/app/assets/javascripts/network/network_bundle.js index 17833d3419a..1e91911c02c 100644 --- a/app/assets/javascripts/network/network_bundle.js +++ b/app/assets/javascripts/network/network_bundle.js @@ -2,13 +2,9 @@ /* global Network */ /* global ShortcutsNetwork */ -// This is a manifest file that'll be compiled into including all the files listed below. -// Add new JavaScript code in separate files in this directory and they'll automatically -// be included in the compiled file accessible from http://example.com/assets/application.js -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// the compiled file. -// -/*= require_tree . */ +// require everything else in this directory +function requireAll(context) { return context.keys().map(context); } +requireAll(require.context('.', false, /^\.\/(?!network_bundle).*\.(js|es6)$/)); (function() { $(function() { diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 603db88567d..148d2382bb0 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -4,13 +4,14 @@ /* global Autosave */ /* global ResolveService */ -/*= require autosave */ -/*= require autosize */ -/*= require dropzone */ -/*= require dropzone_input */ -/*= require gfm_auto_complete */ -/*= require jquery.atwho */ -/*= require task_list */ +require('./autosave'); +window.autosize = require('vendor/autosize'); +window.Dropzone = require('dropzone'); +require('./dropzone_input'); +require('./gfm_auto_complete'); +require('vendor/jquery.caret'); // required by jquery.atwho +require('vendor/jquery.atwho'); +require('vendor/task_list'); (function() { var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; diff --git a/app/assets/javascripts/pipelines.js.es6 b/app/assets/javascripts/pipelines.js.es6 index 0b09ad113a3..f704551a548 100644 --- a/app/assets/javascripts/pipelines.js.es6 +++ b/app/assets/javascripts/pipelines.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable no-new, guard-for-in, no-restricted-syntax, no-continue, padded-blocks, no-param-reassign, max-len */ -//= require lib/utils/bootstrap_linked_tabs +require('./lib/utils/bootstrap_linked_tabs'); ((global) => { diff --git a/app/assets/javascripts/profile/profile_bundle.js b/app/assets/javascripts/profile/profile_bundle.js index f50802bdf2e..d7f3c9fd37e 100644 --- a/app/assets/javascripts/profile/profile_bundle.js +++ b/app/assets/javascripts/profile/profile_bundle.js @@ -1,7 +1,3 @@ -/* eslint-disable func-names, space-before-function-paren */ - -/*= require_tree . */ - -(function() { - -}).call(this); +// require everything else in this directory +function requireAll(context) { return context.keys().map(context); } +requireAll(require.context('.', false, /^\.\/(?!profile_bundle).*\.(js|es6)$/)); diff --git a/app/assets/javascripts/protected_branches/protected_branches_bundle.js b/app/assets/javascripts/protected_branches/protected_branches_bundle.js index 15b3affd469..ffb66caf5f4 100644 --- a/app/assets/javascripts/protected_branches/protected_branches_bundle.js +++ b/app/assets/javascripts/protected_branches/protected_branches_bundle.js @@ -1 +1,3 @@ -/*= require_tree . */ +// require everything else in this directory +function requireAll(context) { return context.keys().map(context); } +requireAll(require.context('.', false, /^\.\/(?!protected_branches_bundle).*\.(js|es6)$/)); diff --git a/app/assets/javascripts/shortcuts_blob.js b/app/assets/javascripts/shortcuts_blob.js index c26903038b4..41c00e2048b 100644 --- a/app/assets/javascripts/shortcuts_blob.js +++ b/app/assets/javascripts/shortcuts_blob.js @@ -2,7 +2,7 @@ /* global Shortcuts */ /* global Mousetrap */ -/*= require shortcuts */ +require('./shortcuts'); (function() { var 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; }, diff --git a/app/assets/javascripts/shortcuts_dashboard_navigation.js b/app/assets/javascripts/shortcuts_dashboard_navigation.js index 4549742bbcb..bc33d52a906 100644 --- a/app/assets/javascripts/shortcuts_dashboard_navigation.js +++ b/app/assets/javascripts/shortcuts_dashboard_navigation.js @@ -2,7 +2,7 @@ /* global Mousetrap */ /* global Shortcuts */ -/*= require shortcuts */ +require('./shortcuts'); (function() { var 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; }, diff --git a/app/assets/javascripts/shortcuts_find_file.js b/app/assets/javascripts/shortcuts_find_file.js index 3a81380eef0..775c3a5e9b7 100644 --- a/app/assets/javascripts/shortcuts_find_file.js +++ b/app/assets/javascripts/shortcuts_find_file.js @@ -2,7 +2,7 @@ /* global Mousetrap */ /* global ShortcutsNavigation */ -/*= require shortcuts_navigation */ +require('./shortcuts_navigation'); (function() { var 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; }, diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js index b892fbc3393..2823e43585c 100644 --- a/app/assets/javascripts/shortcuts_issuable.js +++ b/app/assets/javascripts/shortcuts_issuable.js @@ -4,8 +4,8 @@ /* global ShortcutsNavigation */ /* global sidebar */ -/*= require mousetrap */ -/*= require shortcuts_navigation */ +require('mousetrap'); +require('./shortcuts_navigation'); (function() { var 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; }, diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js index 0776d0a9b67..d35d1dd6bf2 100644 --- a/app/assets/javascripts/shortcuts_navigation.js +++ b/app/assets/javascripts/shortcuts_navigation.js @@ -2,7 +2,7 @@ /* global Mousetrap */ /* global Shortcuts */ -/*= require shortcuts */ +require('./shortcuts'); (function() { var 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; }, diff --git a/app/assets/javascripts/shortcuts_network.js b/app/assets/javascripts/shortcuts_network.js index ecc3fab84c3..6a73b48899b 100644 --- a/app/assets/javascripts/shortcuts_network.js +++ b/app/assets/javascripts/shortcuts_network.js @@ -2,7 +2,7 @@ /* global Mousetrap */ /* global ShortcutsNavigation */ -/*= require shortcuts_navigation */ +require('./shortcuts_navigation'); (function() { var 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; }, diff --git a/app/assets/javascripts/snippet/snippet_bundle.js b/app/assets/javascripts/snippet/snippet_bundle.js index 18512d179b3..a3f128f9315 100644 --- a/app/assets/javascripts/snippet/snippet_bundle.js +++ b/app/assets/javascripts/snippet/snippet_bundle.js @@ -1,7 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, semi, padded-blocks, max-len */ /* global ace */ -/*= require_tree . */ +// require everything else in this directory +function requireAll(context) { return context.keys().map(context); } +requireAll(require.context('.', false, /^\.\/(?!snippet_bundle).*\.(js|es6)$/)); (function() { $(function() { diff --git a/app/assets/javascripts/subbable_resource.js.es6 b/app/assets/javascripts/subbable_resource.js.es6 index 932120157a3..d8191605128 100644 --- a/app/assets/javascripts/subbable_resource.js.es6 +++ b/app/assets/javascripts/subbable_resource.js.es6 @@ -1,6 +1,3 @@ -//= require vue -//= require vue-resource - (() => { /* * SubbableResource can be extended to provide a pubsub-style service for one-off REST diff --git a/app/assets/javascripts/templates/issuable_template_selector.js.es6 b/app/assets/javascripts/templates/issuable_template_selector.js.es6 index bdec948fb63..8dce6ed9fbf 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js.es6 +++ b/app/assets/javascripts/templates/issuable_template_selector.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable prefer-const, comma-dangle, max-len, no-useless-return, object-curly-spacing, no-param-reassign, max-len */ /* global Api */ -/*= require ../blob/template_selector */ +require('../blob/template_selector'); ((global) => { class IssuableTemplateSelector extends gl.TemplateSelector { diff --git a/app/assets/javascripts/terminal/terminal_bundle.js.es6 b/app/assets/javascripts/terminal/terminal_bundle.js.es6 index 33d2c1e1a17..13cf3a10a38 100644 --- a/app/assets/javascripts/terminal/terminal_bundle.js.es6 +++ b/app/assets/javascripts/terminal/terminal_bundle.js.es6 @@ -1,7 +1,7 @@ -//= require xterm/encoding-indexes -//= require xterm/encoding -//= require xterm/xterm.js -//= require xterm/fit.js -//= require ./terminal.js +require('vendor/xterm/encoding-indexes.js'); +require('vendor/xterm/encoding.js'); +window.Terminal = require('vendor/xterm/xterm.js'); +require('vendor/xterm/fit.js'); +require('./terminal.js'); $(() => new gl.Terminal({ selector: '#terminal' })); diff --git a/app/assets/javascripts/users/calendar.js b/app/assets/javascripts/users/calendar.js index 578be7c3590..43ee6a9d9fd 100644 --- a/app/assets/javascripts/users/calendar.js +++ b/app/assets/javascripts/users/calendar.js @@ -33,7 +33,7 @@ date.setDate(date.getDate() + i); var day = date.getDay(); - var count = timestamps[dateFormat(date, 'yyyy-mm-dd')]; + var count = timestamps[date.format('yyyy-mm-dd')]; // Create a new group array if this is the first day of the week // or if is first object @@ -122,7 +122,7 @@ if (stamp.count > 0) { contribText = stamp.count + " contribution" + (stamp.count > 1 ? 's' : ''); } - dateText = dateFormat(date, 'mmm d, yyyy'); + dateText = date.format('mmm d, yyyy'); return contribText + "<br />" + (gl.utils.getDayName(date)) + " " + dateText; }; })(this)).attr('class', 'user-contrib-cell js-tooltip').attr('fill', (function(_this) { diff --git a/app/assets/javascripts/users/users_bundle.js b/app/assets/javascripts/users/users_bundle.js index f50802bdf2e..4cad60a59b1 100644 --- a/app/assets/javascripts/users/users_bundle.js +++ b/app/assets/javascripts/users/users_bundle.js @@ -1,7 +1,3 @@ -/* eslint-disable func-names, space-before-function-paren */ - -/*= require_tree . */ - -(function() { - -}).call(this); +// require everything else in this directory +function requireAll(context) { return context.keys().map(context); } +requireAll(require.context('.', false, /^\.\/(?!users_bundle).*\.(js|es6)$/)); diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_common_component/commit.js.es6 index 62a22e39a3b..4adad7bea31 100644 --- a/app/assets/javascripts/vue_common_component/commit.js.es6 +++ b/app/assets/javascripts/vue_common_component/commit.js.es6 @@ -1,5 +1,7 @@ -/*= require vue */ /* global Vue */ + +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; diff --git a/app/assets/javascripts/vue_pagination/index.js.es6 b/app/assets/javascripts/vue_pagination/index.js.es6 index 605824fa939..7f093b748fe 100644 --- a/app/assets/javascripts/vue_pagination/index.js.es6 +++ b/app/assets/javascripts/vue_pagination/index.js.es6 @@ -1,6 +1,8 @@ /* global Vue, gl */ /* eslint-disable no-param-reassign, no-plusplus */ +window.Vue = require('vue'); + ((gl) => { const PAGINATION_UI_BUTTON_LIMIT = 4; const UI_LIMIT = 6; diff --git a/app/assets/javascripts/vue_pipelines_index/index.js.es6 b/app/assets/javascripts/vue_pipelines_index/index.js.es6 index edd01f17a97..e1bebe0fe5b 100644 --- a/app/assets/javascripts/vue_pipelines_index/index.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/index.js.es6 @@ -1,24 +1,23 @@ /* global Vue, VueResource, gl */ -/*= require vue_common_component/commit */ -/*= require vue_pagination/index */ -/*= require vue-resource -/*= require boards/vue_resource_interceptor */ -/*= require ./status.js.es6 */ -/*= require ./store.js.es6 */ -/*= require ./pipeline_url.js.es6 */ -/*= require ./stage.js.es6 */ -/*= require ./stages.js.es6 */ -/*= require ./pipeline_actions.js.es6 */ -/*= require ./time_ago.js.es6 */ -/*= require ./pipelines.js.es6 */ +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); +require('../vue_common_component/commit'); +require('../vue_pagination/index'); +require('../boards/vue_resource_interceptor'); +require('./status'); +require('./store'); +require('./pipeline_url'); +require('./stage'); +require('./stages'); +require('./pipeline_actions'); +require('./time_ago'); +require('./pipelines'); (() => { const project = document.querySelector('.pipelines'); const entry = document.querySelector('.vue-pipelines-index'); const svgs = document.querySelector('.pipeline-svgs'); - Vue.use(VueResource); - if (!entry) return null; return new Vue({ el: entry, diff --git a/app/assets/javascripts/vue_pipelines_index/store.js.es6 b/app/assets/javascripts/vue_pipelines_index/store.js.es6 index 1982142853a..9f84df6c08a 100644 --- a/app/assets/javascripts/vue_pipelines_index/store.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/store.js.es6 @@ -1,6 +1,6 @@ /* global gl, Flash */ /* eslint-disable no-param-reassign, no-underscore-dangle */ -/*= require vue_realtime_listener/index.js */ +require('../vue_realtime_listener'); ((gl) => { const pageValues = (headers) => { diff --git a/app/assets/javascripts/wikis.js.es6 b/app/assets/javascripts/wikis.js.es6 index ecff5fd5bf4..ef99b2e92f0 100644 --- a/app/assets/javascripts/wikis.js.es6 +++ b/app/assets/javascripts/wikis.js.es6 @@ -1,9 +1,9 @@ /* eslint-disable no-param-reassign */ /* global Breakpoints */ -/*= require latinise */ -/*= require breakpoints */ -/*= require jquery.nicescroll */ +require('vendor/latinise'); +require('./breakpoints'); +require('vendor/jquery.nicescroll'); ((global) => { const dasherize = str => str.replace(/[_\s]+/g, '-'); diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js index e09b59dd5aa..a1c3a19a3e9 100644 --- a/app/assets/javascripts/zen_mode.js +++ b/app/assets/javascripts/zen_mode.js @@ -6,11 +6,11 @@ // /*= provides zen_mode:enter */ /*= provides zen_mode:leave */ -// -/*= require jquery.scrollTo */ -/*= require dropzone */ -/*= require mousetrap */ -/*= require mousetrap/pause */ + +require('vendor/jquery.scrollTo'); +window.Dropzone = require('dropzone'); +require('mousetrap'); +require('mousetrap/plugins/pause/mousetrap-pause'); // // ### Events diff --git a/app/helpers/javascript_helper.rb b/app/helpers/javascript_helper.rb index 0e456214d37..64284910d4d 100644 --- a/app/helpers/javascript_helper.rb +++ b/app/helpers/javascript_helper.rb @@ -2,4 +2,7 @@ module JavascriptHelper def page_specific_javascript_tag(js) javascript_include_tag asset_path(js), { "data-turbolinks-track" => true } end + def page_specific_javascript_bundle_tag(js) + javascript_include_tag(*webpack_asset_paths(js), { "data-turbolinks-track" => true }) + end end diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 3096f0ee19e..0d9f838e804 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -28,7 +28,7 @@ = stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "print", media: "print" - = javascript_include_tag "application" + = javascript_include_tag(*webpack_asset_paths("application")) - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts diff --git a/app/views/profiles/_head.html.haml b/app/views/profiles/_head.html.haml index 943ebdaeffe..1df04ea614e 100644 --- a/app/views/profiles/_head.html.haml +++ b/app/views/profiles/_head.html.haml @@ -1,3 +1,3 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/cropper.js') - = page_specific_javascript_tag('profile/profile_bundle.js') + = page_specific_javascript_bundle_tag('profile') diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index a5dcd93f42e..8853801016b 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -2,7 +2,7 @@ - page_title "Edit", @blob.path, @ref - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') - = page_specific_javascript_tag('blob_edit/blob_edit_bundle.js') + = page_specific_javascript_bundle_tag('blob_edit') = render "projects/commits/head" %div{ class: container_class } diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml index b6ed9518c48..e0ce8cc9601 100644 --- a/app/views/projects/blob/new.html.haml +++ b/app/views/projects/blob/new.html.haml @@ -1,7 +1,7 @@ - page_title "New File", @path.presence, @ref - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') - = page_specific_javascript_tag('blob_edit/blob_edit_bundle.js') + = page_specific_javascript_bundle_tag('blob_edit') %h3.page-title New File diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml index 356bd50f7f3..2d1f377a6dd 100644 --- a/app/views/projects/boards/_show.html.haml +++ b/app/views/projects/boards/_show.html.haml @@ -3,8 +3,8 @@ - page_title "Boards" - content_for :page_specific_javascripts do - = page_specific_javascript_tag('boards/boards_bundle.js') - = page_specific_javascript_tag('boards/test_utils/simulate_drag.js') if Rails.env.test? + = page_specific_javascript_bundle_tag('boards') + = page_specific_javascript_bundle_tag('boards_test') if Rails.env.test? %script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board" %script#js-board-list-template{ type: "text/x-template" }= render "projects/boards/components/board_list" diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml index 479ce44f378..5405ff16bea 100644 --- a/app/views/projects/cycle_analytics/show.html.haml +++ b/app/views/projects/cycle_analytics/show.html.haml @@ -1,7 +1,7 @@ - @no_container = true - page_title "Cycle Analytics" - content_for :page_specific_javascripts do - = page_specific_javascript_tag("cycle_analytics/cycle_analytics_bundle.js") + = page_specific_javascript_bundle_tag('cycle_analytics') = render "projects/pipelines/head" diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 8c728eb0f6a..1f27d41ddd9 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -3,7 +3,7 @@ = render "projects/pipelines/head" - content_for :page_specific_javascripts do - = page_specific_javascript_tag("environments/environments_bundle.js") + = page_specific_javascript_bundle_tag("environments") #environments-list-view{ data: { environments_data: environments_list_data, "can-create-deployment" => can?(current_user, :create_deployment, @project).to_s, diff --git a/app/views/projects/environments/terminal.html.haml b/app/views/projects/environments/terminal.html.haml index 431253c1299..1d49e9cbaf7 100644 --- a/app/views/projects/environments/terminal.html.haml +++ b/app/views/projects/environments/terminal.html.haml @@ -4,7 +4,7 @@ - content_for :page_specific_javascripts do = stylesheet_link_tag "xterm/xterm" - = page_specific_javascript_tag("terminal/terminal_bundle.js") + = page_specific_javascript_bundle_tag("terminal") %div{ class: container_class } .top-area diff --git a/app/views/projects/graphs/_head.html.haml b/app/views/projects/graphs/_head.html.haml index 1a62a6a809c..67018aaa2ac 100644 --- a/app/views/projects/graphs/_head.html.haml +++ b/app/views/projects/graphs/_head.html.haml @@ -5,8 +5,8 @@ %ul{ class: (container_class) } - content_for :page_specific_javascripts do - = page_specific_javascript_tag('lib/chart.js') - = page_specific_javascript_tag('graphs/graphs_bundle.js') + = page_specific_javascript_bundle_tag('lib_chart') + = page_specific_javascript_bundle_tag('graphs') = nav_link(action: :show) do = link_to 'Contributors', namespace_project_graph_path = nav_link(action: :commits) do diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index 18e8372ecab..2d1671a89df 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -7,7 +7,7 @@ = render "projects/issues/head" - content_for :page_specific_javascripts do - = page_specific_javascript_tag('filtered_search/filtered_search_bundle.js') + = page_specific_javascript_bundle_tag('filtered_search') = content_for :meta_tags do - if current_user diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 110dd11d1ce..134f3f09b36 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -3,7 +3,7 @@ - page_description @merge_request.description - page_card_attributes @merge_request.card_attributes - content_for :page_specific_javascripts do - = page_specific_javascript_tag('diff_notes/diff_notes_bundle.js') + = page_specific_javascript_bundle_tag('diff_notes') .merge-request{ 'data-url' => merge_request_path(@merge_request) } = render "projects/merge_requests/show/mr_title" diff --git a/app/views/projects/merge_requests/conflicts.html.haml b/app/views/projects/merge_requests/conflicts.html.haml index b8b87dcdcaf..9242a84f150 100644 --- a/app/views/projects/merge_requests/conflicts.html.haml +++ b/app/views/projects/merge_requests/conflicts.html.haml @@ -1,6 +1,6 @@ - page_title "Merge Conflicts", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests" - content_for :page_specific_javascripts do - = page_specific_javascript_tag('merge_conflicts/merge_conflicts_bundle.js') + = page_specific_javascript_bundle_tag('merge_conflicts') = page_specific_javascript_tag('lib/ace.js') = render "projects/merge_requests/show/mr_title" diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 7809e9c8c72..487943f1167 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -1,5 +1,5 @@ - content_for :page_specific_javascripts do - = page_specific_javascript_tag('merge_request_widget/ci_bundle.js') + = page_specific_javascript_bundle_tag('merge_request_widget') - status_class = @pipeline ? " ci-#{@pipeline.status}" : nil diff --git a/app/views/projects/merge_requests/widget/open/_check.html.haml b/app/views/projects/merge_requests/widget/open/_check.html.haml index 50086767446..909dc52fc06 100644 --- a/app/views/projects/merge_requests/widget/open/_check.html.haml +++ b/app/views/projects/merge_requests/widget/open/_check.html.haml @@ -1,5 +1,5 @@ - content_for :page_specific_javascripts do - = page_specific_javascript_tag('merge_request_widget/ci_bundle.js') + = page_specific_javascript_bundle_tag('merge_request_widget') %strong = icon("spinner spin") diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index d8951e69242..b88eef65cef 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -1,7 +1,7 @@ - page_title "Network", @ref - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/raphael.js') - = page_specific_javascript_tag('network/network_bundle.js') + = page_specific_javascript_bundle_tag('network') = render "projects/commits/head" = render "head" %div{ class: container_class } diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index df36279ed75..f776734556a 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -64,4 +64,4 @@ .vue-pipelines-index -= page_specific_javascript_tag('vue_pipelines_index/index.js') += page_specific_javascript_bundle_tag('vue_pipelines') diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 42e9bdbd30e..b3b419bd92d 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -1,6 +1,6 @@ - page_title "Protected branches" - content_for :page_specific_javascripts do - = page_specific_javascript_tag('protected_branches/protected_branches_bundle.js') + = page_specific_javascript_bundle_tag('protected_branches') .row.prepend-top-default.append-bottom-default .col-lg-3 diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml index 0c788032020..b5362a7d5d5 100644 --- a/app/views/shared/snippets/_form.html.haml +++ b/app/views/shared/snippets/_form.html.haml @@ -1,6 +1,6 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') - = page_specific_javascript_tag('snippet/snippet_bundle.js') + = page_specific_javascript_bundle_tag('snippet') .snippet-form-holder = form_for @snippet, url: url, html: { class: "form-horizontal snippet-form js-requires-input" } do |f| @@ -34,4 +34,3 @@ = link_to "Cancel", namespace_project_snippets_path(@project.namespace, @project), class: "btn btn-cancel" - else = link_to "Cancel", snippets_path(@project), class: "btn btn-cancel" - diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index fb25eed4f37..6f43d083e4a 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,8 +1,8 @@ - page_title @user.name - page_description @user.bio - content_for :page_specific_javascripts do - = page_specific_javascript_tag('lib/d3.js') - = page_specific_javascript_tag('users/users_bundle.js') + = page_specific_javascript_bundle_tag('lib_d3') + = page_specific_javascript_bundle_tag('users') - header_title @user.name, user_path(@user) - @no_container = true diff --git a/bin/teaspoon b/bin/teaspoon deleted file mode 100755 index 7c3b8dfc4ed..00000000000 --- a/bin/teaspoon +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env ruby -begin - load File.expand_path('../spring', __FILE__) -rescue LoadError => e - raise unless e.message.include?('spring') -end -require 'bundler/setup' -load Gem.bin_path('teaspoon', 'teaspoon') diff --git a/config/application.rb b/config/application.rb index 8ce549cebf6..4efe73c7798 100644 --- a/config/application.rb +++ b/config/application.rb @@ -80,6 +80,12 @@ module Gitlab # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql + # Configure webpack + config.webpack.config_file = "config/webpack.config.js" + config.webpack.output_dir = "public/assets/webpack" + config.webpack.public_path = "assets/webpack" + config.webpack.dev_server.enabled = false + # Enable the asset pipeline config.assets.enabled = true config.assets.paths << Gemojione.images_path @@ -91,26 +97,10 @@ module Gitlab config.assets.precompile << "katex.css" config.assets.precompile << "katex.js" config.assets.precompile << "xterm/xterm.css" - config.assets.precompile << "graphs/graphs_bundle.js" - config.assets.precompile << "users/users_bundle.js" - config.assets.precompile << "network/network_bundle.js" - config.assets.precompile << "profile/profile_bundle.js" - config.assets.precompile << "protected_branches/protected_branches_bundle.js" - config.assets.precompile << "diff_notes/diff_notes_bundle.js" - config.assets.precompile << "merge_request_widget/ci_bundle.js" - config.assets.precompile << "boards/boards_bundle.js" - config.assets.precompile << "cycle_analytics/cycle_analytics_bundle.js" - config.assets.precompile << "merge_conflicts/merge_conflicts_bundle.js" - config.assets.precompile << "boards/test_utils/simulate_drag.js" - config.assets.precompile << "environments/environments_bundle.js" - config.assets.precompile << "blob_edit/blob_edit_bundle.js" - config.assets.precompile << "snippet/snippet_bundle.js" - config.assets.precompile << "terminal/terminal_bundle.js" - config.assets.precompile << "filtered_search/filtered_search_bundle.js" - config.assets.precompile << "lib/utils/*.js" - config.assets.precompile << "lib/*.js" + config.assets.precompile << "lib/ace.js" + config.assets.precompile << "lib/cropper.js" + config.assets.precompile << "lib/raphael.js" config.assets.precompile << "u2f.js" - config.assets.precompile << "vue_pipelines_index/index.js" config.assets.precompile << "vendor/assets/fonts/*" # Version of your assets, change this if you want to expire all your assets diff --git a/config/dependency_decisions.yml b/config/dependency_decisions.yml index c11296975b7..aabe859730a 100644 --- a/config/dependency_decisions.yml +++ b/config/dependency_decisions.yml @@ -1,9 +1,9 @@ --- -# IGNORED GROUPS AND GEMS - - :ignore_group - development - :who: Connor Shea - :why: Development gems are not distributed with the final product and are therefore exempt. + :why: Development gems are not distributed with the final product and are therefore + exempt. :versions: [] :when: 2016-04-17 21:27:01.054140000 Z - - :ignore_group @@ -18,8 +18,6 @@ :why: Bundler is MIT licensed but will sometimes fail in CI. :versions: [] :when: 2016-05-02 06:42:08.045090000 Z - -# LICENSE WHITELIST - - :whitelist - MIT - :who: Connor Shea @@ -86,9 +84,6 @@ :why: https://opensource.org/licenses/BSD-2-Clause :versions: [] :when: 2016-07-26 21:24:07.248480000 Z - - -# LICENSE BLACKLIST - - :blacklist - GPLv2 - :who: Connor Shea @@ -107,9 +102,6 @@ :why: The OSL license is a copyleft license :versions: [] :when: 2016-10-28 11:02:15.540105000 Z - - -# GEM LICENSES - - :license - raphael-rails - MIT @@ -201,3 +193,112 @@ :why: https://github.com/jmcnevin/rubypants/blob/master/LICENSE.rdoc :versions: [] :when: 2016-05-02 05:56:50.696858000 Z +- - :approve + - after + - :who: Matt Lee + :why: https://github.com/Raynos/after/blob/master/LICENCE + :versions: [] + :when: 2017-01-14 20:00:32.473125000 Z +- - :approve + - amdefine + - :who: Matt Lee + :why: MIT License + :versions: [] + :when: 2017-01-14 20:08:31.810633000 Z +- - :approve + - base64id + - :who: Matt Lee + :why: https://github.com/faeldt/base64id/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:08:33.174760000 Z +- - :approve + - blob + - :who: Matt Lee + :why: https://github.com/webmodules/blob/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:08:34.564048000 Z +- - :approve + - callsite + - :who: Matt Lee + :why: https://github.com/tj/callsite/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:08:35.976025000 Z +- - :approve + - component-bind + - :who: Matt Lee + :why: https://github.com/component/bind/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:08:37.291219000 Z +- - :approve + - component-inherit + - :who: Matt Lee + :why: https://github.com/component/inherit/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:41.804804000 Z +- - :approve + - fsevents + - :who: Matt Lee + :why: https://github.com/strongloop/fsevents/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:50:20.037775000 Z +- - :approve + - indexof + - :who: Matt Lee + :why: https://github.com/component/indexof/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:43.209900000 Z +- - :approve + - is-integer + - :who: Matt Lee + :why: https://github.com/parshap/js-is-integer/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:44.540916000 Z +- - :approve + - jsonify + - :who: Matt Lee + :why: Public Domain - no formal license on this one. probably okay as its been + the same for along time. would prefer to see CC0 + :versions: [] + :when: 2017-01-14 20:10:45.857261000 Z +- - :approve + - object-component + - :who: Matt Lee + :why: https://github.com/component/object/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:47.190148000 Z +- - :approve + - optimist + - :who: Matt Lee + :why: https://github.com/substack/node-optimist/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:48.563077000 Z +- - :approve + - path-is-inside + - :who: Matt Lee + :why: https://github.com/domenic/path-is-inside/blob/master/LICENSE.txt + :versions: [] + :when: 2017-01-14 20:10:49.910497000 Z +- - :approve + - rc + - :who: Matt Lee + :why: https://github.com/dominictarr/rc/blob/master/LICENSE.MIT + :versions: [] + :when: 2017-01-14 20:10:51.244695000 Z +- - :approve + - ripemd160 + - :who: Matt Lee + :why: https://github.com/crypto-browserify/ripemd160/blob/master/LICENSE.md + :versions: [] + :when: 2017-01-14 20:10:52.560282000 Z +- - :approve + - select2 + - :who: Matt Lee + :why: https://github.com/select2/select2/blob/master/LICENSE.md + :versions: [] + :when: 2017-01-14 20:10:53.909618000 Z +- - :approve + - tweetnacl + - :who: Matt Lee + :why: https://github.com/dchest/tweetnacl-js/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:57.812077000 Z diff --git a/config/environments/development.rb b/config/environments/development.rb index 45a8c1add3e..168c434f261 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -22,6 +22,9 @@ Rails.application.configure do # Only use best-standards-support built into browsers config.action_dispatch.best_standards_support = :builtin + # Enable webpack dev server + config.webpack.dev_server.enabled = true + # Do not compress assets config.assets.compress = false diff --git a/config/karma.config.js b/config/karma.config.js new file mode 100644 index 00000000000..44229e2ee88 --- /dev/null +++ b/config/karma.config.js @@ -0,0 +1,21 @@ +var path = require('path'); +var webpackConfig = require('./webpack.config.js'); +var ROOT_PATH = path.resolve(__dirname, '..'); + +// Karma configuration +module.exports = function(config) { + config.set({ + basePath: ROOT_PATH, + browsers: ['PhantomJS'], + frameworks: ['jasmine'], + files: [ + { pattern: 'spec/javascripts/test_bundle.js', watched: false }, + { pattern: 'spec/javascripts/fixtures/**/*@(.json|.html|.html.raw)', included: false }, + ], + preprocessors: { + 'spec/javascripts/**/*.js?(.es6)': ['webpack', 'sourcemap'], + }, + webpack: webpackConfig, + webpackMiddleware: { stats: 'errors-only' }, + }); +}; diff --git a/config/webpack.config.js b/config/webpack.config.js new file mode 100644 index 00000000000..98b87462a94 --- /dev/null +++ b/config/webpack.config.js @@ -0,0 +1,124 @@ +'use strict'; + +var path = require('path'); +var webpack = require('webpack'); +var StatsPlugin = require('stats-webpack-plugin'); +var CompressionPlugin = require("compression-webpack-plugin"); + +var IS_PRODUCTION = process.env.NODE_ENV === 'production'; +var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1; +var ROOT_PATH = path.resolve(__dirname, '..'); + +// must match config.webpack.dev_server.port +var DEV_SERVER_PORT = 3808; + +var config = { + context: path.join(ROOT_PATH, 'app/assets/javascripts'), + entry: { + application: './application.js', + blob_edit: './blob_edit/blob_edit_bundle.js', + boards: './boards/boards_bundle.js', + boards_test: './boards/test_utils/simulate_drag.js', + cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js', + diff_notes: './diff_notes/diff_notes_bundle.js', + environments: './environments/environments_bundle.js', + filtered_search: './filtered_search/filtered_search_bundle.js', + graphs: './graphs/graphs_bundle.js', + merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js', + merge_request_widget: './merge_request_widget/ci_bundle.js', + network: './network/network_bundle.js', + profile: './profile/profile_bundle.js', + protected_branches: './protected_branches/protected_branches_bundle.js', + snippet: './snippet/snippet_bundle.js', + terminal: './terminal/terminal_bundle.js', + users: './users/users_bundle.js', + lib_chart: './lib/chart.js', + lib_d3: './lib/d3.js', + vue_pipelines: './vue_pipelines_index/index.js', + }, + + output: { + path: path.join(ROOT_PATH, 'public/assets/webpack'), + publicPath: '/assets/webpack/', + filename: IS_PRODUCTION ? '[name]-[chunkhash].js' : '[name].js' + }, + + devtool: 'inline-source-map', + + module: { + loaders: [ + { + test: /\.es6$/, + exclude: /node_modules/, + loader: 'babel-loader', + query: { + // "use strict" was broken in sprockets-es6 due to sprockets concatination method. + // many es5 strict errors which were never caught ended up in our es6 assets as a result. + // this hack is necessary until they can be fixed. + blacklist: ["useStrict"] + } + }, + { + test: /\.(js|es6)$/, + loader: 'imports-loader', + query: 'this=>window' + }, + { + test: /\.json$/, + loader: 'json-loader' + } + ] + }, + + plugins: [ + // manifest filename must match config.webpack.manifest_filename + // webpack-rails only needs assetsByChunkName to function properly + new StatsPlugin('manifest.json', { + chunkModules: false, + source: false, + chunks: false, + modules: false, + assets: true + }), + new CompressionPlugin({ + asset: '[path].gz[query]', + }), + ], + + resolve: { + extensions: ['', '.js', '.es6', '.js.es6'], + alias: { + '~': path.join(ROOT_PATH, 'app/assets/javascripts'), + 'bootstrap/js': 'bootstrap-sass/assets/javascripts/bootstrap', + 'emoji-aliases$': path.join(ROOT_PATH, 'fixtures/emojis/aliases.json'), + 'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'), + 'vue$': 'vue/dist/vue.js', + 'vue-resource$': 'vue-resource/dist/vue-resource.js' + } + } +} + +if (IS_PRODUCTION) { + config.devtool = 'source-map'; + config.plugins.push( + new webpack.NoErrorsPlugin(), + new webpack.optimize.UglifyJsPlugin({ + compress: { warnings: false } + }), + new webpack.DefinePlugin({ + 'process.env': { NODE_ENV: JSON.stringify('production') } + }), + new webpack.optimize.DedupePlugin(), + new webpack.optimize.OccurrenceOrderPlugin() + ); +} + +if (IS_DEV_SERVER) { + config.devServer = { + port: DEV_SERVER_PORT, + headers: { 'Access-Control-Allow-Origin': '*' } + }; + config.output.publicPath = '//localhost:' + DEV_SERVER_PORT + config.output.publicPath; +} + +module.exports = config; diff --git a/lib/tasks/gitlab/test.rake b/lib/tasks/gitlab/test.rake index 4d4e746503a..84810b489ce 100644 --- a/lib/tasks/gitlab/test.rake +++ b/lib/tasks/gitlab/test.rake @@ -6,7 +6,7 @@ namespace :gitlab do %W(rake rubocop), %W(rake spinach), %W(rake spec), - %W(rake teaspoon) + %W(rake karma) ] cmds.each do |cmd| diff --git a/lib/tasks/karma.rake b/lib/tasks/karma.rake new file mode 100644 index 00000000000..89812a179ec --- /dev/null +++ b/lib/tasks/karma.rake @@ -0,0 +1,25 @@ +unless Rails.env.production? + Rake::Task['karma'].clear if Rake::Task.task_defined?('karma') + + namespace :karma do + desc 'GitLab | Karma | Generate fixtures for JavaScript tests' + RSpec::Core::RakeTask.new(:fixtures) do |t| + ENV['NO_KNAPSACK'] = 'true' + t.pattern = 'spec/javascripts/fixtures/*.rb' + t.rspec_opts = '--format documentation' + end + + desc 'GitLab | Karma | Run JavaScript tests' + task :tests do + sh "npm run karma" do |ok, res| + abort('rake karma:tests failed') unless ok + end + end + end + + desc 'GitLab | Karma | Shortcut for karma:fixtures and karma:tests' + task :karma do + Rake::Task['karma:fixtures'].invoke + Rake::Task['karma:tests'].invoke + end +end diff --git a/lib/tasks/teaspoon.rake b/lib/tasks/teaspoon.rake deleted file mode 100644 index 08caedd7ff3..00000000000 --- a/lib/tasks/teaspoon.rake +++ /dev/null @@ -1,25 +0,0 @@ -unless Rails.env.production? - Rake::Task['teaspoon'].clear if Rake::Task.task_defined?('teaspoon') - - namespace :teaspoon do - desc 'GitLab | Teaspoon | Generate fixtures for JavaScript tests' - RSpec::Core::RakeTask.new(:fixtures) do |t| - ENV['NO_KNAPSACK'] = 'true' - t.pattern = 'spec/javascripts/fixtures/*.rb' - t.rspec_opts = '--format documentation' - end - - desc 'GitLab | Teaspoon | Run JavaScript tests' - task :tests do - require "teaspoon/console" - options = {} - abort('rake teaspoon:tests failed') if Teaspoon::Console.new(options).failures? - end - end - - desc 'GitLab | Teaspoon | Shortcut for teaspoon:fixtures and teaspoon:tests' - task :teaspoon do - Rake::Task['teaspoon:fixtures'].invoke - Rake::Task['teaspoon:tests'].invoke - end -end diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake index d3dcbd2c29b..3e01f91d32c 100644 --- a/lib/tasks/test.rake +++ b/lib/tasks/test.rake @@ -7,5 +7,5 @@ end unless Rails.env.production? desc "GitLab | Run all tests on CI with simplecov" - task test_ci: [:rubocop, :brakeman, :teaspoon, :spinach, :spec] + task test_ci: [:rubocop, :brakeman, :karma, :spinach, :spec] end diff --git a/package.json b/package.json index 49b8210e427..73fb487b973 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,35 @@ { "private": true, "scripts": { + "dev-server": "node_modules/.bin/webpack-dev-server --config config/webpack.config.js", "eslint": "eslint --max-warnings 0 --ext .js,.js.es6 .", "eslint-fix": "npm run eslint -- --fix", - "eslint-report": "npm run eslint -- --format html --output-file ./eslint-report.html" + "eslint-report": "npm run eslint -- --format html --output-file ./eslint-report.html", + "karma": "karma start config/karma.config.js --single-run", + "karma-start": "karma start config/karma.config.js" + }, + "dependencies": { + "babel": "^5.8.38", + "babel-core": "^5.8.38", + "babel-loader": "^5.4.2", + "bootstrap-sass": "3.3.6", + "compression-webpack-plugin": "^0.3.2", + "d3": "3.5.11", + "dropzone": "4.2.0", + "exports-loader": "^0.6.3", + "imports-loader": "^0.6.5", + "jquery": "2.2.1", + "jquery-ui": "github:jquery/jquery-ui#1.11.4", + "jquery-ujs": "1.2.1", + "json-loader": "^0.5.4", + "mousetrap": "1.4.6", + "select2": "3.5.2-browserify", + "stats-webpack-plugin": "^0.4.2", + "underscore": "1.8.3", + "vue": "2.0.3", + "vue-resource": "0.9.3", + "webpack": "^1.14.0", + "webpack-dev-server": "^1.16.2" }, "devDependencies": { "eslint": "^3.10.1", @@ -11,6 +37,13 @@ "eslint-plugin-filenames": "^1.1.0", "eslint-plugin-import": "^2.2.0", "eslint-plugin-jasmine": "^2.1.0", - "istanbul": "^0.4.5" + "istanbul": "^0.4.5", + "jasmine-core": "^2.5.2", + "jasmine-jquery": "^2.1.1", + "karma": "^1.3.0", + "karma-jasmine": "^1.1.0", + "karma-phantomjs-launcher": "^1.0.2", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "^1.8.0" } } diff --git a/spec/javascripts/.eslintrc b/spec/javascripts/.eslintrc index dcbcd014dc3..b3d191e15ab 100644 --- a/spec/javascripts/.eslintrc +++ b/spec/javascripts/.eslintrc @@ -22,7 +22,8 @@ }, "plugins": ["jasmine"], "rules": { - "prefer-arrow-callback": 0, - "func-names": 0 + "func-names": 0, + "no-console": 0, + "prefer-arrow-callback": 0 } } diff --git a/spec/javascripts/abuse_reports_spec.js.es6 b/spec/javascripts/abuse_reports_spec.js.es6 index cf19aa05031..6e23a7a0b56 100644 --- a/spec/javascripts/abuse_reports_spec.js.es6 +++ b/spec/javascripts/abuse_reports_spec.js.es6 @@ -1,5 +1,5 @@ -/*= require lib/utils/text_utility */ -/*= require abuse_reports */ +require('~/lib/utils/text_utility'); +require('~/abuse_reports'); ((global) => { describe('Abuse Reports', () => { diff --git a/spec/javascripts/activities_spec.js.es6 b/spec/javascripts/activities_spec.js.es6 index b3617a45bd4..aba16a03ce2 100644 --- a/spec/javascripts/activities_spec.js.es6 +++ b/spec/javascripts/activities_spec.js.es6 @@ -1,9 +1,8 @@ /* eslint-disable no-unused-expressions, comma-spacing, prefer-const, no-prototype-builtins, semi, no-new, keyword-spacing, no-plusplus, no-shadow, max-len */ -/*= require js.cookie.js */ -/*= require jquery.endless-scroll.js */ -/*= require pager */ -/*= require activities */ +require('vendor/jquery.endless-scroll.js'); +require('~/pager'); +require('~/activities'); (() => { window.gon || (window.gon = {}); diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index faba2837d41..672f6f33ad3 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -1,10 +1,8 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, padded-blocks, max-len */ /* global AwardsHandler */ -/*= require awards_handler */ -/*= require jquery */ -/*= require js.cookie */ -/*= require ./fixtures/emoji_menu */ +require('~/awards_handler'); +require('./fixtures/emoji_menu'); (function() { var awardsHandler, lazyAssert, urlRoot; diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js index e77d732a32a..3b29579e70e 100644 --- a/spec/javascripts/behaviors/autosize_spec.js +++ b/spec/javascripts/behaviors/autosize_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, comma-dangle, no-return-assign, padded-blocks, max-len */ -/*= require behaviors/autosize */ +require('~/behaviors/autosize'); (function() { describe('Autosize behavior', function() { diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index 1a1f34cfdc0..247eb5f70ea 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, comma-dangle, jasmine/no-spec-dupes, new-cap, padded-blocks, max-len */ -/*= require behaviors/quick_submit */ +require('~/behaviors/quick_submit'); (function() { describe('Quick Submit behavior', function() { diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index 1f62591c06d..fd098196e7d 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -/*= require behaviors/requires_input */ +require('~/behaviors/requires_input'); (function() { describe('requiresInput', function() { diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index b3a1afa28a5..8f8f6d22066 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -6,19 +6,14 @@ /* global listObj */ /* global listObjDuplicate */ -//= require jquery -//= require jquery_ujs -//= require js.cookie -//= require vue -//= require vue-resource -//= require lib/utils/url_utility -//= require boards/models/issue -//= require boards/models/label -//= require boards/models/list -//= require boards/models/user -//= require boards/services/board_service -//= require boards/stores/boards_store -//= require ./mock_data +require('~/lib/utils/url_utility'); +require('~/boards/models/issue'); +require('~/boards/models/label'); +require('~/boards/models/list'); +require('~/boards/models/user'); +require('~/boards/services/board_service'); +require('~/boards/stores/boards_store'); +require('./mock_data'); describe('Store', () => { beforeEach(() => { diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index c8a61a0a9b5..5514f34c828 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -2,19 +2,14 @@ /* global BoardService */ /* global ListIssue */ -//= require jquery -//= require jquery_ujs -//= require js.cookie -//= require vue -//= require vue-resource -//= require lib/utils/url_utility -//= require boards/models/issue -//= require boards/models/label -//= require boards/models/list -//= require boards/models/user -//= require boards/services/board_service -//= require boards/stores/boards_store -//= require ./mock_data +require('~/lib/utils/url_utility'); +require('~/boards/models/issue'); +require('~/boards/models/label'); +require('~/boards/models/list'); +require('~/boards/models/user'); +require('~/boards/services/board_service'); +require('~/boards/stores/boards_store'); +require('./mock_data'); describe('Issue model', () => { let issue; diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index 7d942ec3d65..31b49e3e27a 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -5,19 +5,14 @@ /* global List */ /* global listObj */ -//= require jquery -//= require jquery_ujs -//= require js.cookie -//= require vue -//= require vue-resource -//= require lib/utils/url_utility -//= require boards/models/issue -//= require boards/models/label -//= require boards/models/list -//= require boards/models/user -//= require boards/services/board_service -//= require boards/stores/boards_store -//= require ./mock_data +require('~/lib/utils/url_utility'); +require('~/boards/models/issue'); +require('~/boards/models/label'); +require('~/boards/models/list'); +require('~/boards/models/user'); +require('~/boards/services/board_service'); +require('~/boards/stores/boards_store'); +require('./mock_data'); describe('List model', () => { let list; diff --git a/spec/javascripts/boards/mock_data.js.es6 b/spec/javascripts/boards/mock_data.js.es6 index 8d3e2237fda..7a399b307ad 100644 --- a/spec/javascripts/boards/mock_data.js.es6 +++ b/spec/javascripts/boards/mock_data.js.es6 @@ -56,3 +56,8 @@ const boardsMockInterceptor = (request, next) => { status: 200 })); }; + +window.listObj = listObj; +window.listObjDuplicate = listObjDuplicate; +window.BoardsMockData = BoardsMockData; +window.boardsMockInterceptor = boardsMockInterceptor; diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 index ea953d0f5a5..54055b04f62 100644 --- a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 +++ b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 @@ -1,6 +1,10 @@ -//= require lib/utils/bootstrap_linked_tabs +require('~/lib/utils/bootstrap_linked_tabs'); (() => { + // TODO: remove this hack! + // PhantomJS causes spyOn to panic because replaceState isn't "writable" + const phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable; + describe('Linked Tabs', () => { preloadFixtures('static/linked_tabs.html.raw'); @@ -10,7 +14,9 @@ describe('when is initialized', () => { beforeEach(() => { - spyOn(window.history, 'replaceState').and.callFake(function () {}); + if (!phantomjs) { + spyOn(window.history, 'replaceState').and.callFake(function () {}); + } }); it('should activate the tab correspondent to the given action', () => { @@ -36,7 +42,7 @@ describe('on click', () => { it('should change the url according to the clicked tab', () => { - const historySpy = spyOn(history, 'replaceState').and.callFake(() => {}); + const historySpy = !phantomjs && spyOn(history, 'replaceState').and.callFake(() => {}); const linkedTabs = new window.gl.LinkedTabs({ // eslint-disable-line action: 'show', @@ -49,10 +55,12 @@ secondTab.click(); - expect(historySpy).toHaveBeenCalledWith({ - turbolinks: true, - url: newState, - }, document.title, newState); + if (historySpy) { + expect(historySpy).toHaveBeenCalledWith({ + turbolinks: true, + url: newState, + }, document.title, newState); + } }); }); }); diff --git a/spec/javascripts/build_spec.js.es6 b/spec/javascripts/build_spec.js.es6 index 0c556382980..d2a093df146 100644 --- a/spec/javascripts/build_spec.js.es6 +++ b/spec/javascripts/build_spec.js.es6 @@ -2,11 +2,10 @@ /* global Build */ /* global Turbolinks */ -//= require lib/utils/datetime_utility -//= require build -//= require breakpoints -//= require jquery.nicescroll -//= require turbolinks +require('~/lib/utils/datetime_utility'); +require('~/build'); +require('~/breakpoints'); +require('vendor/jquery.nicescroll'); describe('Build', () => { const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/builds/1`; diff --git a/spec/javascripts/dashboard_spec.js.es6 b/spec/javascripts/dashboard_spec.js.es6 index 3f6b328348d..501380693d4 100644 --- a/spec/javascripts/dashboard_spec.js.es6 +++ b/spec/javascripts/dashboard_spec.js.es6 @@ -1,9 +1,7 @@ /* eslint-disable no-new, padded-blocks */ -/*= require sidebar */ -/*= require jquery */ -/*= require js.cookie */ -/*= require lib/utils/text_utility */ +require('~/sidebar'); +require('~/lib/utils/text_utility'); ((global) => { describe('Dashboard', () => { diff --git a/spec/javascripts/datetime_utility_spec.js.es6 b/spec/javascripts/datetime_utility_spec.js.es6 index 8ece24555c5..d5eec10be42 100644 --- a/spec/javascripts/datetime_utility_spec.js.es6 +++ b/spec/javascripts/datetime_utility_spec.js.es6 @@ -1,4 +1,4 @@ -//= require lib/utils/datetime_utility +require('~/lib/utils/datetime_utility'); (() => { describe('Date time utils', () => { diff --git a/spec/javascripts/diff_comments_store_spec.js.es6 b/spec/javascripts/diff_comments_store_spec.js.es6 index 18805d26ac0..cf2f17de5ee 100644 --- a/spec/javascripts/diff_comments_store_spec.js.es6 +++ b/spec/javascripts/diff_comments_store_spec.js.es6 @@ -1,10 +1,9 @@ /* eslint-disable no-extra-semi, jasmine/no-global-setup, dot-notation, jasmine/no-expect-in-setup-teardown, max-len */ /* global CommentsStore */ -//= require vue -//= require diff_notes/models/discussion -//= require diff_notes/models/note -//= require diff_notes/stores/comments +require('~/diff_notes/models/discussion'); +require('~/diff_notes/models/note'); +require('~/diff_notes/stores/comments'); (() => { function createDiscussion(noteId = 1, resolved = true) { diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 index 056e4d41e93..b1838045a06 100644 --- a/spec/javascripts/environments/environment_actions_spec.js.es6 +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -1,5 +1,4 @@ -//= require vue -//= require environments/components/environment_actions +require('~/environments/components/environment_actions'); describe('Actions Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 index 950a5d53fad..a6a587e69f5 100644 --- a/spec/javascripts/environments/environment_external_url_spec.js.es6 +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -1,5 +1,4 @@ -//= require vue -//= require environments/components/environment_external_url +require('~/environments/components/environment_external_url'); describe('External URL Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index c178b9cc1ec..9858f346c83 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,6 +1,5 @@ -//= require vue -//= require timeago -//= require environments/components/environment_item +window.timeago = require('vendor/timeago'); +require('~/environments/components/environment_item'); describe('Environment item', () => { preloadFixtures('static/environments/table.html.raw'); diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 index 21241116e29..8c7e1e912b4 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js.es6 +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -1,5 +1,5 @@ -//= require vue -//= require environments/components/environment_rollback +require('~/environments/components/environment_rollback'); + describe('Rollback Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 index bb998a32f32..2dfce5ba824 100644 --- a/spec/javascripts/environments/environment_stop_spec.js.es6 +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -1,5 +1,5 @@ -//= require vue -//= require environments/components/environment_stop +require('~/environments/components/environment_stop'); + describe('Stop Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 17c00acf63e..9a8300d3832 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,8 +1,7 @@ /* global environmentsList */ -//= require vue -//= require environments/stores/environments_store -//= require ./mock_data +require('~/environments/stores/environments_store'); +require('./mock_data'); (() => { describe('Store', () => { diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 9e16bc3e6a5..563414d0b1a 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -1,4 +1,5 @@ /* eslint-disable no-unused-vars */ + const environmentsList = [ { id: 31, @@ -133,3 +134,5 @@ const environmentsList = [ updated_at: '2016-11-07T11:11:16.525Z', }, ]; + +window.environmentsList = environmentsList; diff --git a/spec/javascripts/extensions/array_spec.js.es6 b/spec/javascripts/extensions/array_spec.js.es6 index 2ec759c8e80..75372266808 100644 --- a/spec/javascripts/extensions/array_spec.js.es6 +++ b/spec/javascripts/extensions/array_spec.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -/*= require extensions/array */ +require('~/extensions/array'); (function() { describe('Array extensions', function() { diff --git a/spec/javascripts/extensions/element_spec.js.es6 b/spec/javascripts/extensions/element_spec.js.es6 index c5b86d35204..2d8a128ed33 100644 --- a/spec/javascripts/extensions/element_spec.js.es6 +++ b/spec/javascripts/extensions/element_spec.js.es6 @@ -1,4 +1,4 @@ -/*= require extensions/element */ +require('~/extensions/element'); (() => { describe('Element extensions', function () { diff --git a/spec/javascripts/extensions/jquery_spec.js b/spec/javascripts/extensions/jquery_spec.js index 91846bb9143..298832f6985 100644 --- a/spec/javascripts/extensions/jquery_spec.js +++ b/spec/javascripts/extensions/jquery_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -/*= require extensions/jquery */ +require('~/extensions/jquery'); (function() { describe('jQuery extensions', function() { diff --git a/spec/javascripts/extensions/object_spec.js.es6 b/spec/javascripts/extensions/object_spec.js.es6 index 3b71c255b30..2467ed78459 100644 --- a/spec/javascripts/extensions/object_spec.js.es6 +++ b/spec/javascripts/extensions/object_spec.js.es6 @@ -1,4 +1,4 @@ -/*= require extensions/object */ +require('~/extensions/object'); describe('Object extensions', () => { describe('assign', () => { diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 index ce61b73aa8a..96f33427213 100644 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 +++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 @@ -1,7 +1,7 @@ -//= require extensions/array -//= require filtered_search/dropdown_utils -//= require filtered_search/filtered_search_tokenizer -//= require filtered_search/filtered_search_dropdown_manager +require('~/extensions/array'); +require('~/filtered_search/dropdown_utils'); +require('~/filtered_search/filtered_search_tokenizer'); +require('~/filtered_search/filtered_search_dropdown_manager'); (() => { describe('Dropdown Utils', () => { diff --git a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 index d0d27ceb4a6..0bc6689eba5 100644 --- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 @@ -1,6 +1,6 @@ -//= require extensions/array -//= require filtered_search/filtered_search_tokenizer -//= require filtered_search/filtered_search_dropdown_manager +require('~/extensions/array'); +require('~/filtered_search/filtered_search_tokenizer'); +require('~/filtered_search/filtered_search_dropdown_manager'); (() => { describe('Filtered Search Dropdown Manager', () => { diff --git a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 index 6df7c0e44ef..7df9d9ec1cb 100644 --- a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 @@ -1,5 +1,5 @@ -//= require extensions/array -//= require filtered_search/filtered_search_token_keys +require('~/extensions/array'); +require('~/filtered_search/filtered_search_token_keys'); (() => { describe('Filtered Search Token Keys', () => { diff --git a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6 index ac7f8e9cbcd..84c0e9cbfe2 100644 --- a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6 @@ -1,6 +1,6 @@ -//= require extensions/array -//= require filtered_search/filtered_search_token_keys -//= require filtered_search/filtered_search_tokenizer +require('~/extensions/array'); +require('~/filtered_search/filtered_search_token_keys'); +require('~/filtered_search/filtered_search_tokenizer'); (() => { describe('Filtered Search Tokenizer', () => { diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6 index d11b1182d9a..83e1638cdc6 100644 --- a/spec/javascripts/gl_dropdown_spec.js.es6 +++ b/spec/javascripts/gl_dropdown_spec.js.es6 @@ -1,11 +1,9 @@ /* eslint-disable comma-dangle, prefer-const, no-param-reassign, no-plusplus, semi, no-unused-expressions, arrow-spacing, max-len */ /* global Turbolinks */ -/*= require jquery */ -/*= require gl_dropdown */ -/*= require turbolinks */ -/*= require lib/utils/common_utils */ -/*= require lib/utils/type_utility */ +require('~/gl_dropdown'); +require('~/lib/utils/common_utils'); +require('~/lib/utils/type_utility'); (() => { const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; @@ -44,6 +42,7 @@ describe('Dropdown', function describeDropdown() { preloadFixtures('static/gl_dropdown.html.raw'); + loadJSONFixtures('projects.json'); function initDropDown(hasRemote, isFilterable) { this.dropdownButtonElement = $('#js-project-dropdown', this.dropdownContainerElement).glDropdown({ diff --git a/spec/javascripts/gl_field_errors_spec.js.es6 b/spec/javascripts/gl_field_errors_spec.js.es6 index e5d934540af..51ba59df671 100644 --- a/spec/javascripts/gl_field_errors_spec.js.es6 +++ b/spec/javascripts/gl_field_errors_spec.js.es6 @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, arrow-body-style, indent, padded-blocks */ -//= require jquery -//= require gl_field_errors +require('~/gl_field_errors'); ((global) => { preloadFixtures('static/gl_field_errors.html.raw'); diff --git a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js index bc5cbeb6a40..88aaaa0471b 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js @@ -3,7 +3,7 @@ /* global ContributorsGraph */ /* global ContributorsMasterGraph */ -//= require graphs/stat_graph_contributors_graph +require('~/graphs/stat_graph_contributors_graph'); describe("ContributorsGraph", function () { describe("#set_x_domain", function () { diff --git a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js index 751f3d175e2..671b0ae391c 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js @@ -1,7 +1,7 @@ /* eslint-disable quotes, padded-blocks, no-var, camelcase, object-curly-spacing, semi, indent, object-property-newline, comma-dangle, comma-spacing, spaced-comment, max-len, key-spacing, vars-on-top, quote-props, no-multi-spaces */ /* global ContributorsStatGraphUtil */ -//= require graphs/stat_graph_contributors_util +require('~/graphs/stat_graph_contributors_util'); describe("ContributorsStatGraphUtil", function () { diff --git a/spec/javascripts/graphs/stat_graph_spec.js b/spec/javascripts/graphs/stat_graph_spec.js index 0da124632ae..5b3b7c9222a 100644 --- a/spec/javascripts/graphs/stat_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_spec.js @@ -1,7 +1,7 @@ /* eslint-disable quotes, padded-blocks, semi */ /* global StatGraph */ -//= require graphs/stat_graph +require('~/graphs/stat_graph'); describe("StatGraph", function () { diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index b5262afa1cf..a281502b6ba 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, padded-blocks, no-var */ -/*= require header */ -/*= require lib/utils/text_utility */ -/*= require jquery */ + +require('~/header'); +require('~/lib/utils/text_utility'); (function() { diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6 index 917a6267b92..d846c242b1e 100644 --- a/spec/javascripts/issuable_spec.js.es6 +++ b/spec/javascripts/issuable_spec.js.es6 @@ -1,8 +1,7 @@ /* global Issuable */ /* global Turbolinks */ -//= require issuable -//= require turbolinks +require('~/issuable'); (() => { const BASE_URL = '/user/project/issues?scope=all&state=closed'; diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index eb07421826c..d1d6d5e22cb 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -1,8 +1,8 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-use-before-define, indent, no-trailing-spaces, comma-dangle, padded-blocks, max-len */ /* global Issue */ -/*= require lib/utils/text_utility */ -/*= require issue */ +require('~/lib/utils/text_utility'); +require('~/issue'); (function() { var INVALID_URL = 'http://goesnowhere.nothing/whereami'; diff --git a/spec/javascripts/labels_issue_sidebar_spec.js.es6 b/spec/javascripts/labels_issue_sidebar_spec.js.es6 index e3146559a4a..61ccef42cd8 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js.es6 +++ b/spec/javascripts/labels_issue_sidebar_spec.js.es6 @@ -2,17 +2,15 @@ /* global IssuableContext */ /* global LabelsSelect */ -//= require lib/utils/type_utility -//= require jquery -//= require bootstrap -//= require gl_dropdown -//= require select2 -//= require jquery.nicescroll -//= require api -//= require create_label -//= require issuable_context -//= require users_select -//= require labels_select +require('~/lib/utils/type_utility'); +require('~/gl_dropdown'); +require('select2'); +require('vendor/jquery.nicescroll'); +require('~/api'); +require('~/create_label'); +require('~/issuable_context'); +require('~/users_select'); +require('~/labels_select'); (() => { let saveLabelCount = 0; diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index 031f9ca03c9..9e8456c03aa 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -1,4 +1,4 @@ -//= require lib/utils/common_utils +require('~/lib/utils/common_utils'); (() => { describe('common_utils', () => { @@ -10,9 +10,9 @@ // IE11 will return a relative pathname while other browsers will return a full pathname. // parseUrl uses an anchor element for parsing an url. With relative urls, the anchor // element will create an absolute url relative to the current execution context. - // The JavaScript test suite is executed at '/teaspoon' which will lead to an absolute - // url starting with '/teaspoon'. - expect(gl.utils.parseUrl('" test="asf"').pathname).toEqual('/teaspoon/%22%20test=%22asf%22'); + // The JavaScript test suite is executed at '/' which will lead to an absolute url + // starting with '/'. + expect(gl.utils.parseUrl('" test="asf"').pathname).toContain('/%22%20test=%22asf%22'); }); }); @@ -42,9 +42,13 @@ }); describe('gl.utils.getParameterByName', () => { + beforeEach(() => { + window.history.pushState({}, null, '?scope=all&p=2'); + }); + it('should return valid parameter', () => { - const value = gl.utils.getParameterByName('reporter'); - expect(value).toBe('Console'); + const value = gl.utils.getParameterByName('scope'); + expect(value).toBe('all'); }); it('should return invalid parameter', () => { diff --git a/spec/javascripts/lib/utils/text_utility_spec.js.es6 b/spec/javascripts/lib/utils/text_utility_spec.js.es6 index e97356b65d5..976e24c4ea5 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js.es6 +++ b/spec/javascripts/lib/utils/text_utility_spec.js.es6 @@ -1,4 +1,4 @@ -//= require lib/utils/text_utility +require('~/lib/utils/text_utility'); (() => { describe('text_utility', () => { diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js index 31f516b41bf..be80e06af53 100644 --- a/spec/javascripts/line_highlighter_spec.js +++ b/spec/javascripts/line_highlighter_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, no-var, no-param-reassign, quotes, prefer-template, no-else-return, new-cap, dot-notation, no-return-assign, comma-dangle, no-new, one-var, one-var-declaration-per-line, no-plusplus, jasmine/no-spec-dupes, no-underscore-dangle, padded-blocks, max-len */ /* global LineHighlighter */ -/*= require line_highlighter */ +require('~/line_highlighter'); (function() { describe('LineHighlighter', function() { diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index 9b232617fe5..f87e87f4204 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, no-return-assign, padded-blocks */ /* global MergeRequest */ -/*= require merge_request */ +require('~/merge_request'); (function() { describe('MergeRequest', function() { diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 98201fb98ed..377acd5a3aa 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -1,11 +1,15 @@ /* eslint-disable no-var, comma-dangle, object-shorthand */ -/*= require merge_request_tabs */ -//= require breakpoints -//= require lib/utils/common_utils -//= require jquery.scrollTo +require('~/merge_request_tabs'); +require('~/breakpoints'); +require('~/lib/utils/common_utils'); +require('vendor/jquery.scrollTo'); (function () { + // TODO: remove this hack! + // PhantomJS causes spyOn to panic because replaceState isn't "writable" + const phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable; + describe('MergeRequestTabs', function () { var stubLocation = {}; var setLocation = function (stubs) { @@ -22,9 +26,11 @@ this.class = new gl.MergeRequestTabs({ stubLocation: stubLocation }); setLocation(); - this.spies = { - history: spyOn(window.history, 'replaceState').and.callFake(function () {}) - }; + if (!phantomjs) { + this.spies = { + history: spyOn(window.history, 'replaceState').and.callFake(function () {}) + }; + } }); describe('#activateTab', function () { @@ -98,10 +104,12 @@ pathname: '/foo/bar/merge_requests/1' }); newState = this.subject('commits'); - expect(this.spies.history).toHaveBeenCalledWith({ - turbolinks: true, - url: newState - }, document.title, newState); + if (!phantomjs) { + expect(this.spies.history).toHaveBeenCalledWith({ + turbolinks: true, + url: newState + }, document.title, newState); + } }); it('treats "show" like "notes"', function () { setLocation({ diff --git a/spec/javascripts/merge_request_widget_spec.js b/spec/javascripts/merge_request_widget_spec.js index 6f91529db00..c09cea28696 100644 --- a/spec/javascripts/merge_request_widget_spec.js +++ b/spec/javascripts/merge_request_widget_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, quotes, comma-dangle, dot-notation, indent, quote-props, no-var, padded-blocks, max-len */ -/*= require merge_request_widget */ -/*= require lib/utils/datetime_utility */ +require('~/merge_request_widget'); +require('~/lib/utils/datetime_utility'); (function() { describe('MergeRequestWidget', function() { diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 index a1c2fe3df37..a6994f6edf4 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable no-new */ -//= require flash -//= require mini_pipeline_graph_dropdown +require('~/flash'); +require('~/mini_pipeline_graph_dropdown'); (() => { describe('Mini Pipeline Graph Dropdown', () => { diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index e0dc549a9f4..0fdfa4d037b 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -1,8 +1,8 @@ /* eslint-disable space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-return-assign, quotes, padded-blocks, max-len */ /* global NewBranchForm */ -/*= require jquery-ui/autocomplete */ -/*= require new_branch_form */ +require('jquery-ui/ui/autocomplete'); +require('~/new_branch_form'); (function() { describe('Branch', function() { diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 9cdb0a5d5aa..295b44a3e74 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -1,10 +1,10 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, semi, padded-blocks, max-len */ /* global Notes */ -/*= require notes */ -/*= require autosize */ -/*= require gl_form */ -/*= require lib/utils/text_utility */ +require('~/notes'); +require('vendor/autosize'); +require('~/gl_form'); +require('~/lib/utils/text_utility'); (function() { window.gon || (window.gon = {}); diff --git a/spec/javascripts/pipelines_spec.js.es6 b/spec/javascripts/pipelines_spec.js.es6 index f0f9ad7430d..72770a702d3 100644 --- a/spec/javascripts/pipelines_spec.js.es6 +++ b/spec/javascripts/pipelines_spec.js.es6 @@ -1,4 +1,9 @@ -//= require pipelines +require('~/pipelines'); + +// Fix for phantomJS +if (!Element.prototype.matches && Element.prototype.webkitMatchesSelector) { + Element.prototype.matches = Element.prototype.webkitMatchesSelector; +} (() => { describe('Pipelines', () => { diff --git a/spec/javascripts/pretty_time_spec.js.es6 b/spec/javascripts/pretty_time_spec.js.es6 index 2e12d45f7a7..fe5317e05b1 100644 --- a/spec/javascripts/pretty_time_spec.js.es6 +++ b/spec/javascripts/pretty_time_spec.js.es6 @@ -1,4 +1,4 @@ -//= require lib/utils/pretty_time +require('~/lib/utils/pretty_time'); (() => { const PrettyTime = gl.PrettyTime; diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js index 27b071f266d..fa59a937c8e 100644 --- a/spec/javascripts/project_title_spec.js +++ b/spec/javascripts/project_title_spec.js @@ -1,14 +1,12 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-return-assign, no-param-reassign, no-var, new-cap, wrap-iife, no-unused-vars, quotes, jasmine/no-expect-in-setup-teardown, padded-blocks, max-len */ - /* global Project */ -/*= require bootstrap */ -/*= require select2 */ -/*= require lib/utils/type_utility */ -/*= require gl_dropdown */ -/*= require api */ -/*= require project_select */ -/*= require project */ +require('select2/select2.js'); +require('~/lib/utils/type_utility'); +require('~/gl_dropdown'); +require('~/api'); +require('~/project_select'); +require('~/project'); (function() { window.gon || (window.gon = {}); @@ -17,6 +15,8 @@ describe('Project Title', function() { preloadFixtures('static/project_title.html.raw'); + loadJSONFixtures('projects.json'); + beforeEach(function() { loadFixtures('static/project_title.html.raw'); return this.project = new Project(); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 0177d8e4e79..3b00f15795c 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -1,11 +1,8 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, semi, padded-blocks, max-len */ /* global Sidebar */ -/*= require right_sidebar */ -/*= require jquery */ -/*= require js.cookie */ - -/*= require extensions/jquery.js */ +require('~/right_sidebar'); +require('~/extensions/jquery.js'); (function() { var $aside, $icon, $labelsIcon, $page, $toggle, assertSidebarState; @@ -37,6 +34,8 @@ describe('RightSidebar', function() { var fixtureName = 'issues/open-issue.html.raw'; preloadFixtures(fixtureName); + loadJSONFixtures('todos.json'); + beforeEach(function() { loadFixtures(fixtureName); this.sidebar = new Sidebar; diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 2d3f44e7980..3be8f88f87b 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -1,13 +1,10 @@ /* eslint-disable space-before-function-paren, max-len, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, comma-dangle, object-shorthand, prefer-template, quotes, new-parens, vars-on-top, new-cap, padded-blocks, max-len */ -/*= require gl_dropdown */ -/*= require search_autocomplete */ -/*= require jquery */ -/*= require lib/utils/common_utils */ -/*= require lib/utils/type_utility */ -/*= require fuzzaldrin-plus */ -/*= require turbolinks */ -/*= require jquery.turbolinks */ +require('~/gl_dropdown'); +require('~/search_autocomplete'); +require('~/lib/utils/common_utils'); +require('~/lib/utils/type_utility'); +require('vendor/fuzzaldrin-plus'); (function() { var addBodyAttributes, assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget; @@ -117,13 +114,15 @@ preloadFixtures('static/search_autocomplete.html.raw'); beforeEach(function() { loadFixtures('static/search_autocomplete.html.raw'); - return widget = new gl.SearchAutocomplete; + widget = new gl.SearchAutocomplete; + // Prevent turbolinks from triggering within gl_dropdown + spyOn(window.Turbolinks, 'visit').and.returnValue(true); }); it('should show Dashboard specific dropdown menu', function() { var list; addBodyAttributes(); mockDashboardOptions(); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); return assertLinks(list, dashboardIssuesPath, dashboardMRsPath); }); @@ -131,7 +130,7 @@ var list; addBodyAttributes('group'); mockGroupOptions(); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); return assertLinks(list, groupIssuesPath, groupMRsPath); }); @@ -139,7 +138,7 @@ var list; addBodyAttributes('project'); mockProjectOptions(); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); return assertLinks(list, projectIssuesPath, projectMRsPath); }); @@ -148,7 +147,7 @@ addBodyAttributes('project'); mockProjectOptions(); widget.searchInput.val('help'); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); link = "a[href='" + projectIssuesPath + "/?assignee_id=" + userId + "']"; return expect(list.find(link).length).toBe(0); @@ -159,7 +158,7 @@ addBodyAttributes(); mockDashboardOptions(true); var submitSpy = spyOnEvent('form', 'submit'); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); widget.wrap.trigger($.Event('keydown', { which: DOWN })); var enterKeyEvent = $.Event('keydown', { which: ENTER }); widget.searchInput.trigger(enterKeyEvent); diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index ae5d639ad9c..3f7f6cf0113 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, no-return-assign, no-var, quotes, padded-blocks */ /* global ShortcutsIssuable */ -/*= require shortcuts_issuable */ +require('~/shortcuts_issuable'); (function() { describe('ShortcutsIssuable', function() { @@ -50,13 +50,8 @@ return expect(triggered).toBe(true); }); return it('triggers `focus`', function() { - var focused; - focused = false; - $(this.selector).on('focus', function() { - return focused = true; - }); this.shortcut.replyWithSelectedText(); - return expect(focused).toBe(true); + expect(document.activeElement).toBe(document.querySelector(this.selector)); }); }); describe('with a one-line selection', function() { diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js.es6 b/spec/javascripts/signin_tabs_memoizer_spec.js.es6 index c274b9c45f4..d83d9a57b42 100644 --- a/spec/javascripts/signin_tabs_memoizer_spec.js.es6 +++ b/spec/javascripts/signin_tabs_memoizer_spec.js.es6 @@ -1,4 +1,4 @@ -/*= require signin_tabs_memoizer */ +require('~/signin_tabs_memoizer'); ((global) => { describe('SigninTabsMemoizer', () => { diff --git a/spec/javascripts/smart_interval_spec.js.es6 b/spec/javascripts/smart_interval_spec.js.es6 index 39d236986b9..0c8051810cc 100644 --- a/spec/javascripts/smart_interval_spec.js.es6 +++ b/spec/javascripts/smart_interval_spec.js.es6 @@ -1,5 +1,4 @@ -//= require jquery -//= require smart_interval +require('~/smart_interval'); (() => { const DEFAULT_MAX_INTERVAL = 100; diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js deleted file mode 100644 index f8e3aca29fa..00000000000 --- a/spec/javascripts/spec_helper.js +++ /dev/null @@ -1,48 +0,0 @@ -/* eslint-disable space-before-function-paren */ -// PhantomJS (Teaspoons default driver) doesn't have support for -// Function.prototype.bind, which has caused confusion. Use this polyfill to -// avoid the confusion. -/*= require support/bind-poly */ - -// You can require your own javascript files here. By default this will include -// everything in application, however you may get better load performance if you -// require the specific files that are being used in the spec that tests them. -/*= require jquery */ -/*= require jquery.turbolinks */ -/*= require bootstrap */ -/*= require underscore */ - -// Teaspoon includes some support files, but you can use anything from your own -// support path too. -// require support/jasmine-jquery-1.7.0 -// require support/jasmine-jquery-2.0.0 -/*= require support/jasmine-jquery-2.1.0 */ - -// require support/sinon -// require support/your-support-file -// Deferring execution -// If you're using CommonJS, RequireJS or some other asynchronous library you can -// defer execution. Call Teaspoon.execute() after everything has been loaded. -// Simple example of a timeout: -// Teaspoon.defer = true -// setTimeout(Teaspoon.execute, 1000) -// Matching files -// By default Teaspoon will look for files that match -// _spec.{js,js.es6}. Add a filename_spec.js file in your spec path -// and it'll be included in the default suite automatically. If you want to -// customize suites, check out the configuration in teaspoon_env.rb -// Manifest -// If you'd rather require your spec files manually (to control order for -// instance) you can disable the suite matcher in the configuration and use this -// file as a manifest. -// For more information: http://github.com/modeset/teaspoon - -// set our fixtures path -jasmine.getFixtures().fixturesPath = '/teaspoon/fixtures'; -jasmine.getJSONFixtures().fixturesPath = '/teaspoon/fixtures'; - -// defined in ActionDispatch::TestRequest -// see https://github.com/rails/rails/blob/v4.2.7.1/actionpack/lib/action_dispatch/testing/test_request.rb#L7 -window.gl = window.gl || {}; -window.gl.TEST_HOST = 'http://test.host'; -window.gon = window.gon || {}; diff --git a/spec/javascripts/subbable_resource_spec.js.es6 b/spec/javascripts/subbable_resource_spec.js.es6 index 6a70dd856a7..ef1b32c2d19 100644 --- a/spec/javascripts/subbable_resource_spec.js.es6 +++ b/spec/javascripts/subbable_resource_spec.js.es6 @@ -1,9 +1,6 @@ /* eslint-disable max-len, arrow-parens, comma-dangle, no-plusplus */ -//= vue -//= vue-resource -//= require jquery -//= require subbable_resource +require('~/subbable_resource'); /* * Test that each rest verb calls the publish and subscribe function and passes the correct value back diff --git a/spec/javascripts/syntax_highlight_spec.js b/spec/javascripts/syntax_highlight_spec.js index 5984ce8ffd4..6c953f1b71c 100644 --- a/spec/javascripts/syntax_highlight_spec.js +++ b/spec/javascripts/syntax_highlight_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, quotes, padded-blocks */ -/*= require syntax_highlight */ +require('~/syntax_highlight'); (function() { describe('Syntax Highlighter', function() { diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js new file mode 100644 index 00000000000..cbe8abbbc08 --- /dev/null +++ b/spec/javascripts/test_bundle.js @@ -0,0 +1,42 @@ +// enable test fixtures +require('jasmine-jquery'); + +jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; +jasmine.getJSONFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; + +// include common libraries +window.$ = window.jQuery = require('jquery'); +window._ = require('underscore'); +window.Cookies = require('vendor/js.cookie'); +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); +require('jquery-ujs'); +require('vendor/turbolinks'); +require('vendor/jquery.turbolinks'); +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'); + +// stub expected globals +window.gl = window.gl || {}; +window.gl.TEST_HOST = 'http://test.host'; +window.gon = window.gon || {}; + +// render all of our tests +const testsContext = require.context('.', true, /_spec$/); +testsContext.keys().forEach(function (path) { + try { + testsContext(path); + } catch (err) { + console.error('[ERROR] WITH SPEC FILE: ', path); + console.error(err); + } +}); diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index dc2f4967985..ddbc1455057 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -2,11 +2,11 @@ /* global MockU2FDevice */ /* global U2FAuthenticate */ -/*= require u2f/authenticate */ -/*= require u2f/util */ -/*= require u2f/error */ -/*= require u2f */ -/*= require ./mock_u2f_device */ +require('~/u2f/authenticate'); +require('~/u2f/util'); +require('~/u2f/error'); +require('vendor/u2f'); +require('./mock_u2f_device'); (function() { describe('U2FAuthenticate', function() { @@ -25,19 +25,20 @@ document.querySelector('#js-login-2fa-device'), document.querySelector('.js-2fa-form') ); + + // bypass automatic form submission within renderAuthenticated + spyOn(this.component, 'renderAuthenticated').and.returnValue(true); + return this.component.start(); }); it('allows authenticating via a U2F device', function() { - var authenticatedMessage, deviceResponse, inProgressMessage; + var inProgressMessage; inProgressMessage = this.container.find("p"); expect(inProgressMessage.text()).toContain("Trying to communicate with your device"); this.u2fDevice.respondToAuthenticateRequest({ deviceData: "this is data from the device" }); - authenticatedMessage = this.container.find("p"); - deviceResponse = this.container.find('#js-device-response'); - expect(authenticatedMessage.text()).toContain('We heard back from your U2F device. You have been authenticated.'); - return expect(deviceResponse.val()).toBe('{"deviceData":"this is data from the device"}'); + expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}'); }); return describe("errors", function() { it("displays an error message", function() { @@ -51,7 +52,7 @@ return expect(errorMessage.text()).toContain("There was a problem communicating with your device"); }); return it("allows retrying authentication after an error", function() { - var authenticatedMessage, retryButton, setupButton; + var retryButton, setupButton; setupButton = this.container.find("#js-login-u2f-device"); setupButton.trigger('click'); this.u2fDevice.respondToAuthenticateRequest({ @@ -64,8 +65,7 @@ this.u2fDevice.respondToAuthenticateRequest({ deviceData: "this is data from the device" }); - authenticatedMessage = this.container.find("p"); - return expect(authenticatedMessage.text()).toContain("We heard back from your U2F device. You have been authenticated."); + expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}'); }); }); }); diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index ab4c5edd044..50522ff2391 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -2,11 +2,11 @@ /* global MockU2FDevice */ /* global U2FRegister */ -/*= require u2f/register */ -/*= require u2f/util */ -/*= require u2f/error */ -/*= require u2f */ -/*= require ./mock_u2f_device */ +require('~/u2f/register'); +require('~/u2f/util'); +require('~/u2f/error'); +require('vendor/u2f'); +require('./mock_u2f_device'); (function() { describe('U2FRegister', function() { diff --git a/spec/javascripts/vue_common_components/commit_spec.js.es6 b/spec/javascripts/vue_common_components/commit_spec.js.es6 index d6c6f786fb1..bbd914de4ea 100644 --- a/spec/javascripts/vue_common_components/commit_spec.js.es6 +++ b/spec/javascripts/vue_common_components/commit_spec.js.es6 @@ -1,4 +1,4 @@ -//= require vue_common_component/commit +require('~/vue_common_component/commit'); describe('Commit component', () => { let props; diff --git a/spec/javascripts/vue_pagination/pagination_spec.js.es6 b/spec/javascripts/vue_pagination/pagination_spec.js.es6 index 1a7f2bb5fb8..8935c474ee5 100644 --- a/spec/javascripts/vue_pagination/pagination_spec.js.es6 +++ b/spec/javascripts/vue_pagination/pagination_spec.js.es6 @@ -1,7 +1,5 @@ -//= require vue -//= require lib/utils/common_utils -//= require vue_pagination/index -/* global fixture, gl */ +require('~/lib/utils/common_utils'); +require('~/vue_pagination/index'); describe('Pagination component', () => { let component; @@ -17,7 +15,7 @@ describe('Pagination component', () => { }; it('should render and start at page 1', () => { - fixture.set('<div class="test-pagination-container"></div>'); + setFixtures('<div class="test-pagination-container"></div>'); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -40,7 +38,7 @@ describe('Pagination component', () => { }); it('should go to the previous page', () => { - fixture.set('<div class="test-pagination-container"></div>'); + setFixtures('<div class="test-pagination-container"></div>'); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -61,7 +59,7 @@ describe('Pagination component', () => { }); it('should go to the next page', () => { - fixture.set('<div class="test-pagination-container"></div>'); + setFixtures('<div class="test-pagination-container"></div>'); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -82,7 +80,7 @@ describe('Pagination component', () => { }); it('should go to the last page', () => { - fixture.set('<div class="test-pagination-container"></div>'); + setFixtures('<div class="test-pagination-container"></div>'); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -103,7 +101,7 @@ describe('Pagination component', () => { }); it('should go to the first page', () => { - fixture.set('<div class="test-pagination-container"></div>'); + setFixtures('<div class="test-pagination-container"></div>'); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -124,7 +122,7 @@ describe('Pagination component', () => { }); it('should do nothing', () => { - fixture.set('<div class="test-pagination-container"></div>'); + setFixtures('<div class="test-pagination-container"></div>'); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index f1c2edcc55c..7a68356376f 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -3,7 +3,7 @@ /* global Mousetrap */ /* global ZenMode */ -/*= require zen_mode */ +require('~/zen_mode'); (function() { var enterZen, escapeKeydown, exitZen; diff --git a/spec/teaspoon_env.rb b/spec/teaspoon_env.rb deleted file mode 100644 index 5ea020f313c..00000000000 --- a/spec/teaspoon_env.rb +++ /dev/null @@ -1,178 +0,0 @@ -Teaspoon.configure do |config| - # Determines where the Teaspoon routes will be mounted. Changing this to "/jasmine" would allow you to browse to - # `http://localhost:3000/jasmine` to run your tests. - config.mount_at = "/teaspoon" - - # Specifies the root where Teaspoon will look for files. If you're testing an engine using a dummy application it can - # be useful to set this to your engines root (e.g. `Teaspoon::Engine.root`). - # Note: Defaults to `Rails.root` if nil. - config.root = nil - - # Paths that will be appended to the Rails assets paths - # Note: Relative to `config.root`. - config.asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets"] - - # Fixtures are rendered through a controller, which allows using HAML, RABL/JBuilder, etc. Files in these paths will - # be rendered as fixtures. - config.fixture_paths = ["spec/javascripts/fixtures"] - - # SUITES - # - # You can modify the default suite configuration and create new suites here. Suites are isolated from one another. - # - # When defining a suite you can provide a name and a block. If the name is left blank, :default is assumed. You can - # omit various directives and the ones defined in the default suite will be used. - # - # To run a specific suite - # - in the browser: http://localhost/teaspoon/[suite_name] - # - with the rake task: rake teaspoon suite=[suite_name] - # - with the cli: teaspoon --suite=[suite_name] - config.suite do |suite| - # Specify the framework you would like to use. This allows you to select versions, and will do some basic setup for - # you -- which you can override with the directives below. This should be specified first, as it can override other - # directives. - # Note: If no version is specified, the latest is assumed. - # - # Versions: 1.3.1, 2.0.3, 2.1.3, 2.2.0 - suite.use_framework :jasmine, "2.2.0" - - # Specify a file matcher as a regular expression and all matching files will be loaded when the suite is run. These - # files need to be within an asset path. You can add asset paths using the `config.asset_paths`. - suite.matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.es6,es6}" - - # Load additional JS files, but requiring them in your spec helper is the preferred way to do this. - # suite.javascripts = [] - - # You can include your own stylesheets if you want to change how Teaspoon looks. - # Note: Spec related CSS can and should be loaded using fixtures. - # suite.stylesheets = ["teaspoon"] - - # This suites spec helper, which can require additional support files. This file is loaded before any of your test - # files are loaded. - suite.helper = "spec_helper" - - # Partial to be rendered in the head tag of the runner. You can use the provided ones or define your own by creating - # a `_boot.html.erb` in your fixtures path, and adjust the config to `"/boot"` for instance. - # - # Available: boot, boot_require_js - suite.boot_partial = "boot" - - # Partial to be rendered in the body tag of the runner. You can define your own to create a custom body structure. - suite.body_partial = "body" - - # Hooks allow you to use `Teaspoon.hook("fixtures")` before, after, or during your spec run. This will make a - # synchronous Ajax request to the server that will call all of the blocks you've defined for that hook name. - # suite.hook :fixtures, &proc{} - - # Determine whether specs loaded into the test harness should be embedded as individual script tags or concatenated - # into a single file. Similar to Rails' asset `debug: true` and `config.assets.debug = true` options. By default, - # Teaspoon expands all assets to provide more valuable stack traces that reference individual source files. - # suite.expand_assets = true - end - - # Example suite. Since we're just filtering to files already within the root test/javascripts, these files will also - # be run in the default suite -- but can be focused into a more specific suite. - # config.suite :targeted do |suite| - # suite.matcher = "spec/javascripts/targeted/*_spec.{js,js.coffee,coffee}" - # end - - # CONSOLE RUNNER SPECIFIC - # - # These configuration directives are applicable only when running via the rake task or command line interface. These - # directives can be overridden using the command line interface arguments or with ENV variables when using the rake - # task. - # - # Command Line Interface: - # teaspoon --driver=phantomjs --server-port=31337 --fail-fast=true --format=junit --suite=my_suite /spec/file_spec.js - # - # Rake: - # teaspoon DRIVER=phantomjs SERVER_PORT=31337 FAIL_FAST=true FORMATTERS=junit suite=my_suite - - # Specify which headless driver to use. Supports PhantomJS and Selenium Webdriver. - # - # Available: :phantomjs, :selenium, :capybara_webkit - # PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS - # Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver - # Capybara Webkit: https://github.com/modeset/teaspoon/wiki/Using-Capybara-Webkit - # config.driver = :phantomjs - - # Specify additional options for the driver. - # - # PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS - # Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver - # Capybara Webkit: https://github.com/modeset/teaspoon/wiki/Using-Capybara-Webkit - # config.driver_options = nil - - # Specify the timeout for the driver. Specs are expected to complete within this time frame or the run will be - # considered a failure. This is to avoid issues that can arise where tests stall. - # config.driver_timeout = 180 - - # Specify a server to use with Rack (e.g. thin, mongrel). If nil is provided Rack::Server is used. - # config.server = nil - - # Specify a port to run on a specific port, otherwise Teaspoon will use a random available port. - # config.server_port = nil - - # Timeout for starting the server in seconds. If your server is slow to start you may have to bump this, or you may - # want to lower this if you know it shouldn't take long to start. - # config.server_timeout = 20 - - # Force Teaspoon to fail immediately after a failing suite. Can be useful to make Teaspoon fail early if you have - # several suites, but in environments like CI this may not be desirable. - # config.fail_fast = true - - # Specify the formatters to use when outputting the results. - # Note: Output files can be specified by using `"junit>/path/to/output.xml"`. - # - # Available: :dot, :clean, :documentation, :json, :junit, :pride, :rspec_html, :snowday, :swayze_or_oprah, :tap, :tap_y, :teamcity - # config.formatters = [:dot] - - # Specify if you want color output from the formatters. - # config.color = true - - # Teaspoon pipes all console[log/debug/error] to $stdout. This is useful to catch places where you've forgotten to - # remove them, but in verbose applications this may not be desirable. - # config.suppress_log = false - - # COVERAGE REPORTS / THRESHOLD ASSERTIONS - # - # Coverage reports requires Istanbul (https://github.com/gotwarlost/istanbul) to add instrumentation to your code and - # display coverage statistics. - # - # Coverage configurations are similar to suites. You can define several, and use different ones under different - # conditions. - # - # To run with a specific coverage configuration - # - with the rake task: rake teaspoon USE_COVERAGE=[coverage_name] - # - with the cli: teaspoon --coverage=[coverage_name] - - # Specify that you always want a coverage configuration to be used. Otherwise, specify that you want coverage - # on the CLI. - # Set this to "true" or the name of your coverage config. - config.use_coverage = true - - # You can have multiple coverage configs by passing a name to config.coverage. - # e.g. config.coverage :ci do |coverage| - # The default coverage config name is :default. - config.coverage do |coverage| - # Which coverage reports Istanbul should generate. Correlates directly to what Istanbul supports. - # - # Available: text-summary, text, html, lcov, lcovonly, cobertura, teamcity - coverage.reports = ["text-summary", "html"] - - # The path that the coverage should be written to - when there's an artifact to write to disk. - # Note: Relative to `config.root`. - coverage.output_path = "coverage-javascript" - - # Assets to be ignored when generating coverage reports. Accepts an array of filenames or regular expressions. The - # default excludes assets from vendor, gems and support libraries. - coverage.ignore = [%r{vendor/}, %r{spec/}] - - # Various thresholds requirements can be defined, and those thresholds will be checked at the end of a run. If any - # aren't met the run will fail with a message. Thresholds can be defined as a percentage (0-100), or nil. - # coverage.statements = nil - # coverage.functions = nil - # coverage.branches = nil - # coverage.lines = nil - end -end diff --git a/vendor/assets/javascripts/date.format.js b/vendor/assets/javascripts/date.format.js index f5dc4abcd80..2c9b4825443 100644 --- a/vendor/assets/javascripts/date.format.js +++ b/vendor/assets/javascripts/date.format.js @@ -11,115 +11,122 @@ * The date defaults to the current date/time. * The mask defaults to dateFormat.masks.default. */ + (function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.dateFormat = factory()); + }(this, (function () { 'use strict'; + var dateFormat = function () { + var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, + timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, + timezoneClip = /[^-+\dA-Z]/g, + pad = function (val, len) { + val = String(val); + len = len || 2; + while (val.length < len) val = "0" + val; + return val; + }; -var dateFormat = function () { - var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, - timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, - timezoneClip = /[^-+\dA-Z]/g, - pad = function (val, len) { - val = String(val); - len = len || 2; - while (val.length < len) val = "0" + val; - return val; - }; + // Regexes and supporting functions are cached through closure + return function (date, mask, utc) { + var dF = dateFormat; - // Regexes and supporting functions are cached through closure - return function (date, mask, utc) { - var dF = dateFormat; + // You can't provide utc if you skip other args (use the "UTC:" mask prefix) + if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { + mask = date; + date = undefined; + } - // You can't provide utc if you skip other args (use the "UTC:" mask prefix) - if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { - mask = date; - date = undefined; - } + // Passing date through Date applies Date.parse, if necessary + date = date ? new Date(date) : new Date; + if (isNaN(date)) throw SyntaxError("invalid date"); - // Passing date through Date applies Date.parse, if necessary - date = date ? new Date(date) : new Date; - if (isNaN(date)) throw SyntaxError("invalid date"); + mask = String(dF.masks[mask] || mask || dF.masks["default"]); - mask = String(dF.masks[mask] || mask || dF.masks["default"]); + // Allow setting the utc argument via the mask + if (mask.slice(0, 4) == "UTC:") { + mask = mask.slice(4); + utc = true; + } - // Allow setting the utc argument via the mask - if (mask.slice(0, 4) == "UTC:") { - mask = mask.slice(4); - utc = true; - } + var _ = utc ? "getUTC" : "get", + d = date[_ + "Date"](), + D = date[_ + "Day"](), + m = date[_ + "Month"](), + y = date[_ + "FullYear"](), + H = date[_ + "Hours"](), + M = date[_ + "Minutes"](), + s = date[_ + "Seconds"](), + L = date[_ + "Milliseconds"](), + o = utc ? 0 : date.getTimezoneOffset(), + flags = { + d: d, + dd: pad(d), + ddd: dF.i18n.dayNames[D], + dddd: dF.i18n.dayNames[D + 7], + m: m + 1, + mm: pad(m + 1), + mmm: dF.i18n.monthNames[m], + mmmm: dF.i18n.monthNames[m + 12], + yy: String(y).slice(2), + yyyy: y, + h: H % 12 || 12, + hh: pad(H % 12 || 12), + H: H, + HH: pad(H), + M: M, + MM: pad(M), + s: s, + ss: pad(s), + l: pad(L, 3), + L: pad(L > 99 ? Math.round(L / 10) : L), + t: H < 12 ? "a" : "p", + tt: H < 12 ? "am" : "pm", + T: H < 12 ? "A" : "P", + TT: H < 12 ? "AM" : "PM", + Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), + o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), + S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] + }; - var _ = utc ? "getUTC" : "get", - d = date[_ + "Date"](), - D = date[_ + "Day"](), - m = date[_ + "Month"](), - y = date[_ + "FullYear"](), - H = date[_ + "Hours"](), - M = date[_ + "Minutes"](), - s = date[_ + "Seconds"](), - L = date[_ + "Milliseconds"](), - o = utc ? 0 : date.getTimezoneOffset(), - flags = { - d: d, - dd: pad(d), - ddd: dF.i18n.dayNames[D], - dddd: dF.i18n.dayNames[D + 7], - m: m + 1, - mm: pad(m + 1), - mmm: dF.i18n.monthNames[m], - mmmm: dF.i18n.monthNames[m + 12], - yy: String(y).slice(2), - yyyy: y, - h: H % 12 || 12, - hh: pad(H % 12 || 12), - H: H, - HH: pad(H), - M: M, - MM: pad(M), - s: s, - ss: pad(s), - l: pad(L, 3), - L: pad(L > 99 ? Math.round(L / 10) : L), - t: H < 12 ? "a" : "p", - tt: H < 12 ? "am" : "pm", - T: H < 12 ? "A" : "P", - TT: H < 12 ? "AM" : "PM", - Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), - o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), - S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] - }; + return mask.replace(token, function ($0) { + return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); + }); + }; + }(); - return mask.replace(token, function ($0) { - return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); - }); + // Some common format strings + dateFormat.masks = { + "default": "ddd mmm dd yyyy HH:MM:ss", + shortDate: "m/d/yy", + mediumDate: "mmm d, yyyy", + longDate: "mmmm d, yyyy", + fullDate: "dddd, mmmm d, yyyy", + shortTime: "h:MM TT", + mediumTime: "h:MM:ss TT", + longTime: "h:MM:ss TT Z", + isoDate: "yyyy-mm-dd", + isoTime: "HH:MM:ss", + isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", + isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" }; -}(); -// Some common format strings -dateFormat.masks = { - "default": "ddd mmm dd yyyy HH:MM:ss", - shortDate: "m/d/yy", - mediumDate: "mmm d, yyyy", - longDate: "mmmm d, yyyy", - fullDate: "dddd, mmmm d, yyyy", - shortTime: "h:MM TT", - mediumTime: "h:MM:ss TT", - longTime: "h:MM:ss TT Z", - isoDate: "yyyy-mm-dd", - isoTime: "HH:MM:ss", - isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", - isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" -}; + // Internationalization strings + dateFormat.i18n = { + dayNames: [ + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" + ], + monthNames: [ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" + ] + }; -// Internationalization strings -dateFormat.i18n = { - dayNames: [ - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" - ], - monthNames: [ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" - ] -}; + // For convenience... + Date.prototype.format = function (mask, utc) { + return dateFormat(this, mask, utc); + }; -// For convenience... -Date.prototype.format = function (mask, utc) { - return dateFormat(this, mask, utc); -}; + return dateFormat; +}))); diff --git a/vendor/assets/javascripts/es6-promise.auto.js b/vendor/assets/javascripts/es6-promise.auto.js index 19e6c13a655..b8887115a37 100644 --- a/vendor/assets/javascripts/es6-promise.auto.js +++ b/vendor/assets/javascripts/es6-promise.auto.js @@ -1154,6 +1154,3 @@ Promise.Promise = Promise; return Promise; }))); - -ES6Promise.polyfill(); -//# sourceMappingURL=es6-promise.auto.map diff --git a/vendor/assets/javascripts/jquery.atwho.js b/vendor/assets/javascripts/jquery.atwho.js new file mode 100644 index 00000000000..0d295ebe5af --- /dev/null +++ b/vendor/assets/javascripts/jquery.atwho.js @@ -0,0 +1,1202 @@ +/** + * at.js - 1.5.1 + * Copyright (c) 2016 chord.luo <chord.luo@gmail.com>; + * Homepage: http://ichord.github.com/At.js + * License: MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define(["jquery"], function (a0) { + return (factory(a0)); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(require("jquery")); + } else { + factory(jQuery); + } +}(this, function ($) { +var DEFAULT_CALLBACKS, KEY_CODE; + +KEY_CODE = { + DOWN: 40, + UP: 38, + ESC: 27, + TAB: 9, + ENTER: 13, + CTRL: 17, + A: 65, + P: 80, + N: 78, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + BACKSPACE: 8, + SPACE: 32 +}; + +DEFAULT_CALLBACKS = { + beforeSave: function(data) { + return Controller.arrayToDefaultHash(data); + }, + matcher: function(flag, subtext, should_startWithSpace, acceptSpaceBar) { + var _a, _y, match, regexp, space; + flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + if (should_startWithSpace) { + flag = '(?:^|\\s)' + flag; + } + _a = decodeURI("%C3%80"); + _y = decodeURI("%C3%BF"); + space = acceptSpaceBar ? "\ " : ""; + regexp = new RegExp(flag + "([A-Za-z" + _a + "-" + _y + "0-9_" + space + "\'\.\+\-]*)$|" + flag + "([^\\x00-\\xff]*)$", 'gi'); + match = regexp.exec(subtext); + if (match) { + return match[2] || match[1]; + } else { + return null; + } + }, + filter: function(query, data, searchKey) { + var _results, i, item, len; + _results = []; + for (i = 0, len = data.length; i < len; i++) { + item = data[i]; + if (~new String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase())) { + _results.push(item); + } + } + return _results; + }, + remoteFilter: null, + sorter: function(query, items, searchKey) { + var _results, i, item, len; + if (!query) { + return items; + } + _results = []; + for (i = 0, len = items.length; i < len; i++) { + item = items[i]; + item.atwho_order = new String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase()); + if (item.atwho_order > -1) { + _results.push(item); + } + } + return _results.sort(function(a, b) { + return a.atwho_order - b.atwho_order; + }); + }, + tplEval: function(tpl, map) { + var error, error1, template; + template = tpl; + try { + if (typeof tpl !== 'string') { + template = tpl(map); + } + return template.replace(/\$\{([^\}]*)\}/g, function(tag, key, pos) { + return map[key]; + }); + } catch (error1) { + error = error1; + return ""; + } + }, + highlighter: function(li, query) { + var regexp; + if (!query) { + return li; + } + regexp = new RegExp(">\\s*(\\w*?)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig'); + return li.replace(regexp, function(str, $1, $2, $3) { + return '> ' + $1 + '<strong>' + $2 + '</strong>' + $3 + ' <'; + }); + }, + beforeInsert: function(value, $li, e) { + return value; + }, + beforeReposition: function(offset) { + return offset; + }, + afterMatchFailed: function(at, el) {} +}; + +var App; + +App = (function() { + function App(inputor) { + this.currentFlag = null; + this.controllers = {}; + this.aliasMaps = {}; + this.$inputor = $(inputor); + this.setupRootElement(); + this.listen(); + } + + App.prototype.createContainer = function(doc) { + var ref; + if ((ref = this.$el) != null) { + ref.remove(); + } + return $(doc.body).append(this.$el = $("<div class='atwho-container'></div>")); + }; + + App.prototype.setupRootElement = function(iframe, asRoot) { + var error, error1; + if (asRoot == null) { + asRoot = false; + } + if (iframe) { + this.window = iframe.contentWindow; + this.document = iframe.contentDocument || this.window.document; + this.iframe = iframe; + } else { + this.document = this.$inputor[0].ownerDocument; + this.window = this.document.defaultView || this.document.parentWindow; + try { + this.iframe = this.window.frameElement; + } catch (error1) { + error = error1; + this.iframe = null; + if ($.fn.atwho.debug) { + throw new Error("iframe auto-discovery is failed.\nPlease use `setIframe` to set the target iframe manually.\n" + error); + } + } + } + return this.createContainer((this.iframeAsRoot = asRoot) ? this.document : document); + }; + + App.prototype.controller = function(at) { + var c, current, currentFlag, ref; + if (this.aliasMaps[at]) { + current = this.controllers[this.aliasMaps[at]]; + } else { + ref = this.controllers; + for (currentFlag in ref) { + c = ref[currentFlag]; + if (currentFlag === at) { + current = c; + break; + } + } + } + if (current) { + return current; + } else { + return this.controllers[this.currentFlag]; + } + }; + + App.prototype.setContextFor = function(at) { + this.currentFlag = at; + return this; + }; + + App.prototype.reg = function(flag, setting) { + var base, controller; + controller = (base = this.controllers)[flag] || (base[flag] = this.$inputor.is('[contentEditable]') ? new EditableController(this, flag) : new TextareaController(this, flag)); + if (setting.alias) { + this.aliasMaps[setting.alias] = flag; + } + controller.init(setting); + return this; + }; + + App.prototype.listen = function() { + return this.$inputor.on('compositionstart', (function(_this) { + return function(e) { + var ref; + if ((ref = _this.controller()) != null) { + ref.view.hide(); + } + _this.isComposing = true; + return null; + }; + })(this)).on('compositionend', (function(_this) { + return function(e) { + _this.isComposing = false; + setTimeout(function(e) { + return _this.dispatch(e); + }); + return null; + }; + })(this)).on('keyup.atwhoInner', (function(_this) { + return function(e) { + return _this.onKeyup(e); + }; + })(this)).on('keydown.atwhoInner', (function(_this) { + return function(e) { + return _this.onKeydown(e); + }; + })(this)).on('blur.atwhoInner', (function(_this) { + return function(e) { + var c; + if (c = _this.controller()) { + c.expectedQueryCBId = null; + return c.view.hide(e, c.getOpt("displayTimeout")); + } + }; + })(this)).on('click.atwhoInner', (function(_this) { + return function(e) { + return _this.dispatch(e); + }; + })(this)).on('scroll.atwhoInner', (function(_this) { + return function() { + var lastScrollTop; + lastScrollTop = _this.$inputor.scrollTop(); + return function(e) { + var currentScrollTop, ref; + currentScrollTop = e.target.scrollTop; + if (lastScrollTop !== currentScrollTop) { + if ((ref = _this.controller()) != null) { + ref.view.hide(e); + } + } + lastScrollTop = currentScrollTop; + return true; + }; + }; + })(this)()); + }; + + App.prototype.shutdown = function() { + var _, c, ref; + ref = this.controllers; + for (_ in ref) { + c = ref[_]; + c.destroy(); + delete this.controllers[_]; + } + this.$inputor.off('.atwhoInner'); + return this.$el.remove(); + }; + + App.prototype.dispatch = function(e) { + var _, c, ref, results; + ref = this.controllers; + results = []; + for (_ in ref) { + c = ref[_]; + results.push(c.lookUp(e)); + } + return results; + }; + + App.prototype.onKeyup = function(e) { + var ref; + switch (e.keyCode) { + case KEY_CODE.ESC: + e.preventDefault(); + if ((ref = this.controller()) != null) { + ref.view.hide(); + } + break; + case KEY_CODE.DOWN: + case KEY_CODE.UP: + case KEY_CODE.CTRL: + case KEY_CODE.ENTER: + $.noop(); + break; + case KEY_CODE.P: + case KEY_CODE.N: + if (!e.ctrlKey) { + this.dispatch(e); + } + break; + default: + this.dispatch(e); + } + }; + + App.prototype.onKeydown = function(e) { + var ref, view; + view = (ref = this.controller()) != null ? ref.view : void 0; + if (!(view && view.visible())) { + return; + } + switch (e.keyCode) { + case KEY_CODE.ESC: + e.preventDefault(); + view.hide(e); + break; + case KEY_CODE.UP: + e.preventDefault(); + view.prev(); + break; + case KEY_CODE.DOWN: + e.preventDefault(); + view.next(); + break; + case KEY_CODE.P: + if (!e.ctrlKey) { + return; + } + e.preventDefault(); + view.prev(); + break; + case KEY_CODE.N: + if (!e.ctrlKey) { + return; + } + e.preventDefault(); + view.next(); + break; + case KEY_CODE.TAB: + case KEY_CODE.ENTER: + case KEY_CODE.SPACE: + if (!view.visible()) { + return; + } + if (!this.controller().getOpt('spaceSelectsMatch') && e.keyCode === KEY_CODE.SPACE) { + return; + } + if (!this.controller().getOpt('tabSelectsMatch') && e.keyCode === KEY_CODE.TAB) { + return; + } + if (view.highlighted()) { + e.preventDefault(); + view.choose(e); + } else { + view.hide(e); + } + break; + default: + $.noop(); + } + }; + + return App; + +})(); + +var Controller, + slice = [].slice; + +Controller = (function() { + Controller.prototype.uid = function() { + return (Math.random().toString(16) + "000000000").substr(2, 8) + (new Date().getTime()); + }; + + function Controller(app, at1) { + this.app = app; + this.at = at1; + this.$inputor = this.app.$inputor; + this.id = this.$inputor[0].id || this.uid(); + this.expectedQueryCBId = null; + this.setting = null; + this.query = null; + this.pos = 0; + this.range = null; + if ((this.$el = $("#atwho-ground-" + this.id, this.app.$el)).length === 0) { + this.app.$el.append(this.$el = $("<div id='atwho-ground-" + this.id + "'></div>")); + } + this.model = new Model(this); + this.view = new View(this); + } + + Controller.prototype.init = function(setting) { + this.setting = $.extend({}, this.setting || $.fn.atwho["default"], setting); + this.view.init(); + return this.model.reload(this.setting.data); + }; + + Controller.prototype.destroy = function() { + this.trigger('beforeDestroy'); + this.model.destroy(); + this.view.destroy(); + return this.$el.remove(); + }; + + Controller.prototype.callDefault = function() { + var args, error, error1, funcName; + funcName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + try { + return DEFAULT_CALLBACKS[funcName].apply(this, args); + } catch (error1) { + error = error1; + return $.error(error + " Or maybe At.js doesn't have function " + funcName); + } + }; + + Controller.prototype.trigger = function(name, data) { + var alias, eventName; + if (data == null) { + data = []; + } + data.push(this); + alias = this.getOpt('alias'); + eventName = alias ? name + "-" + alias + ".atwho" : name + ".atwho"; + return this.$inputor.trigger(eventName, data); + }; + + Controller.prototype.callbacks = function(funcName) { + return this.getOpt("callbacks")[funcName] || DEFAULT_CALLBACKS[funcName]; + }; + + Controller.prototype.getOpt = function(at, default_value) { + var e, error1; + try { + return this.setting[at]; + } catch (error1) { + e = error1; + return null; + } + }; + + Controller.prototype.insertContentFor = function($li) { + var data, tpl; + tpl = this.getOpt('insertTpl'); + data = $.extend({}, $li.data('item-data'), { + 'atwho-at': this.at + }); + return this.callbacks("tplEval").call(this, tpl, data, "onInsert"); + }; + + Controller.prototype.renderView = function(data) { + var searchKey; + searchKey = this.getOpt("searchKey"); + data = this.callbacks("sorter").call(this, this.query.text, data.slice(0, 1001), searchKey); + return this.view.render(data.slice(0, this.getOpt('limit'))); + }; + + Controller.arrayToDefaultHash = function(data) { + var i, item, len, results; + if (!$.isArray(data)) { + return data; + } + results = []; + for (i = 0, len = data.length; i < len; i++) { + item = data[i]; + if ($.isPlainObject(item)) { + results.push(item); + } else { + results.push({ + name: item + }); + } + } + return results; + }; + + Controller.prototype.lookUp = function(e) { + var query, wait; + if (e && e.type === 'click' && !this.getOpt('lookUpOnClick')) { + return; + } + if (this.getOpt('suspendOnComposing') && this.app.isComposing) { + return; + } + query = this.catchQuery(e); + if (!query) { + this.expectedQueryCBId = null; + return query; + } + this.app.setContextFor(this.at); + if (wait = this.getOpt('delay')) { + this._delayLookUp(query, wait); + } else { + this._lookUp(query); + } + return query; + }; + + Controller.prototype._delayLookUp = function(query, wait) { + var now, remaining; + now = Date.now ? Date.now() : new Date().getTime(); + this.previousCallTime || (this.previousCallTime = now); + remaining = wait - (now - this.previousCallTime); + if ((0 < remaining && remaining < wait)) { + this.previousCallTime = now; + this._stopDelayedCall(); + return this.delayedCallTimeout = setTimeout((function(_this) { + return function() { + _this.previousCallTime = 0; + _this.delayedCallTimeout = null; + return _this._lookUp(query); + }; + })(this), wait); + } else { + this._stopDelayedCall(); + if (this.previousCallTime !== now) { + this.previousCallTime = 0; + } + return this._lookUp(query); + } + }; + + Controller.prototype._stopDelayedCall = function() { + if (this.delayedCallTimeout) { + clearTimeout(this.delayedCallTimeout); + return this.delayedCallTimeout = null; + } + }; + + Controller.prototype._generateQueryCBId = function() { + return {}; + }; + + Controller.prototype._lookUp = function(query) { + var _callback; + _callback = function(queryCBId, data) { + if (queryCBId !== this.expectedQueryCBId) { + return; + } + if (data && data.length > 0) { + return this.renderView(this.constructor.arrayToDefaultHash(data)); + } else { + return this.view.hide(); + } + }; + this.expectedQueryCBId = this._generateQueryCBId(); + return this.model.query(query.text, $.proxy(_callback, this, this.expectedQueryCBId)); + }; + + return Controller; + +})(); + +var TextareaController, + 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; + +TextareaController = (function(superClass) { + extend(TextareaController, superClass); + + function TextareaController() { + return TextareaController.__super__.constructor.apply(this, arguments); + } + + TextareaController.prototype.catchQuery = function() { + var caretPos, content, end, isString, query, start, subtext; + content = this.$inputor.val(); + caretPos = this.$inputor.caret('pos', { + iframe: this.app.iframe + }); + subtext = content.slice(0, caretPos); + query = this.callbacks("matcher").call(this, this.at, subtext, this.getOpt('startWithSpace'), this.getOpt("acceptSpaceBar")); + isString = typeof query === 'string'; + if (isString && query.length < this.getOpt('minLen', 0)) { + return; + } + if (isString && query.length <= this.getOpt('maxLen', 20)) { + start = caretPos - query.length; + end = start + query.length; + this.pos = start; + query = { + 'text': query, + 'headPos': start, + 'endPos': end + }; + this.trigger("matched", [this.at, query.text]); + } else { + query = null; + this.view.hide(); + } + return this.query = query; + }; + + TextareaController.prototype.rect = function() { + var c, iframeOffset, scaleBottom; + if (!(c = this.$inputor.caret('offset', this.pos - 1, { + iframe: this.app.iframe + }))) { + return; + } + if (this.app.iframe && !this.app.iframeAsRoot) { + iframeOffset = $(this.app.iframe).offset(); + c.left += iframeOffset.left; + c.top += iframeOffset.top; + } + scaleBottom = this.app.document.selection ? 0 : 2; + return { + left: c.left, + top: c.top, + bottom: c.top + c.height + scaleBottom + }; + }; + + TextareaController.prototype.insert = function(content, $li) { + var $inputor, source, startStr, suffix, text; + $inputor = this.$inputor; + source = $inputor.val(); + startStr = source.slice(0, Math.max(this.query.headPos - this.at.length, 0)); + suffix = (suffix = this.getOpt('suffix')) === "" ? suffix : suffix || " "; + content += suffix; + text = "" + startStr + content + (source.slice(this.query['endPos'] || 0)); + $inputor.val(text); + $inputor.caret('pos', startStr.length + content.length, { + iframe: this.app.iframe + }); + if (!$inputor.is(':focus')) { + $inputor.focus(); + } + return $inputor.change(); + }; + + return TextareaController; + +})(Controller); + +var EditableController, + 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; + +EditableController = (function(superClass) { + extend(EditableController, superClass); + + function EditableController() { + return EditableController.__super__.constructor.apply(this, arguments); + } + + EditableController.prototype._getRange = function() { + var sel; + sel = this.app.window.getSelection(); + if (sel.rangeCount > 0) { + return sel.getRangeAt(0); + } + }; + + EditableController.prototype._setRange = function(position, node, range) { + if (range == null) { + range = this._getRange(); + } + if (!range) { + return; + } + node = $(node)[0]; + if (position === 'after') { + range.setEndAfter(node); + range.setStartAfter(node); + } else { + range.setEndBefore(node); + range.setStartBefore(node); + } + range.collapse(false); + return this._clearRange(range); + }; + + EditableController.prototype._clearRange = function(range) { + var sel; + if (range == null) { + range = this._getRange(); + } + sel = this.app.window.getSelection(); + if (this.ctrl_a_pressed == null) { + sel.removeAllRanges(); + return sel.addRange(range); + } + }; + + EditableController.prototype._movingEvent = function(e) { + var ref; + return e.type === 'click' || ((ref = e.which) === KEY_CODE.RIGHT || ref === KEY_CODE.LEFT || ref === KEY_CODE.UP || ref === KEY_CODE.DOWN); + }; + + EditableController.prototype._unwrap = function(node) { + var next; + node = $(node).unwrap().get(0); + if ((next = node.nextSibling) && next.nodeValue) { + node.nodeValue += next.nodeValue; + $(next).remove(); + } + return node; + }; + + EditableController.prototype.catchQuery = function(e) { + var $inserted, $query, _range, index, inserted, isString, lastNode, matched, offset, query, query_content, range; + if (!(range = this._getRange())) { + return; + } + if (!range.collapsed) { + return; + } + if (e.which === KEY_CODE.ENTER) { + ($query = $(range.startContainer).closest('.atwho-query')).contents().unwrap(); + if ($query.is(':empty')) { + $query.remove(); + } + ($query = $(".atwho-query", this.app.document)).text($query.text()).contents().last().unwrap(); + this._clearRange(); + return; + } + if (/firefox/i.test(navigator.userAgent)) { + if ($(range.startContainer).is(this.$inputor)) { + this._clearRange(); + return; + } + if (e.which === KEY_CODE.BACKSPACE && range.startContainer.nodeType === document.ELEMENT_NODE && (offset = range.startOffset - 1) >= 0) { + _range = range.cloneRange(); + _range.setStart(range.startContainer, offset); + if ($(_range.cloneContents()).contents().last().is('.atwho-inserted')) { + inserted = $(range.startContainer).contents().get(offset); + this._setRange('after', $(inserted).contents().last()); + } + } else if (e.which === KEY_CODE.LEFT && range.startContainer.nodeType === document.TEXT_NODE) { + $inserted = $(range.startContainer.previousSibling); + if ($inserted.is('.atwho-inserted') && range.startOffset === 0) { + this._setRange('after', $inserted.contents().last()); + } + } + } + $(range.startContainer).closest('.atwho-inserted').addClass('atwho-query').siblings().removeClass('atwho-query'); + if (($query = $(".atwho-query", this.app.document)).length > 0 && $query.is(':empty') && $query.text().length === 0) { + $query.remove(); + } + if (!this._movingEvent(e)) { + $query.removeClass('atwho-inserted'); + } + if ($query.length > 0) { + switch (e.which) { + case KEY_CODE.LEFT: + this._setRange('before', $query.get(0), range); + $query.removeClass('atwho-query'); + return; + case KEY_CODE.RIGHT: + this._setRange('after', $query.get(0).nextSibling, range); + $query.removeClass('atwho-query'); + return; + } + } + if ($query.length > 0 && (query_content = $query.attr('data-atwho-at-query'))) { + $query.empty().html(query_content).attr('data-atwho-at-query', null); + this._setRange('after', $query.get(0), range); + } + _range = range.cloneRange(); + _range.setStart(range.startContainer, 0); + matched = this.callbacks("matcher").call(this, this.at, _range.toString(), this.getOpt('startWithSpace'), this.getOpt("acceptSpaceBar")); + isString = typeof matched === 'string'; + if ($query.length === 0 && isString && (index = range.startOffset - this.at.length - matched.length) >= 0) { + range.setStart(range.startContainer, index); + $query = $('<span/>', this.app.document).attr(this.getOpt("editableAtwhoQueryAttrs")).addClass('atwho-query'); + range.surroundContents($query.get(0)); + lastNode = $query.contents().last().get(0); + if (/firefox/i.test(navigator.userAgent)) { + range.setStart(lastNode, lastNode.length); + range.setEnd(lastNode, lastNode.length); + this._clearRange(range); + } else { + this._setRange('after', lastNode, range); + } + } + if (isString && matched.length < this.getOpt('minLen', 0)) { + return; + } + if (isString && matched.length <= this.getOpt('maxLen', 20)) { + query = { + text: matched, + el: $query + }; + this.trigger("matched", [this.at, query.text]); + return this.query = query; + } else { + this.view.hide(); + this.query = { + el: $query + }; + if ($query.text().indexOf(this.at) >= 0) { + if (this._movingEvent(e) && $query.hasClass('atwho-inserted')) { + $query.removeClass('atwho-query'); + } else if (false !== this.callbacks('afterMatchFailed').call(this, this.at, $query)) { + this._setRange("after", this._unwrap($query.text($query.text()).contents().first())); + } + } + return null; + } + }; + + EditableController.prototype.rect = function() { + var $iframe, iframeOffset, rect; + rect = this.query.el.offset(); + if (this.app.iframe && !this.app.iframeAsRoot) { + iframeOffset = ($iframe = $(this.app.iframe)).offset(); + rect.left += iframeOffset.left - this.$inputor.scrollLeft(); + rect.top += iframeOffset.top - this.$inputor.scrollTop(); + } + rect.bottom = rect.top + this.query.el.height(); + return rect; + }; + + EditableController.prototype.insert = function(content, $li) { + var data, range, suffix, suffixNode; + if (!this.$inputor.is(':focus')) { + this.$inputor.focus(); + } + suffix = (suffix = this.getOpt('suffix')) === "" ? suffix : suffix || "\u00A0"; + data = $li.data('item-data'); + this.query.el.removeClass('atwho-query').addClass('atwho-inserted').html(content).attr('data-atwho-at-query', "" + data['atwho-at'] + this.query.text); + if (range = this._getRange()) { + range.setEndAfter(this.query.el[0]); + range.collapse(false); + range.insertNode(suffixNode = this.app.document.createTextNode("\u200D" + suffix)); + this._setRange('after', suffixNode, range); + } + if (!this.$inputor.is(':focus')) { + this.$inputor.focus(); + } + return this.$inputor.change(); + }; + + return EditableController; + +})(Controller); + +var Model; + +Model = (function() { + function Model(context) { + this.context = context; + this.at = this.context.at; + this.storage = this.context.$inputor; + } + + Model.prototype.destroy = function() { + return this.storage.data(this.at, null); + }; + + Model.prototype.saved = function() { + return this.fetch() > 0; + }; + + Model.prototype.query = function(query, callback) { + var _remoteFilter, data, searchKey; + data = this.fetch(); + searchKey = this.context.getOpt("searchKey"); + data = this.context.callbacks('filter').call(this.context, query, data, searchKey) || []; + _remoteFilter = this.context.callbacks('remoteFilter'); + if (data.length > 0 || (!_remoteFilter && data.length === 0)) { + return callback(data); + } else { + return _remoteFilter.call(this.context, query, callback); + } + }; + + Model.prototype.fetch = function() { + return this.storage.data(this.at) || []; + }; + + Model.prototype.save = function(data) { + return this.storage.data(this.at, this.context.callbacks("beforeSave").call(this.context, data || [])); + }; + + Model.prototype.load = function(data) { + if (!(this.saved() || !data)) { + return this._load(data); + } + }; + + Model.prototype.reload = function(data) { + return this._load(data); + }; + + Model.prototype._load = function(data) { + if (typeof data === "string") { + return $.ajax(data, { + dataType: "json" + }).done((function(_this) { + return function(data) { + return _this.save(data); + }; + })(this)); + } else { + return this.save(data); + } + }; + + return Model; + +})(); + +var View; + +View = (function() { + function View(context) { + this.context = context; + this.$el = $("<div class='atwho-view'><ul class='atwho-view-ul'></ul></div>"); + this.$elUl = this.$el.children(); + this.timeoutID = null; + this.context.$el.append(this.$el); + this.bindEvent(); + } + + View.prototype.init = function() { + var header_tpl, id; + id = this.context.getOpt("alias") || this.context.at.charCodeAt(0); + header_tpl = this.context.getOpt("headerTpl"); + if (header_tpl && this.$el.children().length === 1) { + this.$el.prepend(header_tpl); + } + return this.$el.attr({ + 'id': "at-view-" + id + }); + }; + + View.prototype.destroy = function() { + return this.$el.remove(); + }; + + View.prototype.bindEvent = function() { + var $menu, lastCoordX, lastCoordY; + $menu = this.$el.find('ul'); + lastCoordX = 0; + lastCoordY = 0; + return $menu.on('mousemove.atwho-view', 'li', (function(_this) { + return function(e) { + var $cur; + if (lastCoordX === e.clientX && lastCoordY === e.clientY) { + return; + } + lastCoordX = e.clientX; + lastCoordY = e.clientY; + $cur = $(e.currentTarget); + if ($cur.hasClass('cur')) { + return; + } + $menu.find('.cur').removeClass('cur'); + return $cur.addClass('cur'); + }; + })(this)).on('click.atwho-view', 'li', (function(_this) { + return function(e) { + $menu.find('.cur').removeClass('cur'); + $(e.currentTarget).addClass('cur'); + _this.choose(e); + return e.preventDefault(); + }; + })(this)); + }; + + View.prototype.visible = function() { + return this.$el.is(":visible"); + }; + + View.prototype.highlighted = function() { + return this.$el.find(".cur").length > 0; + }; + + View.prototype.choose = function(e) { + var $li, content; + if (($li = this.$el.find(".cur")).length) { + content = this.context.insertContentFor($li); + this.context._stopDelayedCall(); + this.context.insert(this.context.callbacks("beforeInsert").call(this.context, content, $li, e), $li); + this.context.trigger("inserted", [$li, e]); + this.hide(e); + } + if (this.context.getOpt("hideWithoutSuffix")) { + return this.stopShowing = true; + } + }; + + View.prototype.reposition = function(rect) { + var _window, offset, overflowOffset, ref; + _window = this.context.app.iframeAsRoot ? this.context.app.window : window; + if (rect.bottom + this.$el.height() - $(_window).scrollTop() > $(_window).height()) { + rect.bottom = rect.top - this.$el.height(); + } + if (rect.left > (overflowOffset = $(_window).width() - this.$el.width() - 5)) { + rect.left = overflowOffset; + } + offset = { + left: rect.left, + top: rect.bottom + }; + if ((ref = this.context.callbacks("beforeReposition")) != null) { + ref.call(this.context, offset); + } + this.$el.offset(offset); + return this.context.trigger("reposition", [offset]); + }; + + View.prototype.next = function() { + var cur, next, nextEl, offset; + cur = this.$el.find('.cur').removeClass('cur'); + next = cur.next(); + if (!next.length) { + next = this.$el.find('li:first'); + } + next.addClass('cur'); + nextEl = next[0]; + offset = nextEl.offsetTop + nextEl.offsetHeight + (nextEl.nextSibling ? nextEl.nextSibling.offsetHeight : 0); + return this.scrollTop(Math.max(0, offset - this.$el.height())); + }; + + View.prototype.prev = function() { + var cur, offset, prev, prevEl; + cur = this.$el.find('.cur').removeClass('cur'); + prev = cur.prev(); + if (!prev.length) { + prev = this.$el.find('li:last'); + } + prev.addClass('cur'); + prevEl = prev[0]; + offset = prevEl.offsetTop + prevEl.offsetHeight + (prevEl.nextSibling ? prevEl.nextSibling.offsetHeight : 0); + return this.scrollTop(Math.max(0, offset - this.$el.height())); + }; + + View.prototype.scrollTop = function(scrollTop) { + var scrollDuration; + scrollDuration = this.context.getOpt('scrollDuration'); + if (scrollDuration) { + return this.$elUl.animate({ + scrollTop: scrollTop + }, scrollDuration); + } else { + return this.$elUl.scrollTop(scrollTop); + } + }; + + View.prototype.show = function() { + var rect; + if (this.stopShowing) { + this.stopShowing = false; + return; + } + if (!this.visible()) { + this.$el.show(); + this.$el.scrollTop(0); + this.context.trigger('shown'); + } + if (rect = this.context.rect()) { + return this.reposition(rect); + } + }; + + View.prototype.hide = function(e, time) { + var callback; + if (!this.visible()) { + return; + } + if (isNaN(time)) { + this.$el.hide(); + return this.context.trigger('hidden', [e]); + } else { + callback = (function(_this) { + return function() { + return _this.hide(); + }; + })(this); + clearTimeout(this.timeoutID); + return this.timeoutID = setTimeout(callback, time); + } + }; + + View.prototype.render = function(list) { + var $li, $ul, i, item, len, li, tpl; + if (!($.isArray(list) && list.length > 0)) { + this.hide(); + return; + } + this.$el.find('ul').empty(); + $ul = this.$el.find('ul'); + tpl = this.context.getOpt('displayTpl'); + for (i = 0, len = list.length; i < len; i++) { + item = list[i]; + item = $.extend({}, item, { + 'atwho-at': this.context.at + }); + li = this.context.callbacks("tplEval").call(this.context, tpl, item, "onDisplay"); + $li = $(this.context.callbacks("highlighter").call(this.context, li, this.context.query.text)); + $li.data("item-data", item); + $ul.append($li); + } + this.show(); + if (this.context.getOpt('highlightFirst')) { + return $ul.find("li:first").addClass("cur"); + } + }; + + return View; + +})(); + +var Api; + +Api = { + load: function(at, data) { + var c; + if (c = this.controller(at)) { + return c.model.load(data); + } + }, + isSelecting: function() { + var ref; + return !!((ref = this.controller()) != null ? ref.view.visible() : void 0); + }, + hide: function() { + var ref; + return (ref = this.controller()) != null ? ref.view.hide() : void 0; + }, + reposition: function() { + var c; + if (c = this.controller()) { + return c.view.reposition(c.rect()); + } + }, + setIframe: function(iframe, asRoot) { + this.setupRootElement(iframe, asRoot); + return null; + }, + run: function() { + return this.dispatch(); + }, + destroy: function() { + this.shutdown(); + return this.$inputor.data('atwho', null); + } +}; + +$.fn.atwho = function(method) { + var _args, result; + _args = arguments; + result = null; + this.filter('textarea, input, [contenteditable=""], [contenteditable=true]').each(function() { + var $this, app; + if (!(app = ($this = $(this)).data("atwho"))) { + $this.data('atwho', (app = new App(this))); + } + if (typeof method === 'object' || !method) { + return app.reg(method.at, method); + } else if (Api[method] && app) { + return result = Api[method].apply(app, Array.prototype.slice.call(_args, 1)); + } else { + return $.error("Method " + method + " does not exist on jQuery.atwho"); + } + }); + if (result != null) { + return result; + } else { + return this; + } +}; + +$.fn.atwho["default"] = { + at: void 0, + alias: void 0, + data: null, + displayTpl: "<li>${name}</li>", + insertTpl: "${atwho-at}${name}", + headerTpl: null, + callbacks: DEFAULT_CALLBACKS, + searchKey: "name", + suffix: void 0, + hideWithoutSuffix: false, + startWithSpace: true, + acceptSpaceBar: false, + highlightFirst: true, + limit: 5, + maxLen: 20, + minLen: 0, + displayTimeout: 300, + delay: null, + spaceSelectsMatch: false, + tabSelectsMatch: true, + editableAtwhoQueryAttrs: {}, + scrollDuration: 150, + suspendOnComposing: true, + lookUpOnClick: true +}; + +$.fn.atwho.debug = false; + +})); diff --git a/vendor/assets/javascripts/jquery.caret.js b/vendor/assets/javascripts/jquery.caret.js new file mode 100644 index 00000000000..811ec63ee47 --- /dev/null +++ b/vendor/assets/javascripts/jquery.caret.js @@ -0,0 +1,436 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(["jquery"], function ($) { + return (root.returnExportsGlobal = factory($)); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like enviroments that support module.exports, + // like Node. + module.exports = factory(require("jquery")); + } else { + factory(jQuery); + } +}(this, function ($) { + +/* + Implement Github like autocomplete mentions + http://ichord.github.com/At.js + + Copyright (c) 2013 chord.luo@gmail.com + Licensed under the MIT license. +*/ + +/* +本插件操作 textarea 或者 input 内的插入符 +只实现了获得插入符在文本框中的位置,我设置 +插入符的位置. +*/ + +"use strict"; +var EditableCaret, InputCaret, Mirror, Utils, discoveryIframeOf, methods, oDocument, oFrame, oWindow, pluginName, setContextBy; + +pluginName = 'caret'; + +EditableCaret = (function() { + function EditableCaret($inputor) { + this.$inputor = $inputor; + this.domInputor = this.$inputor[0]; + } + + EditableCaret.prototype.setPos = function(pos) { + var fn, found, offset, sel; + if (sel = oWindow.getSelection()) { + offset = 0; + found = false; + (fn = function(pos, parent) { + var node, range, _i, _len, _ref, _results; + _ref = parent.childNodes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + node = _ref[_i]; + if (found) { + break; + } + if (node.nodeType === 3) { + if (offset + node.length >= pos) { + found = true; + range = oDocument.createRange(); + range.setStart(node, pos - offset); + sel.removeAllRanges(); + sel.addRange(range); + break; + } else { + _results.push(offset += node.length); + } + } else { + _results.push(fn(pos, node)); + } + } + return _results; + })(pos, this.domInputor); + } + return this.domInputor; + }; + + EditableCaret.prototype.getIEPosition = function() { + return this.getPosition(); + }; + + EditableCaret.prototype.getPosition = function() { + var inputor_offset, offset; + offset = this.getOffset(); + inputor_offset = this.$inputor.offset(); + offset.left -= inputor_offset.left; + offset.top -= inputor_offset.top; + return offset; + }; + + EditableCaret.prototype.getOldIEPos = function() { + var preCaretTextRange, textRange; + textRange = oDocument.selection.createRange(); + preCaretTextRange = oDocument.body.createTextRange(); + preCaretTextRange.moveToElementText(this.domInputor); + preCaretTextRange.setEndPoint("EndToEnd", textRange); + return preCaretTextRange.text.length; + }; + + EditableCaret.prototype.getPos = function() { + var clonedRange, pos, range; + if (range = this.range()) { + clonedRange = range.cloneRange(); + clonedRange.selectNodeContents(this.domInputor); + clonedRange.setEnd(range.endContainer, range.endOffset); + pos = clonedRange.toString().length; + clonedRange.detach(); + return pos; + } else if (oDocument.selection) { + return this.getOldIEPos(); + } + }; + + EditableCaret.prototype.getOldIEOffset = function() { + var range, rect; + range = oDocument.selection.createRange().duplicate(); + range.moveStart("character", -1); + rect = range.getBoundingClientRect(); + return { + height: rect.bottom - rect.top, + left: rect.left, + top: rect.top + }; + }; + + EditableCaret.prototype.getOffset = function(pos) { + var clonedRange, offset, range, rect, shadowCaret; + if (oWindow.getSelection && (range = this.range())) { + if (range.endOffset - 1 > 0 && range.endContainer !== this.domInputor) { + clonedRange = range.cloneRange(); + clonedRange.setStart(range.endContainer, range.endOffset - 1); + clonedRange.setEnd(range.endContainer, range.endOffset); + rect = clonedRange.getBoundingClientRect(); + offset = { + height: rect.height, + left: rect.left + rect.width, + top: rect.top + }; + clonedRange.detach(); + } + if (!offset || (offset != null ? offset.height : void 0) === 0) { + clonedRange = range.cloneRange(); + shadowCaret = $(oDocument.createTextNode("|")); + clonedRange.insertNode(shadowCaret[0]); + clonedRange.selectNode(shadowCaret[0]); + rect = clonedRange.getBoundingClientRect(); + offset = { + height: rect.height, + left: rect.left, + top: rect.top + }; + shadowCaret.remove(); + clonedRange.detach(); + } + } else if (oDocument.selection) { + offset = this.getOldIEOffset(); + } + if (offset) { + offset.top += $(oWindow).scrollTop(); + offset.left += $(oWindow).scrollLeft(); + } + return offset; + }; + + EditableCaret.prototype.range = function() { + var sel; + if (!oWindow.getSelection) { + return; + } + sel = oWindow.getSelection(); + if (sel.rangeCount > 0) { + return sel.getRangeAt(0); + } else { + return null; + } + }; + + return EditableCaret; + +})(); + +InputCaret = (function() { + function InputCaret($inputor) { + this.$inputor = $inputor; + this.domInputor = this.$inputor[0]; + } + + InputCaret.prototype.getIEPos = function() { + var endRange, inputor, len, normalizedValue, pos, range, textInputRange; + inputor = this.domInputor; + range = oDocument.selection.createRange(); + pos = 0; + if (range && range.parentElement() === inputor) { + normalizedValue = inputor.value.replace(/\r\n/g, "\n"); + len = normalizedValue.length; + textInputRange = inputor.createTextRange(); + textInputRange.moveToBookmark(range.getBookmark()); + endRange = inputor.createTextRange(); + endRange.collapse(false); + if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { + pos = len; + } else { + pos = -textInputRange.moveStart("character", -len); + } + } + return pos; + }; + + InputCaret.prototype.getPos = function() { + if (oDocument.selection) { + return this.getIEPos(); + } else { + return this.domInputor.selectionStart; + } + }; + + InputCaret.prototype.setPos = function(pos) { + var inputor, range; + inputor = this.domInputor; + if (oDocument.selection) { + range = inputor.createTextRange(); + range.move("character", pos); + range.select(); + } else if (inputor.setSelectionRange) { + inputor.setSelectionRange(pos, pos); + } + return inputor; + }; + + InputCaret.prototype.getIEOffset = function(pos) { + var h, textRange, x, y; + textRange = this.domInputor.createTextRange(); + pos || (pos = this.getPos()); + textRange.move('character', pos); + x = textRange.boundingLeft; + y = textRange.boundingTop; + h = textRange.boundingHeight; + return { + left: x, + top: y, + height: h + }; + }; + + InputCaret.prototype.getOffset = function(pos) { + var $inputor, offset, position; + $inputor = this.$inputor; + if (oDocument.selection) { + offset = this.getIEOffset(pos); + offset.top += $(oWindow).scrollTop() + $inputor.scrollTop(); + offset.left += $(oWindow).scrollLeft() + $inputor.scrollLeft(); + return offset; + } else { + offset = $inputor.offset(); + position = this.getPosition(pos); + return offset = { + left: offset.left + position.left - $inputor.scrollLeft(), + top: offset.top + position.top - $inputor.scrollTop(), + height: position.height + }; + } + }; + + InputCaret.prototype.getPosition = function(pos) { + var $inputor, at_rect, end_range, format, html, mirror, start_range; + $inputor = this.$inputor; + format = function(value) { + value = value.replace(/<|>|`|"|&/g, '?').replace(/\r\n|\r|\n/g, "<br/>"); + if (/firefox/i.test(navigator.userAgent)) { + value = value.replace(/\s/g, ' '); + } + return value; + }; + if (pos === void 0) { + pos = this.getPos(); + } + start_range = $inputor.val().slice(0, pos); + end_range = $inputor.val().slice(pos); + html = "<span style='position: relative; display: inline;'>" + format(start_range) + "</span>"; + html += "<span id='caret' style='position: relative; display: inline;'>|</span>"; + html += "<span style='position: relative; display: inline;'>" + format(end_range) + "</span>"; + mirror = new Mirror($inputor); + return at_rect = mirror.create(html).rect(); + }; + + InputCaret.prototype.getIEPosition = function(pos) { + var h, inputorOffset, offset, x, y; + offset = this.getIEOffset(pos); + inputorOffset = this.$inputor.offset(); + x = offset.left - inputorOffset.left; + y = offset.top - inputorOffset.top; + h = offset.height; + return { + left: x, + top: y, + height: h + }; + }; + + return InputCaret; + +})(); + +Mirror = (function() { + Mirror.prototype.css_attr = ["borderBottomWidth", "borderLeftWidth", "borderRightWidth", "borderTopStyle", "borderRightStyle", "borderBottomStyle", "borderLeftStyle", "borderTopWidth", "boxSizing", "fontFamily", "fontSize", "fontWeight", "height", "letterSpacing", "lineHeight", "marginBottom", "marginLeft", "marginRight", "marginTop", "outlineWidth", "overflow", "overflowX", "overflowY", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "textAlign", "textOverflow", "textTransform", "whiteSpace", "wordBreak", "wordWrap"]; + + function Mirror($inputor) { + this.$inputor = $inputor; + } + + Mirror.prototype.mirrorCss = function() { + var css, + _this = this; + css = { + position: 'absolute', + left: -9999, + top: 0, + zIndex: -20000 + }; + if (this.$inputor.prop('tagName') === 'TEXTAREA') { + this.css_attr.push('width'); + } + $.each(this.css_attr, function(i, p) { + return css[p] = _this.$inputor.css(p); + }); + return css; + }; + + Mirror.prototype.create = function(html) { + this.$mirror = $('<div></div>'); + this.$mirror.css(this.mirrorCss()); + this.$mirror.html(html); + this.$inputor.after(this.$mirror); + return this; + }; + + Mirror.prototype.rect = function() { + var $flag, pos, rect; + $flag = this.$mirror.find("#caret"); + pos = $flag.position(); + rect = { + left: pos.left, + top: pos.top, + height: $flag.height() + }; + this.$mirror.remove(); + return rect; + }; + + return Mirror; + +})(); + +Utils = { + contentEditable: function($inputor) { + return !!($inputor[0].contentEditable && $inputor[0].contentEditable === 'true'); + } +}; + +methods = { + pos: function(pos) { + if (pos || pos === 0) { + return this.setPos(pos); + } else { + return this.getPos(); + } + }, + position: function(pos) { + if (oDocument.selection) { + return this.getIEPosition(pos); + } else { + return this.getPosition(pos); + } + }, + offset: function(pos) { + var offset; + offset = this.getOffset(pos); + return offset; + } +}; + +oDocument = null; + +oWindow = null; + +oFrame = null; + +setContextBy = function(settings) { + var iframe; + if (iframe = settings != null ? settings.iframe : void 0) { + oFrame = iframe; + oWindow = iframe.contentWindow; + return oDocument = iframe.contentDocument || oWindow.document; + } else { + oFrame = void 0; + oWindow = window; + return oDocument = document; + } +}; + +discoveryIframeOf = function($dom) { + var error; + oDocument = $dom[0].ownerDocument; + oWindow = oDocument.defaultView || oDocument.parentWindow; + try { + return oFrame = oWindow.frameElement; + } catch (_error) { + error = _error; + } +}; + +$.fn.caret = function(method, value, settings) { + var caret; + if (methods[method]) { + if ($.isPlainObject(value)) { + setContextBy(value); + value = void 0; + } else { + setContextBy(settings); + } + caret = Utils.contentEditable(this) ? new EditableCaret(this) : new InputCaret(this); + return methods[method].apply(caret, [value]); + } else { + return $.error("Method " + method + " does not exist on jQuery.caret"); + } +}; + +$.fn.caret.EditableCaret = EditableCaret; + +$.fn.caret.InputCaret = InputCaret; + +$.fn.caret.Utils = Utils; + +$.fn.caret.apis = methods; + + +})); diff --git a/vendor/assets/javascripts/jquery.turbolinks.js b/vendor/assets/javascripts/jquery.turbolinks.js index fd6e95e75d5..0cf3fc7cf7a 100644 --- a/vendor/assets/javascripts/jquery.turbolinks.js +++ b/vendor/assets/javascripts/jquery.turbolinks.js @@ -8,10 +8,23 @@ The MIT License Copyright (c) 2012-2013 Sasha Koss & Rico Sta. Cruz */ -(function() { +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define(["jquery"], function (a0) { + return (factory(a0)); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(require("jquery")); + } else { + factory(jQuery); + } +}(this, function($) { var $, $document; - - $ = window.jQuery || (typeof require === "function" ? require('jquery') : void 0); + $ = $ || window.jQuery || (typeof require === "function" ? require('jquery') : void 0); $document = $(document); @@ -46,4 +59,4 @@ Copyright (c) 2012-2013 Sasha Koss & Rico Sta. Cruz $.turbo.use('page:load', 'page:fetch'); -}).call(this); +})); diff --git a/vendor/assets/javascripts/turbolinks.js b/vendor/assets/javascripts/turbolinks.js new file mode 100644 index 00000000000..17a2635bf2a --- /dev/null +++ b/vendor/assets/javascripts/turbolinks.js @@ -0,0 +1,781 @@ +// Turbolinks Classic v2.5.3 compiled from CoffeeScript +(function() { + var CSRFToken, Click, ComponentUrl, EVENTS, Link, ProgressBar, browserIsntBuggy, browserSupportsCustomEvents, browserSupportsPushState, browserSupportsTurbolinks, bypassOnLoadPopstate, cacheCurrentPage, cacheSize, changePage, clone, constrainPageCacheTo, createDocument, crossOriginRedirect, currentState, enableProgressBar, enableTransitionCache, executeScriptTags, extractTitleAndBody, fetch, fetchHistory, fetchReplacement, historyStateIsDefined, initializeTurbolinks, installDocumentReadyPageEventTriggers, installHistoryChangeHandler, installJqueryAjaxSuccessPageUpdateTrigger, loadedAssets, manuallyTriggerHashChangeForFirefox, pageCache, pageChangePrevented, pagesCached, popCookie, processResponse, progressBar, recallScrollPosition, ref, referer, reflectNewUrl, reflectRedirectedUrl, rememberCurrentState, rememberCurrentUrl, rememberReferer, removeNoscriptTags, requestMethodIsSafe, resetScrollPosition, setAutofocusElement, transitionCacheEnabled, transitionCacheFor, triggerEvent, visit, xhr, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, + 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, + slice = [].slice, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + pageCache = {}; + + cacheSize = 10; + + transitionCacheEnabled = false; + + progressBar = null; + + currentState = null; + + loadedAssets = null; + + referer = null; + + xhr = null; + + EVENTS = { + BEFORE_CHANGE: 'page:before-change', + FETCH: 'page:fetch', + RECEIVE: 'page:receive', + CHANGE: 'page:change', + UPDATE: 'page:update', + LOAD: 'page:load', + RESTORE: 'page:restore', + BEFORE_UNLOAD: 'page:before-unload', + EXPIRE: 'page:expire' + }; + + fetch = function(url) { + var cachedPage; + url = new ComponentUrl(url); + rememberReferer(); + cacheCurrentPage(); + if (progressBar != null) { + progressBar.start(); + } + if (transitionCacheEnabled && (cachedPage = transitionCacheFor(url.absolute))) { + fetchHistory(cachedPage); + return fetchReplacement(url, null, false); + } else { + return fetchReplacement(url, resetScrollPosition); + } + }; + + transitionCacheFor = function(url) { + var cachedPage; + cachedPage = pageCache[url]; + if (cachedPage && !cachedPage.transitionCacheDisabled) { + return cachedPage; + } + }; + + enableTransitionCache = function(enable) { + if (enable == null) { + enable = true; + } + return transitionCacheEnabled = enable; + }; + + enableProgressBar = function(enable) { + if (enable == null) { + enable = true; + } + if (!browserSupportsTurbolinks) { + return; + } + if (enable) { + return progressBar != null ? progressBar : progressBar = new ProgressBar('html'); + } else { + if (progressBar != null) { + progressBar.uninstall(); + } + return progressBar = null; + } + }; + + fetchReplacement = function(url, onLoadFunction, showProgressBar) { + if (showProgressBar == null) { + showProgressBar = true; + } + triggerEvent(EVENTS.FETCH, { + url: url.absolute + }); + if (xhr != null) { + xhr.abort(); + } + xhr = new XMLHttpRequest; + xhr.open('GET', url.withoutHashForIE10compatibility(), true); + xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml'); + xhr.setRequestHeader('X-XHR-Referer', referer); + xhr.onload = function() { + var doc; + triggerEvent(EVENTS.RECEIVE, { + url: url.absolute + }); + if (doc = processResponse()) { + reflectNewUrl(url); + reflectRedirectedUrl(); + changePage.apply(null, extractTitleAndBody(doc)); + manuallyTriggerHashChangeForFirefox(); + if (typeof onLoadFunction === "function") { + onLoadFunction(); + } + return triggerEvent(EVENTS.LOAD); + } else { + return document.location.href = crossOriginRedirect() || url.absolute; + } + }; + if (progressBar && showProgressBar) { + xhr.onprogress = (function(_this) { + return function(event) { + var percent; + percent = event.lengthComputable ? event.loaded / event.total * 100 : progressBar.value + (100 - progressBar.value) / 10; + return progressBar.advanceTo(percent); + }; + })(this); + } + xhr.onloadend = function() { + return xhr = null; + }; + xhr.onerror = function() { + return document.location.href = url.absolute; + }; + return xhr.send(); + }; + + fetchHistory = function(cachedPage) { + if (xhr != null) { + xhr.abort(); + } + changePage(cachedPage.title, cachedPage.body); + recallScrollPosition(cachedPage); + return triggerEvent(EVENTS.RESTORE); + }; + + cacheCurrentPage = function() { + var currentStateUrl; + currentStateUrl = new ComponentUrl(currentState.url); + pageCache[currentStateUrl.absolute] = { + url: currentStateUrl.relative, + body: document.body, + title: document.title, + positionY: window.pageYOffset, + positionX: window.pageXOffset, + cachedAt: new Date().getTime(), + transitionCacheDisabled: document.querySelector('[data-no-transition-cache]') != null + }; + return constrainPageCacheTo(cacheSize); + }; + + pagesCached = function(size) { + if (size == null) { + size = cacheSize; + } + if (/^[\d]+$/.test(size)) { + return cacheSize = parseInt(size); + } + }; + + constrainPageCacheTo = function(limit) { + var cacheTimesRecentFirst, i, key, len, pageCacheKeys, results; + pageCacheKeys = Object.keys(pageCache); + cacheTimesRecentFirst = pageCacheKeys.map(function(url) { + return pageCache[url].cachedAt; + }).sort(function(a, b) { + return b - a; + }); + results = []; + for (i = 0, len = pageCacheKeys.length; i < len; i++) { + key = pageCacheKeys[i]; + if (!(pageCache[key].cachedAt <= cacheTimesRecentFirst[limit])) { + continue; + } + triggerEvent(EVENTS.EXPIRE, pageCache[key]); + results.push(delete pageCache[key]); + } + return results; + }; + + changePage = function(title, body, csrfToken, runScripts) { + triggerEvent(EVENTS.BEFORE_UNLOAD); + document.title = title; + document.documentElement.replaceChild(body, document.body); + if (csrfToken != null) { + CSRFToken.update(csrfToken); + } + setAutofocusElement(); + if (runScripts) { + executeScriptTags(); + } + currentState = window.history.state; + if (progressBar != null) { + progressBar.done(); + } + triggerEvent(EVENTS.CHANGE); + return triggerEvent(EVENTS.UPDATE); + }; + + executeScriptTags = function() { + var attr, copy, i, j, len, len1, nextSibling, parentNode, ref, ref1, script, scripts; + scripts = Array.prototype.slice.call(document.body.querySelectorAll('script:not([data-turbolinks-eval="false"])')); + for (i = 0, len = scripts.length; i < len; i++) { + script = scripts[i]; + if (!((ref = script.type) === '' || ref === 'text/javascript')) { + continue; + } + copy = document.createElement('script'); + ref1 = script.attributes; + for (j = 0, len1 = ref1.length; j < len1; j++) { + attr = ref1[j]; + copy.setAttribute(attr.name, attr.value); + } + if (!script.hasAttribute('async')) { + copy.async = false; + } + copy.appendChild(document.createTextNode(script.innerHTML)); + parentNode = script.parentNode, nextSibling = script.nextSibling; + parentNode.removeChild(script); + parentNode.insertBefore(copy, nextSibling); + } + }; + + removeNoscriptTags = function(node) { + node.innerHTML = node.innerHTML.replace(/<noscript[\S\s]*?<\/noscript>/ig, ''); + return node; + }; + + setAutofocusElement = function() { + var autofocusElement, list; + autofocusElement = (list = document.querySelectorAll('input[autofocus], textarea[autofocus]'))[list.length - 1]; + if (autofocusElement && document.activeElement !== autofocusElement) { + return autofocusElement.focus(); + } + }; + + reflectNewUrl = function(url) { + if ((url = new ComponentUrl(url)).absolute !== referer) { + return window.history.pushState({ + turbolinks: true, + url: url.absolute + }, '', url.absolute); + } + }; + + reflectRedirectedUrl = function() { + var location, preservedHash; + if (location = xhr.getResponseHeader('X-XHR-Redirected-To')) { + location = new ComponentUrl(location); + preservedHash = location.hasNoHash() ? document.location.hash : ''; + return window.history.replaceState(window.history.state, '', location.href + preservedHash); + } + }; + + crossOriginRedirect = function() { + var redirect; + if (((redirect = xhr.getResponseHeader('Location')) != null) && (new ComponentUrl(redirect)).crossOrigin()) { + return redirect; + } + }; + + rememberReferer = function() { + return referer = document.location.href; + }; + + rememberCurrentUrl = function() { + return window.history.replaceState({ + turbolinks: true, + url: document.location.href + }, '', document.location.href); + }; + + rememberCurrentState = function() { + return currentState = window.history.state; + }; + + manuallyTriggerHashChangeForFirefox = function() { + var url; + if (navigator.userAgent.match(/Firefox/) && !(url = new ComponentUrl).hasNoHash()) { + window.history.replaceState(currentState, '', url.withoutHash()); + return document.location.hash = url.hash; + } + }; + + recallScrollPosition = function(page) { + return window.scrollTo(page.positionX, page.positionY); + }; + + resetScrollPosition = function() { + if (document.location.hash) { + return document.location.href = document.location.href; + } else { + return window.scrollTo(0, 0); + } + }; + + clone = function(original) { + var copy, key, value; + if ((original == null) || typeof original !== 'object') { + return original; + } + copy = new original.constructor(); + for (key in original) { + value = original[key]; + copy[key] = clone(value); + } + return copy; + }; + + popCookie = function(name) { + var ref, value; + value = ((ref = document.cookie.match(new RegExp(name + "=(\\w+)"))) != null ? ref[1].toUpperCase() : void 0) || ''; + document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'; + return value; + }; + + triggerEvent = function(name, data) { + var event; + if (typeof Prototype !== 'undefined') { + Event.fire(document, name, data, true); + } + event = document.createEvent('Events'); + if (data) { + event.data = data; + } + event.initEvent(name, true, true); + return document.dispatchEvent(event); + }; + + pageChangePrevented = function(url) { + return !triggerEvent(EVENTS.BEFORE_CHANGE, { + url: url + }); + }; + + processResponse = function() { + var assetsChanged, clientOrServerError, doc, extractTrackAssets, intersection, validContent; + clientOrServerError = function() { + var ref; + return (400 <= (ref = xhr.status) && ref < 600); + }; + validContent = function() { + var contentType; + return ((contentType = xhr.getResponseHeader('Content-Type')) != null) && contentType.match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/); + }; + extractTrackAssets = function(doc) { + var i, len, node, ref, results; + ref = doc.querySelector('head').childNodes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + node = ref[i]; + if ((typeof node.getAttribute === "function" ? node.getAttribute('data-turbolinks-track') : void 0) != null) { + results.push(node.getAttribute('src') || node.getAttribute('href')); + } + } + return results; + }; + assetsChanged = function(doc) { + var fetchedAssets; + loadedAssets || (loadedAssets = extractTrackAssets(document)); + fetchedAssets = extractTrackAssets(doc); + return fetchedAssets.length !== loadedAssets.length || intersection(fetchedAssets, loadedAssets).length !== loadedAssets.length; + }; + intersection = function(a, b) { + var i, len, ref, results, value; + if (a.length > b.length) { + ref = [b, a], a = ref[0], b = ref[1]; + } + results = []; + for (i = 0, len = a.length; i < len; i++) { + value = a[i]; + if (indexOf.call(b, value) >= 0) { + results.push(value); + } + } + return results; + }; + if (!clientOrServerError() && validContent()) { + doc = createDocument(xhr.responseText); + if (doc && !assetsChanged(doc)) { + return doc; + } + } + }; + + extractTitleAndBody = function(doc) { + var title; + title = doc.querySelector('title'); + return [title != null ? title.textContent : void 0, removeNoscriptTags(doc.querySelector('body')), CSRFToken.get(doc).token, 'runScripts']; + }; + + CSRFToken = { + get: function(doc) { + var tag; + if (doc == null) { + doc = document; + } + return { + node: tag = doc.querySelector('meta[name="csrf-token"]'), + token: tag != null ? typeof tag.getAttribute === "function" ? tag.getAttribute('content') : void 0 : void 0 + }; + }, + update: function(latest) { + var current; + current = this.get(); + if ((current.token != null) && (latest != null) && current.token !== latest) { + return current.node.setAttribute('content', latest); + } + } + }; + + createDocument = function(html) { + var doc; + doc = document.documentElement.cloneNode(); + doc.innerHTML = html; + doc.head = doc.querySelector('head'); + doc.body = doc.querySelector('body'); + return doc; + }; + + ComponentUrl = (function() { + function ComponentUrl(original1) { + this.original = original1 != null ? original1 : document.location.href; + if (this.original.constructor === ComponentUrl) { + return this.original; + } + this._parse(); + } + + ComponentUrl.prototype.withoutHash = function() { + return this.href.replace(this.hash, '').replace('#', ''); + }; + + ComponentUrl.prototype.withoutHashForIE10compatibility = function() { + return this.withoutHash(); + }; + + ComponentUrl.prototype.hasNoHash = function() { + return this.hash.length === 0; + }; + + ComponentUrl.prototype.crossOrigin = function() { + return this.origin !== (new ComponentUrl).origin; + }; + + ComponentUrl.prototype._parse = function() { + var ref; + (this.link != null ? this.link : this.link = document.createElement('a')).href = this.original; + ref = this.link, this.href = ref.href, this.protocol = ref.protocol, this.host = ref.host, this.hostname = ref.hostname, this.port = ref.port, this.pathname = ref.pathname, this.search = ref.search, this.hash = ref.hash; + this.origin = [this.protocol, '//', this.hostname].join(''); + if (this.port.length !== 0) { + this.origin += ":" + this.port; + } + this.relative = [this.pathname, this.search, this.hash].join(''); + return this.absolute = this.href; + }; + + return ComponentUrl; + + })(); + + Link = (function(superClass) { + extend(Link, superClass); + + Link.HTML_EXTENSIONS = ['html']; + + Link.allowExtensions = function() { + var extension, extensions, i, len; + extensions = 1 <= arguments.length ? slice.call(arguments, 0) : []; + for (i = 0, len = extensions.length; i < len; i++) { + extension = extensions[i]; + Link.HTML_EXTENSIONS.push(extension); + } + return Link.HTML_EXTENSIONS; + }; + + function Link(link1) { + this.link = link1; + if (this.link.constructor === Link) { + return this.link; + } + this.original = this.link.href; + this.originalElement = this.link; + this.link = this.link.cloneNode(false); + Link.__super__.constructor.apply(this, arguments); + } + + Link.prototype.shouldIgnore = function() { + return this.crossOrigin() || this._anchored() || this._nonHtml() || this._optOut() || this._target(); + }; + + Link.prototype._anchored = function() { + return (this.hash.length > 0 || this.href.charAt(this.href.length - 1) === '#') && (this.withoutHash() === (new ComponentUrl).withoutHash()); + }; + + Link.prototype._nonHtml = function() { + return this.pathname.match(/\.[a-z]+$/g) && !this.pathname.match(new RegExp("\\.(?:" + (Link.HTML_EXTENSIONS.join('|')) + ")?$", 'g')); + }; + + Link.prototype._optOut = function() { + var ignore, link; + link = this.originalElement; + while (!(ignore || link === document)) { + ignore = link.getAttribute('data-no-turbolink') != null; + link = link.parentNode; + } + return ignore; + }; + + Link.prototype._target = function() { + return this.link.target.length !== 0; + }; + + return Link; + + })(ComponentUrl); + + Click = (function() { + Click.installHandlerLast = function(event) { + if (!event.defaultPrevented) { + document.removeEventListener('click', Click.handle, false); + return document.addEventListener('click', Click.handle, false); + } + }; + + Click.handle = function(event) { + return new Click(event); + }; + + function Click(event1) { + this.event = event1; + if (this.event.defaultPrevented) { + return; + } + this._extractLink(); + if (this._validForTurbolinks()) { + if (!pageChangePrevented(this.link.absolute)) { + visit(this.link.href); + } + this.event.preventDefault(); + } + } + + Click.prototype._extractLink = function() { + var link; + link = this.event.target; + while (!(!link.parentNode || link.nodeName === 'A')) { + link = link.parentNode; + } + if (link.nodeName === 'A' && link.href.length !== 0) { + return this.link = new Link(link); + } + }; + + Click.prototype._validForTurbolinks = function() { + return (this.link != null) && !(this.link.shouldIgnore() || this._nonStandardClick()); + }; + + Click.prototype._nonStandardClick = function() { + return this.event.which > 1 || this.event.metaKey || this.event.ctrlKey || this.event.shiftKey || this.event.altKey; + }; + + return Click; + + })(); + + ProgressBar = (function() { + var className; + + className = 'turbolinks-progress-bar'; + + function ProgressBar(elementSelector) { + this.elementSelector = elementSelector; + this._trickle = bind(this._trickle, this); + this.value = 0; + this.content = ''; + this.speed = 300; + this.opacity = 0.99; + this.install(); + } + + ProgressBar.prototype.install = function() { + this.element = document.querySelector(this.elementSelector); + this.element.classList.add(className); + this.styleElement = document.createElement('style'); + document.head.appendChild(this.styleElement); + return this._updateStyle(); + }; + + ProgressBar.prototype.uninstall = function() { + this.element.classList.remove(className); + return document.head.removeChild(this.styleElement); + }; + + ProgressBar.prototype.start = function() { + return this.advanceTo(5); + }; + + ProgressBar.prototype.advanceTo = function(value) { + var ref; + if ((value > (ref = this.value) && ref <= 100)) { + this.value = value; + this._updateStyle(); + if (this.value === 100) { + return this._stopTrickle(); + } else if (this.value > 0) { + return this._startTrickle(); + } + } + }; + + ProgressBar.prototype.done = function() { + if (this.value > 0) { + this.advanceTo(100); + return this._reset(); + } + }; + + ProgressBar.prototype._reset = function() { + var originalOpacity; + originalOpacity = this.opacity; + setTimeout((function(_this) { + return function() { + _this.opacity = 0; + return _this._updateStyle(); + }; + })(this), this.speed / 2); + return setTimeout((function(_this) { + return function() { + _this.value = 0; + _this.opacity = originalOpacity; + return _this._withSpeed(0, function() { + return _this._updateStyle(true); + }); + }; + })(this), this.speed); + }; + + ProgressBar.prototype._startTrickle = function() { + if (this.trickling) { + return; + } + this.trickling = true; + return setTimeout(this._trickle, this.speed); + }; + + ProgressBar.prototype._stopTrickle = function() { + return delete this.trickling; + }; + + ProgressBar.prototype._trickle = function() { + if (!this.trickling) { + return; + } + this.advanceTo(this.value + Math.random() / 2); + return setTimeout(this._trickle, this.speed); + }; + + ProgressBar.prototype._withSpeed = function(speed, fn) { + var originalSpeed, result; + originalSpeed = this.speed; + this.speed = speed; + result = fn(); + this.speed = originalSpeed; + return result; + }; + + ProgressBar.prototype._updateStyle = function(forceRepaint) { + if (forceRepaint == null) { + forceRepaint = false; + } + if (forceRepaint) { + this._changeContentToForceRepaint(); + } + return this.styleElement.textContent = this._createCSSRule(); + }; + + ProgressBar.prototype._changeContentToForceRepaint = function() { + return this.content = this.content === '' ? ' ' : ''; + }; + + ProgressBar.prototype._createCSSRule = function() { + return this.elementSelector + "." + className + "::before {\n content: '" + this.content + "';\n position: fixed;\n top: 0;\n left: 0;\n z-index: 2000;\n background-color: #0076ff;\n height: 3px;\n opacity: " + this.opacity + ";\n width: " + this.value + "%;\n transition: width " + this.speed + "ms ease-out, opacity " + (this.speed / 2) + "ms ease-in;\n transform: translate3d(0,0,0);\n}"; + }; + + return ProgressBar; + + })(); + + bypassOnLoadPopstate = function(fn) { + return setTimeout(fn, 500); + }; + + installDocumentReadyPageEventTriggers = function() { + return document.addEventListener('DOMContentLoaded', (function() { + triggerEvent(EVENTS.CHANGE); + return triggerEvent(EVENTS.UPDATE); + }), true); + }; + + installJqueryAjaxSuccessPageUpdateTrigger = function() { + if (typeof jQuery !== 'undefined') { + return jQuery(document).on('ajaxSuccess', function(event, xhr, settings) { + if (!jQuery.trim(xhr.responseText)) { + return; + } + return triggerEvent(EVENTS.UPDATE); + }); + } + }; + + installHistoryChangeHandler = function(event) { + var cachedPage, ref; + if ((ref = event.state) != null ? ref.turbolinks : void 0) { + if (cachedPage = pageCache[(new ComponentUrl(event.state.url)).absolute]) { + cacheCurrentPage(); + return fetchHistory(cachedPage); + } else { + return visit(event.target.location.href); + } + } + }; + + initializeTurbolinks = function() { + rememberCurrentUrl(); + rememberCurrentState(); + document.addEventListener('click', Click.installHandlerLast, true); + window.addEventListener('hashchange', function(event) { + rememberCurrentUrl(); + return rememberCurrentState(); + }, false); + return bypassOnLoadPopstate(function() { + return window.addEventListener('popstate', installHistoryChangeHandler, false); + }); + }; + + historyStateIsDefined = window.history.state !== void 0 || navigator.userAgent.match(/Firefox\/2[6|7]/); + + browserSupportsPushState = window.history && window.history.pushState && window.history.replaceState && historyStateIsDefined; + + browserIsntBuggy = !navigator.userAgent.match(/CriOS\//); + + requestMethodIsSafe = (ref = popCookie('request_method')) === 'GET' || ref === ''; + + browserSupportsTurbolinks = browserSupportsPushState && browserIsntBuggy && requestMethodIsSafe; + + browserSupportsCustomEvents = document.addEventListener && document.createEvent; + + if (browserSupportsCustomEvents) { + installDocumentReadyPageEventTriggers(); + installJqueryAjaxSuccessPageUpdateTrigger(); + } + + if (browserSupportsTurbolinks) { + visit = fetch; + initializeTurbolinks(); + } else { + visit = function(url) { + return document.location.href = url; + }; + } + + this.Turbolinks = { + visit: visit, + pagesCached: pagesCached, + enableTransitionCache: enableTransitionCache, + enableProgressBar: enableProgressBar, + allowLinkExtensions: Link.allowExtensions, + supported: browserSupportsTurbolinks, + EVENTS: clone(EVENTS) + }; + +}).call(this); diff --git a/vendor/assets/javascripts/u2f.js b/vendor/assets/javascripts/u2f.js index e666b136051..a33e5e0ade9 100644 --- a/vendor/assets/javascripts/u2f.js +++ b/vendor/assets/javascripts/u2f.js @@ -745,4 +745,6 @@ u2f.getApiVersion = function(callback, opt_timeoutSeconds) { }; port.postMessage(req); }); -};
\ No newline at end of file +}; + +window.u2f || (window.u2f = u2f); diff --git a/vendor/assets/javascripts/xterm/fit.js b/vendor/assets/javascripts/xterm/fit.js index 7e24fd9b36e..55438452cad 100644 --- a/vendor/assets/javascripts/xterm/fit.js +++ b/vendor/assets/javascripts/xterm/fit.js @@ -16,12 +16,12 @@ /* * CommonJS environment */ - module.exports = fit(require('../../xterm')); + module.exports = fit(require('./xterm')); } else if (typeof define == 'function') { /* * Require.js is available */ - define(['../../xterm'], fit); + define(['./xterm'], fit); } else { /* * Plain browser environment |