Commit 7b70014d authored by Jacob Schatz's avatar Jacob Schatz

Merge branch 'go-go-gadget-webpack' into 'master'

Integrate webpack for frontend asset compilation

Closes #14634

See merge request !7288
parents 06eb5f36 56e5404d
/builds/
/coverage/
/coverage-javascript/
/node_modules/
/public/
/tmp/
/vendor/
/builds/
karma.config.js
webpack.config.js
......@@ -16,6 +16,8 @@
],
"rules": {
"filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"],
"no-multiple-empty-lines": ["error", { "max": 1 }]
"no-multiple-empty-lines": ["error", { "max": 1 }],
"import/no-extraneous-dependencies": "off",
"import/no-unresolved": "off"
}
}
......@@ -107,11 +107,13 @@ setup-test-env:
<<: *dedicated-runner
stage: prepare
script:
- bundle exec rake gitlab:assets:compile 2>/dev/null
- npm install
- bundle exec rake gitlab:assets:compile
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
artifacts:
expire_in: 7d
paths:
- node_modules
- public/assets
- tmp/tests
......@@ -232,7 +234,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
script:
- bundle exec $CI_BUILD_NAME
rubocop:
rubocop:
<<: *ruby-static-analysis
<<: *dedicated-runner
stage: test
......@@ -291,18 +293,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
- bundle exec rake teaspoon
- bundle exec rake karma
artifacts:
name: coverage-javascript
expire_in: 31d
......@@ -444,7 +445,7 @@ pages:
<<: *dedicated-runner
dependencies:
- coverage
- teaspoon
- karma
- lint:javascript:report
script:
- mv public/ .public/
......
......@@ -7,7 +7,6 @@ gem 'rails-deprecated_sanitizer', '~> 1.0.3'
gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.7.0'
gem 'sprockets-es6', '~> 0.9.2'
# Default values for AR models
gem 'default_value_for', '~> 3.0.0'
......@@ -219,6 +218,7 @@ gem 'oj', '~> 2.17.4'
gem 'chronic', '~> 0.10.2'
gem 'chronic_duration', '~> 0.10.6'
gem 'webpack-rails', '~> 0.9.9'
gem 'sass-rails', '~> 5.0.6'
gem 'coffee-rails', '~> 4.1.0'
gem 'uglifier', '~> 2.7.2'
......@@ -291,13 +291,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
......@@ -315,6 +311,8 @@ group :development, :test do
gem 'activerecord_sane_schema_dumper', '0.2'
gem 'stackprof', '~> 0.2.10'
gem 'rack-proxy', '~> 0.6.0'
end
group :test do
......
......@@ -72,10 +72,6 @@ GEM
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
babel-source (5.8.35)
babel-transpiler (0.7.0)
babel-source (>= 4.0, < 6)
execjs (~> 2.0)
babosa (1.0.2)
base32 (0.3.2)
bcrypt (3.1.11)
......@@ -546,6 +542,8 @@ GEM
rack (>= 1.1)
rack-protection (1.5.3)
rack
rack-proxy (0.6.0)
rack
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.7.1)
......@@ -733,15 +731,9 @@ 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)
sprockets-es6 (0.9.2)
babel-source (>= 5.8.11)
babel-transpiler
sprockets (>= 3.0.0)
sprockets-rails (3.1.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
......@@ -759,10 +751,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 (1.1.0)
activerecord (>= 3.2)
......@@ -814,6 +802,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)
......@@ -952,6 +942,7 @@ DEPENDENCIES
rack-attack (~> 4.4.1)
rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1)
rack-proxy (~> 0.6.0)
rails (= 4.2.7.1)
rails-deprecated_sanitizer (~> 1.0.3)
rainbow (~> 2.1.0)
......@@ -993,14 +984,10 @@ 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 (~> 1.1)
thin (~> 1.7.0)
timecop (~> 0.8.0)
......@@ -1016,6 +1003,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
......
/* 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,60 +6,57 @@
/* 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 js.cookie */
/*= 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');
window.Cookies = require('vendor/js.cookie');
require('./autosave');
require('bootstrap/js/affix');
require('bootstrap/js/alert');
require('bootstrap/js/button');
require('bootstrap/js/collapse');
require('bootstrap/js/dropdown');
require('bootstrap/js/modal');
require('bootstrap/js/scrollspy');
require('bootstrap/js/tab');
require('bootstrap/js/transition');
require('bootstrap/js/tooltip');
require('bootstrap/js/popover');
require('select2/select2.js');
window._ = 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).*\.(js|es6)$/));
require('vendor/fuzzaldrin-plus');
window.ES6Promise = require('vendor/es6-promise.auto');
window.ES6Promise.polyfill();
(function () {
document.addEventListener('beforeunload', function () {
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-template, quotes, comma-dangle, no-param-reassign, no-void, brace-style, no-underscore-dangle, no-return-assign, camelcase */
/* global Cookies */
var emojiAliases = require('emoji-aliases');
(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();
......
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, consistent-return, max-len */
/* global autosize */
/*= require autosize */
var autosize = require('vendor/autosize');
(function() {
$(function() {
......
......@@ -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
......
......@@ -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
......
/* eslint-disable no-param-reassign, comma-dangle */
/* global Api */
/*= require blob/template_selector */
require('./template_selector');
((global) => {
class BlobCiYamlSelector extends gl.TemplateSelector {
requestFile(query) {
......
/* global Api */
/*= require blob/template_selector */
require('./template_selector');
(() => {
const global = window.gl || (window.gl = {});
......
/* 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 */
/* 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; },
......
/* 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 */
/* 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; },
......
......@@ -2,7 +2,7 @@
/* global EditBlob */
/* global NewCommitForm */
/*= require_tree . */
require('./edit_blob');
(function() {
$(function() {
......
/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */
/* eslint-disable one-var, 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 ./components/modal/index
//= 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('./components/modal/index');
require('./vue_resource_interceptor');
$(() => {
const $boardApp = document.getElementById('board-app');
......@@ -76,7 +78,7 @@ $(() => {
});
gl.IssueBoardsSearch = new Vue({
el: '#js-boards-search',
el: document.getElementById('js-boards-search'),
data: {
filters: Store.state.filters
},
......@@ -87,7 +89,7 @@ $(() => {
gl.IssueBoardsModalAddBtn = new Vue({
mixins: [gl.issueBoards.ModalMixins],
el: '#js-add-issues-btn',
el: document.getElementById('js-add-issues-btn'),
data: {
modal: ModalStore.store,
store: Store.state,
......
......@@ -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;
......
/* eslint-disable comma-dangle, space-before-function-paren, dot-notation */
//= require ./issue_card_inner
/* global Vue */
require('./issue_card_inner');
(() => {
const Store = gl.issueBoards.BoardsStore;
......
......@@ -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;
......
......@@ -4,7 +4,8 @@
/* global MilestoneSelect */
/* global LabelsSelect */
/* global Sidebar */
//= require ./sidebar/remove_issue
require('./sidebar/remove_issue');
(() => {
const Store = gl.issueBoards.BoardsStore;
......
/* eslint-disable no-new */
//= require ./lists_dropdown
/* global Vue */
/* global Flash */
require('./lists_dropdown');
(() => {
const ModalStore = gl.issueBoards.ModalStore;
......
/* global Vue */
//= require ./tabs
require('./tabs');
(() => {
const ModalStore = gl.issueBoards.ModalStore;
......
/* global Vue */
/* global ListIssue */
//= require ./header
//= require ./list
//= require ./footer
//= require ./empty_state
require('./header');
require('./list');
require('./footer');
require('./empty_state');
(() => {
const ModalStore = gl.issueBoards.ModalStore;
......
/* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */
/* jshint esversion: 6 */
/*= require lib/utils/common_utils */
require('./lib/utils/common_utils');
(() => {
const gfmRules = {
......
/* 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, max-len */
/* global Clipboard */
/*= require clipboard */
window.Clipboard = require('vendor/clipboard');
(function() {
var genericError, genericSuccess, showTooltip;
......
......@@ -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';
......
/* eslint-disable class-methods-use-this */
//= require lib/utils/url_utility */
require('./lib/utils/url_utility');
(() => {
const UNFOLD_COUNT = 20;
......
/* 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_directory ./models
//= require_directory ./stores
//= require_directory ./services
//= require_directory ./mixins
//= require_directory ./components
function requireAll(context) { return context.keys().map(context); }
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';
......
/* 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, prefer-arrow-callback */
/* global Dropzone */
/*= require preview_markdown */
require('./preview_markdown');
(function() {
this.DropzoneInput = (function() {
......
......@@ -3,10 +3,10 @@
/* global EnvironmentsService */
/* global Flash */
//= 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 || {};
......
/*= require vue */
/* global Vue */
window.Vue = require('vue');
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
......
/*= require vue */
/* global Vue */
window.Vue = require('vue');
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
......
/* 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');
(() => {
/**
......
/*= require vue */
/* global Vue */
window.Vue = require('vue');
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
......
/*= require vue */
/* global Vue */
window.Vue = require('vue');
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
......
/*= require vue */
/* global Vue */
window.Vue = require('vue');
(() => {
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
......
//= 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 || {};
......
/* globals Vue */
/* eslint-disable no-unused-vars, no-param-reassign */
class EnvironmentsService {
constructor(root) {
......
/* eslint-disable no-extend-native, func-names, space-before-function-paren, space-infix-ops, max-len */
/* eslint-disable no-extend-native, func-names, space-before-function-paren, space-infix-ops, strict, max-len */
'use strict';
Array.prototype.first = function() {
return this[0];
};
......
/*= require filtered_search/filtered_search_dropdown */
require('./filtered_search_dropdown');
/* global droplabFilter */
......
/*= require filtered_search/filtered_search_dropdown */
require('./filtered_search_dropdown');
/* global droplabAjax */
/* global droplabFilter */
......
/*= require filtered_search/filtered_search_dropdown */
require('./filtered_search_dropdown');
/* global droplabAjaxFilter */
......
// 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)$/));
/* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign */
//= require gl_field_error
require('./gl_field_error');
((global) => {
const customValidationFlag = 'gl-field-error-ignore';
......
/* 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)$/));
......@@ -5,7 +5,7 @@
/* global ContributorsStatGraphUtil */
/* global d3 */
/*= require d3 */
window.d3 = require('d3');
(function() {
this.ContributorsStatGraph = (function() {
......
......@@ -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); }; },
......
//= require ./time_tracking/time_tracking_bundle
require('./time_tracking/time_tracking_bundle');
/* global Vue */
//= require lib/utils/pretty_time
require('../../../lib/utils/pretty_time');
(() => {
Vue.component('time-tracking-collapsed-state', {
......@@ -39,4 +39,3 @@
`,
});
})();
/* global Vue */
//= require lib/utils/pretty_time
require('../../../lib/utils/pretty_time');
(() => {
const prettyTime = gl.utils.prettyTime;
......
/* global Vue */
//= require ./help_state
//= require ./collapsed_state
//= require ./spent_only_pane
//= require ./no_tracking_pane
//= require ./estimate_only_pane
//= require ./comparison_pane
require('./help_state');
require('./collapsed_state');
require('./spent_only_pane');
require('./no_tracking_pane');
require('./estimate_only_pane');
require('./comparison_pane');
(() => {
Vue.component('issuable-time-tracker', {
......
/* global Vue */
//= require ./components/time_tracker
//= require smart_interval
//= require subbable_resource
require('./components/time_tracker');
require('../../smart_interval');
require('../../subbable_resource');
(() => {
/* This Vue instance represents what will become the parent instance for the
......
/* eslint-disable func-names, space-before-function-paren, no-var, 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, 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); }; };
......
/* eslint-disable func-names, space-before-function-paren */
/*= require Chart */
(function() {
}).call(this);
window.Chart = require('vendor/Chart');
/* eslint-disable func-names, space-before-function-paren */
/*= require d3 */
(function() {
}).call(this);
window.d3 = require('d3');
......@@ -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) {
......
(function() {
gl.emojiAliases = function() {
return JSON.parse('<%= Gitlab::AwardEmoji.aliases.to_json %>');
};
}).call(this);
//= require vue
//= require vue-resource
window.Vue = require('vue');
window.Vue.use(require('vue-resource'));
......@@ -4,7 +4,7 @@
//
// Handles single- and multi-line selection and highlight for blob views.
//
/*= require jquery.scrollTo */
require('vendor/jquery.scrollTo');
//
// ### Example Markup
......
......@@ -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';
......
/* eslint-disable func-names, space-before-function-paren, no-var, 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, 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); }; };
......
/* 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
......
......@@ -3,6 +3,8 @@
/* global notifyPermissions */
/* global merge_request_widget */
require('./smart_interval');
((global) => {
var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i += 1) { if (i in this && this[i] === item) return i; } return -1; };
......
......@@ -47,7 +47,7 @@
$('.js-rebase-button').html("<i class='fa fa-spinner fa-spin'></i> Rebase in progress");
});
} else {
merge_request_widget.getMergeStatus();
setTimeout(() => merge_request_widget.getMergeStatus(), 200);
}
});
})();
......@@ -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() {
......
......@@ -4,13 +4,14 @@
/* global ResolveService */
/* global mrRefreshWidgetUrl */
/*= 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); }; };
......
/* eslint-disable no-new, guard-for-in, no-restricted-syntax, no-continue, no-param-reassign, max-len */
//= require lib/utils/bootstrap_linked_tabs
require('./lib/utils/bootstrap_linked_tabs');
((global) => {
class Pipelines {
......
/* 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)$/));
/*= 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)$/));
......@@ -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; },
......
......@@ -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; },
......
......@@ -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; },
......
......@@ -3,8 +3,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; },
......
......@@ -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; },
......
......@@ -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; },
......
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, 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() {
......
/* eslint-disable comma-dangle, max-len, no-useless-return, no-param-reassign, max-len */
/* global Api */
/*= require ../blob/template_selector */
require('../blob/template_selector');
((global) => {
class IssuableTemplateSelector extends gl.TemplateSelector {
......
//= 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' }));
/* 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)$/));
/*= require vue */
/* global Vue */
window.Vue = require('vue');
(() => {
window.gl = window.gl || {};
......
/* 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;
......
/* 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,
......
/* 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) => {
......
/* 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, '-');
......
......@@ -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
......
......@@ -2,4 +2,7 @@ module JavascriptHelper
def page_specific_javascript_tag(js)
javascript_include_tag asset_path(js)
end
def page_specific_javascript_bundle_tag(js)
javascript_include_tag(*webpack_asset_paths(js))
end
end
......@@ -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
......
- 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')
......@@ -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 }
......
- 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
......
......@@ -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"
......
- @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"
......
......@@ -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,
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -3,7 +3,7 @@
- page_description @issue.description
- page_card_attributes @issue.card_attributes
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/vue_resource.js')
= page_specific_javascript_bundle_tag('lib_vue')
.clearfix.detail-page-header
.issuable-header
......
......@@ -3,8 +3,8 @@
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/vue_resource.js')
= page_specific_javascript_tag('diff_notes/diff_notes_bundle.js')
= page_specific_javascript_bundle_tag('lib_vue')
= page_specific_javascript_bundle_tag('diff_notes')
.merge-request{ 'data-url' => merge_request_path(@merge_request) }
= render "projects/merge_requests/show/mr_title"
......
- page_title "Merge Conflicts", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests"
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/vue_resource.js')
= page_specific_javascript_tag('merge_conflicts/merge_conflicts_bundle.js')
= page_specific_javascript_bundle_tag('lib_vue')
= page_specific_javascript_bundle_tag('merge_conflicts')
= page_specific_javascript_tag('lib/ace.js')
= render "projects/merge_requests/show/mr_title"
......
- 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
......
- 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")
......
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('merge_request_widget/ci_bundle.js')
= page_specific_javascript_bundle_tag('merge_request_widget')
%h4
Set by #{link_to_member(@project, @merge_request.merge_user, avatar: true)}
......
- 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 }
......
......@@ -64,4 +64,4 @@
.vue-pipelines-index
= page_specific_javascript_tag('vue_pipelines_index/index.js')
= page_specific_javascript_bundle_tag('vue_pipelines')
- 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
......
- todo = issuable_todo(issuable)
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('issuable/issuable_bundle.js')
= page_specific_javascript_bundle_tag('issuable')
%aside.right-sidebar{ class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
.issuable-sidebar
- can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
......
- 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|
......
- 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
......
#!/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')
---
title: use webpack to bundle frontend assets and use karma for frontend testing
merge_request: 7288
author:
......@@ -80,6 +80,14 @@ 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"
# Webpack dev server configuration is handled in initializers/static_files.rb
config.webpack.dev_server.enabled = false
# Enable the asset pipeline
config.assets.enabled = true
config.assets.paths << Gemojione.images_path
......@@ -88,31 +96,13 @@ module Gitlab
config.assets.precompile << "print.css"
config.assets.precompile << "notify.css"
config.assets.precompile << "mailers/*.css"
config.assets.precompile << "lib/vue_resource.js"
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 << "issuable/issuable_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
......
---
# 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
......@@ -505,6 +505,16 @@ production: &base
# Git timeout to read a commit, in seconds
timeout: 10
## Webpack settings
# If enabled, this will tell rails to serve frontend assets from the webpack-dev-server running
# on a given port instead of serving directly from /assets/webpack. This is only indended for use
# in development.
webpack:
# dev_server:
# enabled: true
# host: localhost
# port: 3808
#
# 5. Extra customization
# ==========================
......
......@@ -409,6 +409,15 @@ Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour
Settings['gitaly'] ||= Settingslogic.new({})
Settings.gitaly['socket_path'] ||= ENV['GITALY_SOCKET_PATH']
#
# Webpack settings
#
Settings['webpack'] ||= Settingslogic.new({})
Settings.webpack['dev_server'] ||= Settingslogic.new({})
Settings.webpack.dev_server['enabled'] ||= false
Settings.webpack.dev_server['host'] ||= 'localhost'
Settings.webpack.dev_server['port'] ||= 3808
#
# Testing settings
#
......
......@@ -12,4 +12,35 @@ if app.config.serve_static_files
app.paths["public"].first,
app.config.static_cache_control
)
# If webpack-dev-server is configured, proxy webpack's public directory
# instead of looking for static assets
dev_server = Gitlab.config.webpack.dev_server
if dev_server.enabled
settings = {
enabled: true,
host: dev_server.host,
port: dev_server.port,
manifest_host: dev_server.host,
manifest_port: dev_server.port,
}
if Rails.env.development?
settings.merge!(
host: Gitlab.config.gitlab.host,
port: Gitlab.config.gitlab.port,
https: Gitlab.config.gitlab.https,
)
app.config.middleware.insert_before(
Gitlab::Middleware::Static,
Gitlab::Middleware::WebpackProxy,
proxy_path: app.config.webpack.public_path,
proxy_host: dev_server.host,
proxy_port: dev_server.port,
)
end
app.config.webpack.dev_server.merge!(settings)
end
end
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' },
});
};
'use strict';
var fs = require('fs');
var path = require('path');
var webpack = require('webpack');
var StatsPlugin = require('stats-webpack-plugin');
var CompressionPlugin = require('compression-webpack-plugin');
var ROOT_PATH = path.resolve(__dirname, '..');
var IS_PRODUCTION = process.env.NODE_ENV === 'production';
var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1;
var DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 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',
issuable: './issuable/issuable_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',
lib_vue: './lib/vue_resource.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;
# This Rack middleware is intended to proxy the webpack assets directory to the
# webpack-dev-server. It is only intended for use in development.
module Gitlab
module Middleware
class WebpackProxy < Rack::Proxy
def initialize(app = nil, opts = {})
@proxy_host = opts.fetch(:proxy_host, 'localhost')
@proxy_port = opts.fetch(:proxy_port, 3808)
@proxy_path = opts[:proxy_path] if opts[:proxy_path]
super(app, opts)
end
def perform_request(env)
unless @proxy_path && env['PATH_INFO'].start_with?("/#{@proxy_path}")
return @app.call(env)
end
env['HTTP_HOST'] = "#{@proxy_host}:#{@proxy_port}"
super(env)
end
end
end
end
......@@ -3,6 +3,7 @@ namespace :gitlab do
desc 'GitLab | Assets | Compile all frontend assets'
task :compile do
Rake::Task['assets:precompile'].invoke
Rake::Task['webpack:compile'].invoke
Rake::Task['gitlab:assets:fix_urls'].invoke
end
......
......@@ -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|
......
unless Rails.env.production?
Rake::Task['teaspoon'].clear if Rake::Task.task_defined?('teaspoon')
Rake::Task['karma'].clear if Rake::Task.task_defined?('karma')
namespace :teaspoon do
desc 'GitLab | Teaspoon | Generate fixtures for JavaScript tests'
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 | Teaspoon | Run JavaScript tests'
desc 'GitLab | Karma | Run JavaScript tests'
task :tests do
require "teaspoon/console"
options = {}
abort('rake teaspoon:tests failed') if Teaspoon::Console.new(options).failures?
sh "npm run karma" do |ok, res|
abort('rake karma:tests failed') unless ok
end
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
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
......@@ -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
{
"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"
}
}
/*= require lib/utils/text_utility */
/*= require abuse_reports */
require('~/lib/utils/text_utility');
require('~/abuse_reports');
((global) => {
describe('Abuse Reports', () => {
......
/* eslint-disable no-unused-expressions, no-prototype-builtins, no-new, 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 = {});
......
/* 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, 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;
......
/* eslint-disable space-before-function-paren, no-var, comma-dangle, no-return-assign, max-len */
/*= require behaviors/autosize */
require('~/behaviors/autosize');
(function() {
describe('Autosize behavior', function() {
......
/* eslint-disable space-before-function-paren, no-var, no-return-assign, comma-dangle, jasmine/no-spec-dupes, new-cap, max-len */
/*= require behaviors/quick_submit */
require('~/behaviors/quick_submit');
(function() {
describe('Quick Submit behavior', function() {
......
/* eslint-disable space-before-function-paren, no-var */
/*= require behaviors/requires_input */
require('~/behaviors/requires_input');
(function() {
describe('requiresInput', function() {
......
......@@ -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(() => {
......
......@@ -4,15 +4,13 @@
/* global listObj */
/* global ListIssue */
//= require jquery
//= require vue
//= require boards/models/issue
//= require boards/models/label
//= require boards/models/list
//= require boards/models/user
//= require boards/stores/boards_store
//= require boards/components/issue_card_inner
//= require ./mock_data
require('~/boards/models/issue');
require('~/boards/models/label');
require('~/boards/models/list');
require('~/boards/models/user');
require('~/boards/stores/boards_store');
require('~/boards/components/issue_card_inner');
require('./mock_data');
describe('Issue card component', () => {
const user = new ListUser({
......
......@@ -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;
......
......@@ -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;
......
/* global Vue */
/* global ListIssue */
//= require jquery
//= require vue
//= require boards/models/issue
//= require boards/models/label
//= require boards/models/list
//= require boards/models/user
//= require boards/stores/modal_store
require('~/boards/models/issue');
require('~/boards/models/label');
require('~/boards/models/list');
require('~/boards/models/user');
require('~/boards/stores/modal_store');
describe('Modal store', () => {
let issue;
......
//= 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"
let phantomjs;
try {
phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
} catch (err) {
phantomjs = false;
}
describe('Linked Tabs', () => {
preloadFixtures('static/linked_tabs.html.raw');
......@@ -10,7 +19,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 +47,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,9 +60,11 @@
secondTab.click();
expect(historySpy).toHaveBeenCalledWith({
url: newState,
}, document.title, newState);
if (historySpy) {
expect(historySpy).toHaveBeenCalledWith({
url: newState,
}, document.title, newState);
}
});
});
});
......
/* eslint-disable no-new */
/* global Build */
//= require lib/utils/datetime_utility
//= require lib/utils/url_utility
//= require build
//= require breakpoints
//= require jquery.nicescroll
require('~/lib/utils/datetime_utility');
require('~/lib/utils/url_utility');
require('~/build');
require('~/breakpoints');
require('vendor/jquery.nicescroll');
describe('Build', () => {
const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/builds/1`;
......
/* global CommitsList */
//= require jquery.endless-scroll
//= require pager
//= require commits
require('vendor/jquery.endless-scroll');
require('~/pager');
require('~/commits');
(() => {
// TODO: remove this hack!
// PhantomJS causes spyOn to panic because replaceState isn't "writable"
let phantomjs;
try {
phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
} catch (err) {
phantomjs = false;
}
describe('Commits List', () => {
beforeEach(() => {
setFixtures(`
......@@ -25,7 +34,10 @@
beforeEach(() => {
CommitsList.init(25);
CommitsList.searchField.val('');
spyOn(history, 'replaceState').and.stub();
if (!phantomjs) {
spyOn(history, 'replaceState').and.stub();
}
ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => {
req.success({
data: '<li>Result</li>',
......
/* eslint-disable no-new */
/*= require sidebar */
/*= require jquery */
/*= require js.cookie */
/*= require lib/utils/text_utility */
require('~/sidebar');
require('~/lib/utils/text_utility');
((global) => {
describe('Dashboard', () => {
......
//= require lib/utils/datetime_utility
require('~/lib/utils/datetime_utility');
(() => {
describe('Date time utils', () => {
......
/* eslint-disable 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) {
......
//= require vue
//= require environments/components/environment_actions
require('~/environments/components/environment_actions');
describe('Actions Component', () => {
preloadFixtures('static/environments/element.html.raw');
......
//= require vue
//= require environments/components/environment_external_url
require('~/environments/components/environment_external_url');
describe('External URL Component', () => {
preloadFixtures('static/environments/element.html.raw');
......
//= 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');
......
//= require vue
//= require environments/components/environment_rollback
require('~/environments/components/environment_rollback');
describe('Rollback Component', () => {
preloadFixtures('static/environments/element.html.raw');
......
/* global Vue, environment */
//= require vue
//= require vue-resource
//= require flash
//= require environments/stores/environments_store
//= require environments/components/environment
//= require ./mock_data
require('~/flash');
require('~/environments/stores/environments_store');
require('~/environments/components/environment');
require('./mock_data');
describe('Environment', () => {
preloadFixtures('static/environments/environments.html.raw');
......
//= require vue
//= require environments/components/environment_stop
require('~/environments/components/environment_stop');
describe('Stop Component', () => {
preloadFixtures('static/environments/element.html.raw');
......
/* global environmentsList */
//= require vue
//= require environments/stores/environments_store
//= require ./mock_data
require('~/environments/stores/environments_store');
require('./mock_data');
(() => {
describe('Store', () => {
......
/* eslint-disable space-before-function-paren, no-var */
/*= require extensions/array */
require('~/extensions/array');
(function() {
describe('Array extensions', function() {
......
/*= require extensions/element */
require('~/extensions/element');
(() => {
describe('Element extensions', function () {
......
/* eslint-disable space-before-function-paren, no-var */
/*= require extensions/jquery */
require('~/extensions/jquery');
(function() {
describe('jQuery extensions', function() {
......
/*= require extensions/object */
require('~/extensions/object');
describe('Object extensions', () => {
describe('assign', () => {
......
//= require filtered_search/dropdown_utils
//= require filtered_search/filtered_search_tokenizer
//= require filtered_search/filtered_search_dropdown
//= require filtered_search/dropdown_user
require('~/filtered_search/dropdown_utils');
require('~/filtered_search/filtered_search_tokenizer');
require('~/filtered_search/filtered_search_dropdown');
require('~/filtered_search/dropdown_user');
(() => {
describe('Dropdown User', () => {
......
//= 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', () => {
......
//= 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', () => {
......
//= require lib/utils/url_utility
//= require lib/utils/common_utils
//= require filtered_search/filtered_search_token_keys
//= require filtered_search/filtered_search_tokenizer
//= require filtered_search/filtered_search_dropdown_manager
//= require filtered_search/filtered_search_manager
require('~/lib/utils/url_utility');
require('~/lib/utils/common_utils');
require('~/filtered_search/filtered_search_token_keys');
require('~/filtered_search/filtered_search_tokenizer');
require('~/filtered_search/filtered_search_dropdown_manager');
require('~/filtered_search/filtered_search_manager');
(() => {
describe('Filtered Search Manager', () => {
......
//= 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', () => {
......
//= 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', () => {
......
//= require gfm_auto_complete
//= require jquery
//= require jquery.atwho
require('~/gfm_auto_complete');
require('vendor/jquery.caret');
require('vendor/jquery.atwho');
const global = window.gl || (window.gl = {});
const GfmAutoComplete = global.GfmAutoComplete;
......
/* eslint-disable comma-dangle, no-param-reassign, no-unused-expressions, max-len */
/*= require jquery */
/*= require gl_dropdown */
/*= require lib/utils/common_utils */
/*= require lib/utils/type_utility */
//= require lib/utils/url_utility
require('~/gl_dropdown');
require('~/lib/utils/common_utils');
require('~/lib/utils/type_utility');
require('~/lib/utils/url_utility');
(() => {
const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link';
......
/* eslint-disable space-before-function-paren, arrow-body-style */
//= require jquery
//= require gl_field_errors
require('~/gl_field_errors');
((global) => {
preloadFixtures('static/gl_field_errors.html.raw');
......
/* global autosize */
/*= require gl_form */
/*= require autosize */
/*= require lib/utils/text_utility */
/*= require lib/utils/common_utils */
window.autosize = require('vendor/autosize');
require('~/gl_form');
require('~/lib/utils/text_utility');
require('~/lib/utils/common_utils');
describe('GLForm', () => {
const global = window.gl || (window.gl = {});
......
......@@ -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 () {
......
/* eslint-disable quotes, no-var, camelcase, object-property-newline, comma-dangle, max-len, vars-on-top, quote-props */
/* global ContributorsStatGraphUtil */
//= require graphs/stat_graph_contributors_util
require('~/graphs/stat_graph_contributors_util');
describe("ContributorsStatGraphUtil", function () {
describe("#parse_log", function () {
......
/* eslint-disable quotes */
/* global StatGraph */
//= require graphs/stat_graph
require('~/graphs/stat_graph');
describe("StatGraph", function () {
describe("#get_log", function () {
......
/* eslint-disable space-before-function-paren, no-var */
/*= require header */
/*= require lib/utils/text_utility */
/*= require jquery */
require('~/header');
require('~/lib/utils/text_utility');
(function() {
describe('Header', function() {
......
/* global ClassSpecHelper */
//= require ./class_spec_helper
require('./class_spec_helper');
describe('ClassSpecHelper', () => {
describe('.itShouldBeAStaticMethod', function () {
......
/* global Issuable */
//= require lib/utils/url_utility
//= require issuable
require('~/lib/utils/url_utility');
require('~/issuable');
(() => {
const BASE_URL = '/user/project/issues?scope=all&state=closed';
......
/* eslint-disable */
//= require jquery
//= require vue
//= require issuable/time_tracking/components/time_tracker
require('jquery');
require('vue');
require('~/issuable/time_tracking/components/time_tracker');
function initTimeTrackingComponent(opts) {
setFixtures(`
......
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, 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';
......
......@@ -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;
......
//= require lib/utils/common_utils
require('~/lib/utils/common_utils');
(() => {
describe('common_utils', () => {
......
//= require lib/utils/text_utility
require('~/lib/utils/text_utility');
(() => {
describe('text_utility', () => {
......
/* 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, jasmine/no-spec-dupes, no-underscore-dangle, max-len */
/* global LineHighlighter */
/*= require line_highlighter */
require('~/line_highlighter');
(function() {
describe('LineHighlighter', function() {
......
/* eslint-disable space-before-function-paren, no-return-assign */
/* global MergeRequest */
/*= require merge_request */
require('~/merge_request');
(function() {
describe('MergeRequest', function() {
......
/* 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"
var phantomjs;
try {
phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
} catch (err) {
phantomjs = false;
}
describe('MergeRequestTabs', function () {
var stubLocation = {};
var setLocation = function (stubs) {
......@@ -22,9 +31,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,9 +109,11 @@
pathname: '/foo/bar/merge_requests/1'
});
newState = this.subject('commits');
expect(this.spies.history).toHaveBeenCalledWith({
url: newState
}, document.title, newState);
if (!phantomjs) {
expect(this.spies.history).toHaveBeenCalledWith({
url: newState
}, document.title, newState);
}
});
it('treats "show" like "notes"', function () {
setLocation({
......
/* eslint-disable space-before-function-paren, quotes, comma-dangle, dot-notation, quote-props, no-var, max-len */
/*= require merge_request_widget */
/*= require smart_interval */
/*= require lib/utils/datetime_utility */
require('~/merge_request_widget');
require('~/smart_interval');
require('~/lib/utils/datetime_utility');
(function() {
describe('MergeRequestWidget', function() {
......
/* eslint-disable no-new */
//= require flash
//= require mini_pipeline_graph_dropdown
require('~/flash');
require('~/mini_pipeline_graph_dropdown');
(() => {
describe('Mini Pipeline Graph Dropdown', () => {
......
/* eslint-disable space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-return-assign, quotes, 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() {
......
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, 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 = {});
......
//= require pipelines
require('~/pipelines');
// Fix for phantomJS
if (!Element.prototype.matches && Element.prototype.webkitMatchesSelector) {
Element.prototype.matches = Element.prototype.webkitMatchesSelector;
}
(() => {
describe('Pipelines', () => {
......
//= require lib/utils/pretty_time
require('~/lib/utils/pretty_time');
(() => {
const prettyTime = gl.utils.prettyTime;
......
/* 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, 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 = {});
......
/* 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, 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;
......
/* 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, max-len */
/*= require gl_dropdown */
/*= require search_autocomplete */
/*= require jquery */
/*= require lib/utils/common_utils */
/*= require lib/utils/type_utility */
/*= require fuzzaldrin-plus */
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;
......@@ -115,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.gl.utils, 'visitUrl').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);
});
......@@ -129,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);
});
......@@ -137,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);
});
......@@ -146,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);
......@@ -157,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);
......
/* eslint-disable space-before-function-paren, no-return-assign, no-var, quotes */
/* global ShortcutsIssuable */
/*= require copy_as_gfm */
/*= require shortcuts_issuable */
require('~/copy_as_gfm');
require('~/shortcuts_issuable');
(function() {
describe('ShortcutsIssuable', function() {
......
/*= require signin_tabs_memoizer */
require('~/signin_tabs_memoizer');
((global) => {
describe('SigninTabsMemoizer', () => {
......
//= require jquery
//= require smart_interval
require('~/smart_interval');
(() => {
const DEFAULT_MAX_INTERVAL = 100;
......@@ -164,7 +163,7 @@
const interval = this.smartInterval;
setTimeout(() => {
$(document).trigger('beforeunload');
$(document).triggerHandler('beforeunload');
expect(interval.state.intervalId).toBeUndefined();
expect(interval.getCurrentInterval()).toBe(interval.cfg.startingInterval);
done();
......
/* 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 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 || {};
/* eslint-disable max-len, arrow-parens, comma-dangle */
//= 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
......
/* eslint-disable space-before-function-paren, no-var, no-return-assign, quotes */
/*= require syntax_highlight */
require('~/syntax_highlight');
(function() {
describe('Syntax Highlighter', function() {
......
// 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('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);
}
});
......@@ -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() {
......
......@@ -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() {
......
/*= require visibility_select */
require('~/visibility_select');
(() => {
const VisibilitySelect = gl.VisibilitySelect;
......
//= require vue_common_component/commit
require('~/vue_common_component/commit');
describe('Commit component', () => {
let props;
......
//= require vue
//= require lib/utils/common_utils
//= require vue_pagination/index
require('~/lib/utils/common_utils');
require('~/vue_pagination/index');
describe('Pagination component', () => {
let component;
......
......@@ -3,7 +3,7 @@
/* global Mousetrap */
/* global ZenMode */
/*= require zen_mode */
require('~/zen_mode');
(function() {
var enterZen, escapeKeydown, exitZen;
......
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/javascripts/(?!helpers/)}]
# 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
......@@ -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;
})));
......@@ -1154,6 +1154,3 @@ Promise.Promise = Promise;
return Promise;
})));
ES6Promise.polyfill();
//# sourceMappingURL=es6-promise.auto.map
/**
* 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;
}));
(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, '&nbsp;');
}
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;
}));
......@@ -745,4 +745,6 @@ u2f.getApiVersion = function(callback, opt_timeoutSeconds) {
};
port.postMessage(req);
});
};
\ No newline at end of file
};
window.u2f || (window.u2f = u2f);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment