summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/application.js1
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js2
-rw-r--r--app/assets/javascripts/users/calendar.js4
-rw-r--r--app/assets/javascripts/webpack/application.js293
-rw-r--r--app/assets/javascripts/webpack/bundle.js4
-rw-r--r--app/assets/javascripts/webpack/hello_world.js.es611
-rw-r--r--app/views/layouts/_head.html.haml3
-rw-r--r--config/webpack.config.js20
-rw-r--r--package.json13
-rw-r--r--vendor/assets/javascripts/jquery.atwho.js1202
-rw-r--r--vendor/assets/javascripts/jquery.caret.js436
-rw-r--r--vendor/assets/javascripts/jquery.turbolinks.js49
-rw-r--r--vendor/assets/javascripts/turbolinks.js781
13 files changed, 2797 insertions, 22 deletions
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index e43afbb4cc9..c21f0572fa7 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -22,6 +22,7 @@
/*= require jquery.endless-scroll */
/*= require jquery.highlight */
/*= require jquery.waitforimages */
+/*= require jquery.caret */
/*= require jquery.atwho */
/*= require jquery.scrollTo */
/*= require jquery.turbolinks */
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index e8e502694d6..30e4e490543 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -17,7 +17,7 @@
w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
w.gl.utils.formatDate = function(datetime) {
- return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z');
+ return (new Date(datetime)).format('mmm d, yyyy h:MMtt Z');
};
w.gl.utils.getDayName = function(date) {
diff --git a/app/assets/javascripts/users/calendar.js b/app/assets/javascripts/users/calendar.js
index 578be7c3590..43ee6a9d9fd 100644
--- a/app/assets/javascripts/users/calendar.js
+++ b/app/assets/javascripts/users/calendar.js
@@ -33,7 +33,7 @@
date.setDate(date.getDate() + i);
var day = date.getDay();
- var count = timestamps[dateFormat(date, 'yyyy-mm-dd')];
+ var count = timestamps[date.format('yyyy-mm-dd')];
// Create a new group array if this is the first day of the week
// or if is first object
@@ -122,7 +122,7 @@
if (stamp.count > 0) {
contribText = stamp.count + " contribution" + (stamp.count > 1 ? 's' : '');
}
- dateText = dateFormat(date, 'mmm d, yyyy');
+ dateText = date.format('mmm d, yyyy');
return contribText + "<br />" + (gl.utils.getDayName(date)) + " " + dateText;
};
})(this)).attr('class', 'user-contrib-cell js-tooltip').attr('fill', (function(_this) {
diff --git a/app/assets/javascripts/webpack/application.js b/app/assets/javascripts/webpack/application.js
new file mode 100644
index 00000000000..660e00d4c5b
--- /dev/null
+++ b/app/assets/javascripts/webpack/application.js
@@ -0,0 +1,293 @@
+/* eslint-disable */
+
+/**
+ * Simulate sprockets compile order of application.js through CommonJS require statements
+ *
+ * Currently exports everything appropriate to window until the scripts that rely on this behavior
+ * can be refactored.
+ *
+ * Test the output from this against sprockets output and it should be almost identical apart from
+ * webpack's CommonJS wrapper. You can add the following line to webpack.config.js to fix the
+ * script indentation:
+ * config.output.sourcePrefix = '';
+ */
+
+/*= require jquery2 */
+window.jQuery = window.$ = require('jquery');
+
+/*= require jquery-ui/autocomplete */
+// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/menu, jquery-ui/position
+require('jquery-ui/ui/core');
+require('jquery-ui/ui/widget');
+require('jquery-ui/ui/position');
+require('jquery-ui/ui/menu');
+require('jquery-ui/ui/autocomplete');
+
+/*= require jquery-ui/datepicker */
+// depends on jquery-ui/core
+require('jquery-ui/ui/datepicker');
+
+/*= require jquery-ui/draggable */
+// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/mouse
+require('jquery-ui/ui/mouse');
+require('jquery-ui/ui/draggable');
+
+/*= require jquery-ui/effect-highlight */
+// depends on jquery-ui/effect
+require('jquery-ui/ui/effect');
+require('jquery-ui/ui/effect-highlight');
+
+/*= require jquery-ui/sortable */
+// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/mouse
+require('jquery-ui/ui/sortable');
+
+/*= require jquery_ujs */
+require('jquery-ujs');
+
+/*= require jquery.endless-scroll */
+require('vendor/jquery.endless-scroll');
+
+/*= require jquery.highlight */
+require('vendor/jquery.highlight');
+
+/*= require jquery.waitforimages */
+require('vendor/jquery.waitforimages');
+
+/*= require jquery.atwho */
+require('vendor/jquery.caret'); // required by jquery.atwho
+require('vendor/jquery.atwho');
+
+/*= require jquery.scrollTo */
+require('vendor/jquery.scrollTo');
+
+/*= require jquery.turbolinks */
+require('vendor/jquery.turbolinks');
+
+/*= require js.cookie */
+window.Cookies = require('vendor/js.cookie');
+
+/*= require turbolinks */
+require('vendor/turbolinks');
+
+/*= require autosave */
+require('../autosave');
+
+/*= require bootstrap/affix */
+require('bootstrap/js/affix');
+
+/*= require bootstrap/alert */
+require('bootstrap/js/alert');
+
+/*= require bootstrap/button */
+require('bootstrap/js/button');
+
+/*= require bootstrap/collapse */
+require('bootstrap/js/collapse');
+
+/*= require bootstrap/dropdown */
+require('bootstrap/js/dropdown');
+
+/*= require bootstrap/modal */
+require('bootstrap/js/modal');
+
+/*= require bootstrap/scrollspy */
+require('bootstrap/js/scrollspy');
+
+/*= require bootstrap/tab */
+require('bootstrap/js/tab');
+
+/*= require bootstrap/transition */
+require('bootstrap/js/transition');
+
+/*= require bootstrap/tooltip */
+require('bootstrap/js/tooltip');
+
+/*= require bootstrap/popover */
+require('bootstrap/js/popover');
+
+/*= require select2 */
+require('select2/select2.js');
+
+/*= require underscore */
+window._ = require('underscore');
+
+/*= require dropzone */
+window.Dropzone = require('dropzone');
+
+/*= require mousetrap */
+require('mousetrap');
+
+/*= require mousetrap/pause */
+require('mousetrap/plugins/pause/mousetrap-pause');
+
+/*= require shortcuts */
+require('../shortcuts');
+
+/*= require shortcuts_navigation */
+require('../shortcuts_navigation');
+
+/*= require shortcuts_dashboard_navigation */
+require('../shortcuts_dashboard_navigation');
+
+/*= require shortcuts_issuable */
+require('../shortcuts_issuable');
+
+/*= require shortcuts_network */
+require('../shortcuts_network');
+
+/*= require jquery.nicescroll */
+require('vendor/jquery.nicescroll');
+
+/*= require date.format */
+require('vendor/date.format');
+
+/*= require_directory ./behaviors */
+require('vendor/jquery.ba-resize');
+window.autosize = require('vendor/autosize');
+require('../behaviors/autosize'); // requires vendor/jquery.ba-resize and vendor/autosize
+require('../behaviors/details_behavior');
+require('../extensions/jquery');
+require('../behaviors/quick_submit'); // requires extensions/jquery
+require('../behaviors/requires_input');
+require('../behaviors/toggler_behavior');
+
+/*= require_directory ./blob */
+require('../blob/template_selector');
+require('../blob/blob_ci_yaml'); // requires template_selector
+require('../blob/blob_file_dropzone');
+require('../blob/blob_gitignore_selector');
+require('../blob/blob_gitignore_selectors');
+require('../blob/blob_license_selector');
+require('../blob/blob_license_selectors');
+
+/*= require_directory ./templates */
+require('../templates/issuable_template_selector');
+require('../templates/issuable_template_selectors');
+
+/*= require_directory ./commit */
+require('../commit/file');
+require('../commit/image_file');
+
+/*= require_directory ./extensions */
+require('../extensions/array');
+require('../extensions/element');
+
+/*= require_directory ./lib/utils */
+require('../lib/utils/animate');
+require('../lib/utils/common_utils');
+require('../lib/utils/datetime_utility');
+// require('../lib/utils/emoji_aliases.js.erb');
+window.gl.emojiAliases = function() { return require('emoji-aliases'); };
+require('../lib/utils/jquery.timeago');
+require('../lib/utils/notify');
+require('../lib/utils/text_utility');
+require('../lib/utils/type_utility');
+require('../lib/utils/url_utility');
+
+/*= require_directory ./u2f */
+require('../u2f/authenticate');
+require('../u2f/error');
+require('../u2f/register');
+require('../u2f/util');
+
+/*= require_directory . */
+require('../abuse_reports');
+require('../activities');
+require('../admin');
+require('../api');
+require('../aside');
+require('../awards_handler');
+require('../breakpoints');
+require('../broadcast_message');
+require('../build');
+require('../build_artifacts');
+require('../build_variables');
+require('../commit');
+require('../commits');
+require('../compare');
+require('../compare_autocomplete');
+require('../confirm_danger_modal');
+window.Clipboard = require('vendor/clipboard'); // required by copy_to_clipboard
+require('../copy_to_clipboard');
+require('../create_label');
+require('vue'); // required by cycle_analytics
+require('../cycle_analytics');
+require('../diff');
+require('../dispatcher');
+require('../preview_markdown');
+require('../dropzone_input');
+require('../due_date_select');
+require('../files_comment_button');
+require('../flash');
+require('../gfm_auto_complete');
+require('../gl_dropdown');
+require('../gl_field_errors');
+require('../gl_form');
+require('../group_avatar');
+require('../groups_select');
+require('../header');
+require('../importer_status');
+require('../issuable');
+require('../issuable_context');
+require('../issuable_form');
+require('vendor/task_list'); // required by issue
+require('../issue');
+require('../issue_status_select');
+require('../issues_bulk_assignment');
+require('../label_manager');
+require('../labels');
+require('../labels_select');
+require('../layout_nav');
+require('../line_highlighter');
+require('../logo');
+require('../member_expiration_date');
+require('../members');
+require('../merge_request_tabs');
+require('../merge_request');
+require('../merge_request_widget');
+require('../merged_buttons');
+require('../milestone');
+require('../milestone_select');
+require('../namespace_select');
+require('../new_branch_form');
+require('../new_commit_form');
+require('../notes');
+require('../notifications_dropdown');
+require('../notifications_form');
+require('../pager');
+require('../pipelines');
+require('../project');
+require('../project_avatar');
+require('../project_find_file');
+require('../project_fork');
+require('../project_import');
+require('../project_new');
+require('../project_select');
+require('../project_show');
+require('../projects_list');
+require('../right_sidebar');
+require('../search');
+require('../search_autocomplete');
+require('../shortcuts_blob');
+require('../shortcuts_find_file');
+require('../sidebar');
+require('../single_file_diff');
+require('../snippets_list');
+require('../star');
+require('../subscription');
+require('../subscription_select');
+require('../syntax_highlight');
+require('../todos');
+require('../tree');
+require('../user');
+require('../user_tabs');
+require('../username_validator');
+require('../users_select');
+require('vendor/latinise'); // required by wikis
+require('../wikis');
+require('../zen_mode');
+
+/*= require fuzzaldrin-plus */
+require('vendor/fuzzaldrin-plus');
+
+require('../application');
diff --git a/app/assets/javascripts/webpack/bundle.js b/app/assets/javascripts/webpack/bundle.js
deleted file mode 100644
index b8e38151e5f..00000000000
--- a/app/assets/javascripts/webpack/bundle.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var HelloWorld = require('./hello_world').default;
-
-var message = new HelloWorld('webpack');
-message.sayHello();
diff --git a/app/assets/javascripts/webpack/hello_world.js.es6 b/app/assets/javascripts/webpack/hello_world.js.es6
deleted file mode 100644
index b3d7c9dd4d4..00000000000
--- a/app/assets/javascripts/webpack/hello_world.js.es6
+++ /dev/null
@@ -1,11 +0,0 @@
-/* eslint-disable no-undef, no-alert */
-
-export default class HelloWorld {
- constructor(name) {
- this.message = `Hello ${name}!`;
- }
-
- sayHello() {
- alert(this.message);
- }
-}
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 87aadfb1bf5..d260e2133f2 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -28,8 +28,7 @@
= stylesheet_link_tag "application", media: "all"
= stylesheet_link_tag "print", media: "print"
- = javascript_include_tag "application"
- = javascript_include_tag *webpack_asset_paths("bundle")
+ = javascript_include_tag *webpack_asset_paths("application")
- if content_for?(:page_specific_javascripts)
= yield :page_specific_javascripts
diff --git a/config/webpack.config.js b/config/webpack.config.js
index acd5597da3a..d45638fbcbd 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -14,7 +14,7 @@ var DEV_SERVER_PORT = 3808;
var config = {
context: ROOT_PATH,
entry: {
- bundle: './app/assets/javascripts/webpack/bundle.js'
+ application: './app/assets/javascripts/webpack/application.js'
},
output: {
@@ -31,6 +31,15 @@ var config = {
test: /\.es6$/,
exclude: /node_modules/,
loader: 'babel-loader'
+ },
+ {
+ test: /\.(js|es6)$/,
+ loader: 'imports-loader',
+ query: 'this=>window'
+ },
+ {
+ test: /\.json$/,
+ loader: 'json-loader'
}
]
},
@@ -48,7 +57,14 @@ var config = {
],
resolve: {
- extensions: ['', '.js', '.es6', '.js.es6']
+ extensions: ['', '.js', '.es6', '.js.es6'],
+ alias: {
+ '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'
+ }
}
}
diff --git a/package.json b/package.json
index b089eb805c7..7ef811ae478 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,20 @@
"babel": "^5.8.38",
"babel-core": "^5.8.38",
"babel-loader": "^5.4.2",
+ "bootstrap-sass": "3.3.6",
+ "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": "1.0.26",
+ "vue-resource": "0.9.3",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.16.2"
},
diff --git a/vendor/assets/javascripts/jquery.atwho.js b/vendor/assets/javascripts/jquery.atwho.js
new file mode 100644
index 00000000000..0d295ebe5af
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.atwho.js
@@ -0,0 +1,1202 @@
+/**
+ * at.js - 1.5.1
+ * Copyright (c) 2016 chord.luo <chord.luo@gmail.com>;
+ * Homepage: http://ichord.github.com/At.js
+ * License: MIT
+ */
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module unless amdModuleId is set
+ define(["jquery"], function (a0) {
+ return (factory(a0));
+ });
+ } else if (typeof exports === 'object') {
+ // Node. Does not work with strict CommonJS, but
+ // only CommonJS-like environments that support module.exports,
+ // like Node.
+ module.exports = factory(require("jquery"));
+ } else {
+ factory(jQuery);
+ }
+}(this, function ($) {
+var DEFAULT_CALLBACKS, KEY_CODE;
+
+KEY_CODE = {
+ DOWN: 40,
+ UP: 38,
+ ESC: 27,
+ TAB: 9,
+ ENTER: 13,
+ CTRL: 17,
+ A: 65,
+ P: 80,
+ N: 78,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ BACKSPACE: 8,
+ SPACE: 32
+};
+
+DEFAULT_CALLBACKS = {
+ beforeSave: function(data) {
+ return Controller.arrayToDefaultHash(data);
+ },
+ matcher: function(flag, subtext, should_startWithSpace, acceptSpaceBar) {
+ var _a, _y, match, regexp, space;
+ flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ if (should_startWithSpace) {
+ flag = '(?:^|\\s)' + flag;
+ }
+ _a = decodeURI("%C3%80");
+ _y = decodeURI("%C3%BF");
+ space = acceptSpaceBar ? "\ " : "";
+ regexp = new RegExp(flag + "([A-Za-z" + _a + "-" + _y + "0-9_" + space + "\'\.\+\-]*)$|" + flag + "([^\\x00-\\xff]*)$", 'gi');
+ match = regexp.exec(subtext);
+ if (match) {
+ return match[2] || match[1];
+ } else {
+ return null;
+ }
+ },
+ filter: function(query, data, searchKey) {
+ var _results, i, item, len;
+ _results = [];
+ for (i = 0, len = data.length; i < len; i++) {
+ item = data[i];
+ if (~new String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase())) {
+ _results.push(item);
+ }
+ }
+ return _results;
+ },
+ remoteFilter: null,
+ sorter: function(query, items, searchKey) {
+ var _results, i, item, len;
+ if (!query) {
+ return items;
+ }
+ _results = [];
+ for (i = 0, len = items.length; i < len; i++) {
+ item = items[i];
+ item.atwho_order = new String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase());
+ if (item.atwho_order > -1) {
+ _results.push(item);
+ }
+ }
+ return _results.sort(function(a, b) {
+ return a.atwho_order - b.atwho_order;
+ });
+ },
+ tplEval: function(tpl, map) {
+ var error, error1, template;
+ template = tpl;
+ try {
+ if (typeof tpl !== 'string') {
+ template = tpl(map);
+ }
+ return template.replace(/\$\{([^\}]*)\}/g, function(tag, key, pos) {
+ return map[key];
+ });
+ } catch (error1) {
+ error = error1;
+ return "";
+ }
+ },
+ highlighter: function(li, query) {
+ var regexp;
+ if (!query) {
+ return li;
+ }
+ regexp = new RegExp(">\\s*(\\w*?)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig');
+ return li.replace(regexp, function(str, $1, $2, $3) {
+ return '> ' + $1 + '<strong>' + $2 + '</strong>' + $3 + ' <';
+ });
+ },
+ beforeInsert: function(value, $li, e) {
+ return value;
+ },
+ beforeReposition: function(offset) {
+ return offset;
+ },
+ afterMatchFailed: function(at, el) {}
+};
+
+var App;
+
+App = (function() {
+ function App(inputor) {
+ this.currentFlag = null;
+ this.controllers = {};
+ this.aliasMaps = {};
+ this.$inputor = $(inputor);
+ this.setupRootElement();
+ this.listen();
+ }
+
+ App.prototype.createContainer = function(doc) {
+ var ref;
+ if ((ref = this.$el) != null) {
+ ref.remove();
+ }
+ return $(doc.body).append(this.$el = $("<div class='atwho-container'></div>"));
+ };
+
+ App.prototype.setupRootElement = function(iframe, asRoot) {
+ var error, error1;
+ if (asRoot == null) {
+ asRoot = false;
+ }
+ if (iframe) {
+ this.window = iframe.contentWindow;
+ this.document = iframe.contentDocument || this.window.document;
+ this.iframe = iframe;
+ } else {
+ this.document = this.$inputor[0].ownerDocument;
+ this.window = this.document.defaultView || this.document.parentWindow;
+ try {
+ this.iframe = this.window.frameElement;
+ } catch (error1) {
+ error = error1;
+ this.iframe = null;
+ if ($.fn.atwho.debug) {
+ throw new Error("iframe auto-discovery is failed.\nPlease use `setIframe` to set the target iframe manually.\n" + error);
+ }
+ }
+ }
+ return this.createContainer((this.iframeAsRoot = asRoot) ? this.document : document);
+ };
+
+ App.prototype.controller = function(at) {
+ var c, current, currentFlag, ref;
+ if (this.aliasMaps[at]) {
+ current = this.controllers[this.aliasMaps[at]];
+ } else {
+ ref = this.controllers;
+ for (currentFlag in ref) {
+ c = ref[currentFlag];
+ if (currentFlag === at) {
+ current = c;
+ break;
+ }
+ }
+ }
+ if (current) {
+ return current;
+ } else {
+ return this.controllers[this.currentFlag];
+ }
+ };
+
+ App.prototype.setContextFor = function(at) {
+ this.currentFlag = at;
+ return this;
+ };
+
+ App.prototype.reg = function(flag, setting) {
+ var base, controller;
+ controller = (base = this.controllers)[flag] || (base[flag] = this.$inputor.is('[contentEditable]') ? new EditableController(this, flag) : new TextareaController(this, flag));
+ if (setting.alias) {
+ this.aliasMaps[setting.alias] = flag;
+ }
+ controller.init(setting);
+ return this;
+ };
+
+ App.prototype.listen = function() {
+ return this.$inputor.on('compositionstart', (function(_this) {
+ return function(e) {
+ var ref;
+ if ((ref = _this.controller()) != null) {
+ ref.view.hide();
+ }
+ _this.isComposing = true;
+ return null;
+ };
+ })(this)).on('compositionend', (function(_this) {
+ return function(e) {
+ _this.isComposing = false;
+ setTimeout(function(e) {
+ return _this.dispatch(e);
+ });
+ return null;
+ };
+ })(this)).on('keyup.atwhoInner', (function(_this) {
+ return function(e) {
+ return _this.onKeyup(e);
+ };
+ })(this)).on('keydown.atwhoInner', (function(_this) {
+ return function(e) {
+ return _this.onKeydown(e);
+ };
+ })(this)).on('blur.atwhoInner', (function(_this) {
+ return function(e) {
+ var c;
+ if (c = _this.controller()) {
+ c.expectedQueryCBId = null;
+ return c.view.hide(e, c.getOpt("displayTimeout"));
+ }
+ };
+ })(this)).on('click.atwhoInner', (function(_this) {
+ return function(e) {
+ return _this.dispatch(e);
+ };
+ })(this)).on('scroll.atwhoInner', (function(_this) {
+ return function() {
+ var lastScrollTop;
+ lastScrollTop = _this.$inputor.scrollTop();
+ return function(e) {
+ var currentScrollTop, ref;
+ currentScrollTop = e.target.scrollTop;
+ if (lastScrollTop !== currentScrollTop) {
+ if ((ref = _this.controller()) != null) {
+ ref.view.hide(e);
+ }
+ }
+ lastScrollTop = currentScrollTop;
+ return true;
+ };
+ };
+ })(this)());
+ };
+
+ App.prototype.shutdown = function() {
+ var _, c, ref;
+ ref = this.controllers;
+ for (_ in ref) {
+ c = ref[_];
+ c.destroy();
+ delete this.controllers[_];
+ }
+ this.$inputor.off('.atwhoInner');
+ return this.$el.remove();
+ };
+
+ App.prototype.dispatch = function(e) {
+ var _, c, ref, results;
+ ref = this.controllers;
+ results = [];
+ for (_ in ref) {
+ c = ref[_];
+ results.push(c.lookUp(e));
+ }
+ return results;
+ };
+
+ App.prototype.onKeyup = function(e) {
+ var ref;
+ switch (e.keyCode) {
+ case KEY_CODE.ESC:
+ e.preventDefault();
+ if ((ref = this.controller()) != null) {
+ ref.view.hide();
+ }
+ break;
+ case KEY_CODE.DOWN:
+ case KEY_CODE.UP:
+ case KEY_CODE.CTRL:
+ case KEY_CODE.ENTER:
+ $.noop();
+ break;
+ case KEY_CODE.P:
+ case KEY_CODE.N:
+ if (!e.ctrlKey) {
+ this.dispatch(e);
+ }
+ break;
+ default:
+ this.dispatch(e);
+ }
+ };
+
+ App.prototype.onKeydown = function(e) {
+ var ref, view;
+ view = (ref = this.controller()) != null ? ref.view : void 0;
+ if (!(view && view.visible())) {
+ return;
+ }
+ switch (e.keyCode) {
+ case KEY_CODE.ESC:
+ e.preventDefault();
+ view.hide(e);
+ break;
+ case KEY_CODE.UP:
+ e.preventDefault();
+ view.prev();
+ break;
+ case KEY_CODE.DOWN:
+ e.preventDefault();
+ view.next();
+ break;
+ case KEY_CODE.P:
+ if (!e.ctrlKey) {
+ return;
+ }
+ e.preventDefault();
+ view.prev();
+ break;
+ case KEY_CODE.N:
+ if (!e.ctrlKey) {
+ return;
+ }
+ e.preventDefault();
+ view.next();
+ break;
+ case KEY_CODE.TAB:
+ case KEY_CODE.ENTER:
+ case KEY_CODE.SPACE:
+ if (!view.visible()) {
+ return;
+ }
+ if (!this.controller().getOpt('spaceSelectsMatch') && e.keyCode === KEY_CODE.SPACE) {
+ return;
+ }
+ if (!this.controller().getOpt('tabSelectsMatch') && e.keyCode === KEY_CODE.TAB) {
+ return;
+ }
+ if (view.highlighted()) {
+ e.preventDefault();
+ view.choose(e);
+ } else {
+ view.hide(e);
+ }
+ break;
+ default:
+ $.noop();
+ }
+ };
+
+ return App;
+
+})();
+
+var Controller,
+ slice = [].slice;
+
+Controller = (function() {
+ Controller.prototype.uid = function() {
+ return (Math.random().toString(16) + "000000000").substr(2, 8) + (new Date().getTime());
+ };
+
+ function Controller(app, at1) {
+ this.app = app;
+ this.at = at1;
+ this.$inputor = this.app.$inputor;
+ this.id = this.$inputor[0].id || this.uid();
+ this.expectedQueryCBId = null;
+ this.setting = null;
+ this.query = null;
+ this.pos = 0;
+ this.range = null;
+ if ((this.$el = $("#atwho-ground-" + this.id, this.app.$el)).length === 0) {
+ this.app.$el.append(this.$el = $("<div id='atwho-ground-" + this.id + "'></div>"));
+ }
+ this.model = new Model(this);
+ this.view = new View(this);
+ }
+
+ Controller.prototype.init = function(setting) {
+ this.setting = $.extend({}, this.setting || $.fn.atwho["default"], setting);
+ this.view.init();
+ return this.model.reload(this.setting.data);
+ };
+
+ Controller.prototype.destroy = function() {
+ this.trigger('beforeDestroy');
+ this.model.destroy();
+ this.view.destroy();
+ return this.$el.remove();
+ };
+
+ Controller.prototype.callDefault = function() {
+ var args, error, error1, funcName;
+ funcName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
+ try {
+ return DEFAULT_CALLBACKS[funcName].apply(this, args);
+ } catch (error1) {
+ error = error1;
+ return $.error(error + " Or maybe At.js doesn't have function " + funcName);
+ }
+ };
+
+ Controller.prototype.trigger = function(name, data) {
+ var alias, eventName;
+ if (data == null) {
+ data = [];
+ }
+ data.push(this);
+ alias = this.getOpt('alias');
+ eventName = alias ? name + "-" + alias + ".atwho" : name + ".atwho";
+ return this.$inputor.trigger(eventName, data);
+ };
+
+ Controller.prototype.callbacks = function(funcName) {
+ return this.getOpt("callbacks")[funcName] || DEFAULT_CALLBACKS[funcName];
+ };
+
+ Controller.prototype.getOpt = function(at, default_value) {
+ var e, error1;
+ try {
+ return this.setting[at];
+ } catch (error1) {
+ e = error1;
+ return null;
+ }
+ };
+
+ Controller.prototype.insertContentFor = function($li) {
+ var data, tpl;
+ tpl = this.getOpt('insertTpl');
+ data = $.extend({}, $li.data('item-data'), {
+ 'atwho-at': this.at
+ });
+ return this.callbacks("tplEval").call(this, tpl, data, "onInsert");
+ };
+
+ Controller.prototype.renderView = function(data) {
+ var searchKey;
+ searchKey = this.getOpt("searchKey");
+ data = this.callbacks("sorter").call(this, this.query.text, data.slice(0, 1001), searchKey);
+ return this.view.render(data.slice(0, this.getOpt('limit')));
+ };
+
+ Controller.arrayToDefaultHash = function(data) {
+ var i, item, len, results;
+ if (!$.isArray(data)) {
+ return data;
+ }
+ results = [];
+ for (i = 0, len = data.length; i < len; i++) {
+ item = data[i];
+ if ($.isPlainObject(item)) {
+ results.push(item);
+ } else {
+ results.push({
+ name: item
+ });
+ }
+ }
+ return results;
+ };
+
+ Controller.prototype.lookUp = function(e) {
+ var query, wait;
+ if (e && e.type === 'click' && !this.getOpt('lookUpOnClick')) {
+ return;
+ }
+ if (this.getOpt('suspendOnComposing') && this.app.isComposing) {
+ return;
+ }
+ query = this.catchQuery(e);
+ if (!query) {
+ this.expectedQueryCBId = null;
+ return query;
+ }
+ this.app.setContextFor(this.at);
+ if (wait = this.getOpt('delay')) {
+ this._delayLookUp(query, wait);
+ } else {
+ this._lookUp(query);
+ }
+ return query;
+ };
+
+ Controller.prototype._delayLookUp = function(query, wait) {
+ var now, remaining;
+ now = Date.now ? Date.now() : new Date().getTime();
+ this.previousCallTime || (this.previousCallTime = now);
+ remaining = wait - (now - this.previousCallTime);
+ if ((0 < remaining && remaining < wait)) {
+ this.previousCallTime = now;
+ this._stopDelayedCall();
+ return this.delayedCallTimeout = setTimeout((function(_this) {
+ return function() {
+ _this.previousCallTime = 0;
+ _this.delayedCallTimeout = null;
+ return _this._lookUp(query);
+ };
+ })(this), wait);
+ } else {
+ this._stopDelayedCall();
+ if (this.previousCallTime !== now) {
+ this.previousCallTime = 0;
+ }
+ return this._lookUp(query);
+ }
+ };
+
+ Controller.prototype._stopDelayedCall = function() {
+ if (this.delayedCallTimeout) {
+ clearTimeout(this.delayedCallTimeout);
+ return this.delayedCallTimeout = null;
+ }
+ };
+
+ Controller.prototype._generateQueryCBId = function() {
+ return {};
+ };
+
+ Controller.prototype._lookUp = function(query) {
+ var _callback;
+ _callback = function(queryCBId, data) {
+ if (queryCBId !== this.expectedQueryCBId) {
+ return;
+ }
+ if (data && data.length > 0) {
+ return this.renderView(this.constructor.arrayToDefaultHash(data));
+ } else {
+ return this.view.hide();
+ }
+ };
+ this.expectedQueryCBId = this._generateQueryCBId();
+ return this.model.query(query.text, $.proxy(_callback, this, this.expectedQueryCBId));
+ };
+
+ return Controller;
+
+})();
+
+var TextareaController,
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty;
+
+TextareaController = (function(superClass) {
+ extend(TextareaController, superClass);
+
+ function TextareaController() {
+ return TextareaController.__super__.constructor.apply(this, arguments);
+ }
+
+ TextareaController.prototype.catchQuery = function() {
+ var caretPos, content, end, isString, query, start, subtext;
+ content = this.$inputor.val();
+ caretPos = this.$inputor.caret('pos', {
+ iframe: this.app.iframe
+ });
+ subtext = content.slice(0, caretPos);
+ query = this.callbacks("matcher").call(this, this.at, subtext, this.getOpt('startWithSpace'), this.getOpt("acceptSpaceBar"));
+ isString = typeof query === 'string';
+ if (isString && query.length < this.getOpt('minLen', 0)) {
+ return;
+ }
+ if (isString && query.length <= this.getOpt('maxLen', 20)) {
+ start = caretPos - query.length;
+ end = start + query.length;
+ this.pos = start;
+ query = {
+ 'text': query,
+ 'headPos': start,
+ 'endPos': end
+ };
+ this.trigger("matched", [this.at, query.text]);
+ } else {
+ query = null;
+ this.view.hide();
+ }
+ return this.query = query;
+ };
+
+ TextareaController.prototype.rect = function() {
+ var c, iframeOffset, scaleBottom;
+ if (!(c = this.$inputor.caret('offset', this.pos - 1, {
+ iframe: this.app.iframe
+ }))) {
+ return;
+ }
+ if (this.app.iframe && !this.app.iframeAsRoot) {
+ iframeOffset = $(this.app.iframe).offset();
+ c.left += iframeOffset.left;
+ c.top += iframeOffset.top;
+ }
+ scaleBottom = this.app.document.selection ? 0 : 2;
+ return {
+ left: c.left,
+ top: c.top,
+ bottom: c.top + c.height + scaleBottom
+ };
+ };
+
+ TextareaController.prototype.insert = function(content, $li) {
+ var $inputor, source, startStr, suffix, text;
+ $inputor = this.$inputor;
+ source = $inputor.val();
+ startStr = source.slice(0, Math.max(this.query.headPos - this.at.length, 0));
+ suffix = (suffix = this.getOpt('suffix')) === "" ? suffix : suffix || " ";
+ content += suffix;
+ text = "" + startStr + content + (source.slice(this.query['endPos'] || 0));
+ $inputor.val(text);
+ $inputor.caret('pos', startStr.length + content.length, {
+ iframe: this.app.iframe
+ });
+ if (!$inputor.is(':focus')) {
+ $inputor.focus();
+ }
+ return $inputor.change();
+ };
+
+ return TextareaController;
+
+})(Controller);
+
+var EditableController,
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty;
+
+EditableController = (function(superClass) {
+ extend(EditableController, superClass);
+
+ function EditableController() {
+ return EditableController.__super__.constructor.apply(this, arguments);
+ }
+
+ EditableController.prototype._getRange = function() {
+ var sel;
+ sel = this.app.window.getSelection();
+ if (sel.rangeCount > 0) {
+ return sel.getRangeAt(0);
+ }
+ };
+
+ EditableController.prototype._setRange = function(position, node, range) {
+ if (range == null) {
+ range = this._getRange();
+ }
+ if (!range) {
+ return;
+ }
+ node = $(node)[0];
+ if (position === 'after') {
+ range.setEndAfter(node);
+ range.setStartAfter(node);
+ } else {
+ range.setEndBefore(node);
+ range.setStartBefore(node);
+ }
+ range.collapse(false);
+ return this._clearRange(range);
+ };
+
+ EditableController.prototype._clearRange = function(range) {
+ var sel;
+ if (range == null) {
+ range = this._getRange();
+ }
+ sel = this.app.window.getSelection();
+ if (this.ctrl_a_pressed == null) {
+ sel.removeAllRanges();
+ return sel.addRange(range);
+ }
+ };
+
+ EditableController.prototype._movingEvent = function(e) {
+ var ref;
+ return e.type === 'click' || ((ref = e.which) === KEY_CODE.RIGHT || ref === KEY_CODE.LEFT || ref === KEY_CODE.UP || ref === KEY_CODE.DOWN);
+ };
+
+ EditableController.prototype._unwrap = function(node) {
+ var next;
+ node = $(node).unwrap().get(0);
+ if ((next = node.nextSibling) && next.nodeValue) {
+ node.nodeValue += next.nodeValue;
+ $(next).remove();
+ }
+ return node;
+ };
+
+ EditableController.prototype.catchQuery = function(e) {
+ var $inserted, $query, _range, index, inserted, isString, lastNode, matched, offset, query, query_content, range;
+ if (!(range = this._getRange())) {
+ return;
+ }
+ if (!range.collapsed) {
+ return;
+ }
+ if (e.which === KEY_CODE.ENTER) {
+ ($query = $(range.startContainer).closest('.atwho-query')).contents().unwrap();
+ if ($query.is(':empty')) {
+ $query.remove();
+ }
+ ($query = $(".atwho-query", this.app.document)).text($query.text()).contents().last().unwrap();
+ this._clearRange();
+ return;
+ }
+ if (/firefox/i.test(navigator.userAgent)) {
+ if ($(range.startContainer).is(this.$inputor)) {
+ this._clearRange();
+ return;
+ }
+ if (e.which === KEY_CODE.BACKSPACE && range.startContainer.nodeType === document.ELEMENT_NODE && (offset = range.startOffset - 1) >= 0) {
+ _range = range.cloneRange();
+ _range.setStart(range.startContainer, offset);
+ if ($(_range.cloneContents()).contents().last().is('.atwho-inserted')) {
+ inserted = $(range.startContainer).contents().get(offset);
+ this._setRange('after', $(inserted).contents().last());
+ }
+ } else if (e.which === KEY_CODE.LEFT && range.startContainer.nodeType === document.TEXT_NODE) {
+ $inserted = $(range.startContainer.previousSibling);
+ if ($inserted.is('.atwho-inserted') && range.startOffset === 0) {
+ this._setRange('after', $inserted.contents().last());
+ }
+ }
+ }
+ $(range.startContainer).closest('.atwho-inserted').addClass('atwho-query').siblings().removeClass('atwho-query');
+ if (($query = $(".atwho-query", this.app.document)).length > 0 && $query.is(':empty') && $query.text().length === 0) {
+ $query.remove();
+ }
+ if (!this._movingEvent(e)) {
+ $query.removeClass('atwho-inserted');
+ }
+ if ($query.length > 0) {
+ switch (e.which) {
+ case KEY_CODE.LEFT:
+ this._setRange('before', $query.get(0), range);
+ $query.removeClass('atwho-query');
+ return;
+ case KEY_CODE.RIGHT:
+ this._setRange('after', $query.get(0).nextSibling, range);
+ $query.removeClass('atwho-query');
+ return;
+ }
+ }
+ if ($query.length > 0 && (query_content = $query.attr('data-atwho-at-query'))) {
+ $query.empty().html(query_content).attr('data-atwho-at-query', null);
+ this._setRange('after', $query.get(0), range);
+ }
+ _range = range.cloneRange();
+ _range.setStart(range.startContainer, 0);
+ matched = this.callbacks("matcher").call(this, this.at, _range.toString(), this.getOpt('startWithSpace'), this.getOpt("acceptSpaceBar"));
+ isString = typeof matched === 'string';
+ if ($query.length === 0 && isString && (index = range.startOffset - this.at.length - matched.length) >= 0) {
+ range.setStart(range.startContainer, index);
+ $query = $('<span/>', this.app.document).attr(this.getOpt("editableAtwhoQueryAttrs")).addClass('atwho-query');
+ range.surroundContents($query.get(0));
+ lastNode = $query.contents().last().get(0);
+ if (/firefox/i.test(navigator.userAgent)) {
+ range.setStart(lastNode, lastNode.length);
+ range.setEnd(lastNode, lastNode.length);
+ this._clearRange(range);
+ } else {
+ this._setRange('after', lastNode, range);
+ }
+ }
+ if (isString && matched.length < this.getOpt('minLen', 0)) {
+ return;
+ }
+ if (isString && matched.length <= this.getOpt('maxLen', 20)) {
+ query = {
+ text: matched,
+ el: $query
+ };
+ this.trigger("matched", [this.at, query.text]);
+ return this.query = query;
+ } else {
+ this.view.hide();
+ this.query = {
+ el: $query
+ };
+ if ($query.text().indexOf(this.at) >= 0) {
+ if (this._movingEvent(e) && $query.hasClass('atwho-inserted')) {
+ $query.removeClass('atwho-query');
+ } else if (false !== this.callbacks('afterMatchFailed').call(this, this.at, $query)) {
+ this._setRange("after", this._unwrap($query.text($query.text()).contents().first()));
+ }
+ }
+ return null;
+ }
+ };
+
+ EditableController.prototype.rect = function() {
+ var $iframe, iframeOffset, rect;
+ rect = this.query.el.offset();
+ if (this.app.iframe && !this.app.iframeAsRoot) {
+ iframeOffset = ($iframe = $(this.app.iframe)).offset();
+ rect.left += iframeOffset.left - this.$inputor.scrollLeft();
+ rect.top += iframeOffset.top - this.$inputor.scrollTop();
+ }
+ rect.bottom = rect.top + this.query.el.height();
+ return rect;
+ };
+
+ EditableController.prototype.insert = function(content, $li) {
+ var data, range, suffix, suffixNode;
+ if (!this.$inputor.is(':focus')) {
+ this.$inputor.focus();
+ }
+ suffix = (suffix = this.getOpt('suffix')) === "" ? suffix : suffix || "\u00A0";
+ data = $li.data('item-data');
+ this.query.el.removeClass('atwho-query').addClass('atwho-inserted').html(content).attr('data-atwho-at-query', "" + data['atwho-at'] + this.query.text);
+ if (range = this._getRange()) {
+ range.setEndAfter(this.query.el[0]);
+ range.collapse(false);
+ range.insertNode(suffixNode = this.app.document.createTextNode("\u200D" + suffix));
+ this._setRange('after', suffixNode, range);
+ }
+ if (!this.$inputor.is(':focus')) {
+ this.$inputor.focus();
+ }
+ return this.$inputor.change();
+ };
+
+ return EditableController;
+
+})(Controller);
+
+var Model;
+
+Model = (function() {
+ function Model(context) {
+ this.context = context;
+ this.at = this.context.at;
+ this.storage = this.context.$inputor;
+ }
+
+ Model.prototype.destroy = function() {
+ return this.storage.data(this.at, null);
+ };
+
+ Model.prototype.saved = function() {
+ return this.fetch() > 0;
+ };
+
+ Model.prototype.query = function(query, callback) {
+ var _remoteFilter, data, searchKey;
+ data = this.fetch();
+ searchKey = this.context.getOpt("searchKey");
+ data = this.context.callbacks('filter').call(this.context, query, data, searchKey) || [];
+ _remoteFilter = this.context.callbacks('remoteFilter');
+ if (data.length > 0 || (!_remoteFilter && data.length === 0)) {
+ return callback(data);
+ } else {
+ return _remoteFilter.call(this.context, query, callback);
+ }
+ };
+
+ Model.prototype.fetch = function() {
+ return this.storage.data(this.at) || [];
+ };
+
+ Model.prototype.save = function(data) {
+ return this.storage.data(this.at, this.context.callbacks("beforeSave").call(this.context, data || []));
+ };
+
+ Model.prototype.load = function(data) {
+ if (!(this.saved() || !data)) {
+ return this._load(data);
+ }
+ };
+
+ Model.prototype.reload = function(data) {
+ return this._load(data);
+ };
+
+ Model.prototype._load = function(data) {
+ if (typeof data === "string") {
+ return $.ajax(data, {
+ dataType: "json"
+ }).done((function(_this) {
+ return function(data) {
+ return _this.save(data);
+ };
+ })(this));
+ } else {
+ return this.save(data);
+ }
+ };
+
+ return Model;
+
+})();
+
+var View;
+
+View = (function() {
+ function View(context) {
+ this.context = context;
+ this.$el = $("<div class='atwho-view'><ul class='atwho-view-ul'></ul></div>");
+ this.$elUl = this.$el.children();
+ this.timeoutID = null;
+ this.context.$el.append(this.$el);
+ this.bindEvent();
+ }
+
+ View.prototype.init = function() {
+ var header_tpl, id;
+ id = this.context.getOpt("alias") || this.context.at.charCodeAt(0);
+ header_tpl = this.context.getOpt("headerTpl");
+ if (header_tpl && this.$el.children().length === 1) {
+ this.$el.prepend(header_tpl);
+ }
+ return this.$el.attr({
+ 'id': "at-view-" + id
+ });
+ };
+
+ View.prototype.destroy = function() {
+ return this.$el.remove();
+ };
+
+ View.prototype.bindEvent = function() {
+ var $menu, lastCoordX, lastCoordY;
+ $menu = this.$el.find('ul');
+ lastCoordX = 0;
+ lastCoordY = 0;
+ return $menu.on('mousemove.atwho-view', 'li', (function(_this) {
+ return function(e) {
+ var $cur;
+ if (lastCoordX === e.clientX && lastCoordY === e.clientY) {
+ return;
+ }
+ lastCoordX = e.clientX;
+ lastCoordY = e.clientY;
+ $cur = $(e.currentTarget);
+ if ($cur.hasClass('cur')) {
+ return;
+ }
+ $menu.find('.cur').removeClass('cur');
+ return $cur.addClass('cur');
+ };
+ })(this)).on('click.atwho-view', 'li', (function(_this) {
+ return function(e) {
+ $menu.find('.cur').removeClass('cur');
+ $(e.currentTarget).addClass('cur');
+ _this.choose(e);
+ return e.preventDefault();
+ };
+ })(this));
+ };
+
+ View.prototype.visible = function() {
+ return this.$el.is(":visible");
+ };
+
+ View.prototype.highlighted = function() {
+ return this.$el.find(".cur").length > 0;
+ };
+
+ View.prototype.choose = function(e) {
+ var $li, content;
+ if (($li = this.$el.find(".cur")).length) {
+ content = this.context.insertContentFor($li);
+ this.context._stopDelayedCall();
+ this.context.insert(this.context.callbacks("beforeInsert").call(this.context, content, $li, e), $li);
+ this.context.trigger("inserted", [$li, e]);
+ this.hide(e);
+ }
+ if (this.context.getOpt("hideWithoutSuffix")) {
+ return this.stopShowing = true;
+ }
+ };
+
+ View.prototype.reposition = function(rect) {
+ var _window, offset, overflowOffset, ref;
+ _window = this.context.app.iframeAsRoot ? this.context.app.window : window;
+ if (rect.bottom + this.$el.height() - $(_window).scrollTop() > $(_window).height()) {
+ rect.bottom = rect.top - this.$el.height();
+ }
+ if (rect.left > (overflowOffset = $(_window).width() - this.$el.width() - 5)) {
+ rect.left = overflowOffset;
+ }
+ offset = {
+ left: rect.left,
+ top: rect.bottom
+ };
+ if ((ref = this.context.callbacks("beforeReposition")) != null) {
+ ref.call(this.context, offset);
+ }
+ this.$el.offset(offset);
+ return this.context.trigger("reposition", [offset]);
+ };
+
+ View.prototype.next = function() {
+ var cur, next, nextEl, offset;
+ cur = this.$el.find('.cur').removeClass('cur');
+ next = cur.next();
+ if (!next.length) {
+ next = this.$el.find('li:first');
+ }
+ next.addClass('cur');
+ nextEl = next[0];
+ offset = nextEl.offsetTop + nextEl.offsetHeight + (nextEl.nextSibling ? nextEl.nextSibling.offsetHeight : 0);
+ return this.scrollTop(Math.max(0, offset - this.$el.height()));
+ };
+
+ View.prototype.prev = function() {
+ var cur, offset, prev, prevEl;
+ cur = this.$el.find('.cur').removeClass('cur');
+ prev = cur.prev();
+ if (!prev.length) {
+ prev = this.$el.find('li:last');
+ }
+ prev.addClass('cur');
+ prevEl = prev[0];
+ offset = prevEl.offsetTop + prevEl.offsetHeight + (prevEl.nextSibling ? prevEl.nextSibling.offsetHeight : 0);
+ return this.scrollTop(Math.max(0, offset - this.$el.height()));
+ };
+
+ View.prototype.scrollTop = function(scrollTop) {
+ var scrollDuration;
+ scrollDuration = this.context.getOpt('scrollDuration');
+ if (scrollDuration) {
+ return this.$elUl.animate({
+ scrollTop: scrollTop
+ }, scrollDuration);
+ } else {
+ return this.$elUl.scrollTop(scrollTop);
+ }
+ };
+
+ View.prototype.show = function() {
+ var rect;
+ if (this.stopShowing) {
+ this.stopShowing = false;
+ return;
+ }
+ if (!this.visible()) {
+ this.$el.show();
+ this.$el.scrollTop(0);
+ this.context.trigger('shown');
+ }
+ if (rect = this.context.rect()) {
+ return this.reposition(rect);
+ }
+ };
+
+ View.prototype.hide = function(e, time) {
+ var callback;
+ if (!this.visible()) {
+ return;
+ }
+ if (isNaN(time)) {
+ this.$el.hide();
+ return this.context.trigger('hidden', [e]);
+ } else {
+ callback = (function(_this) {
+ return function() {
+ return _this.hide();
+ };
+ })(this);
+ clearTimeout(this.timeoutID);
+ return this.timeoutID = setTimeout(callback, time);
+ }
+ };
+
+ View.prototype.render = function(list) {
+ var $li, $ul, i, item, len, li, tpl;
+ if (!($.isArray(list) && list.length > 0)) {
+ this.hide();
+ return;
+ }
+ this.$el.find('ul').empty();
+ $ul = this.$el.find('ul');
+ tpl = this.context.getOpt('displayTpl');
+ for (i = 0, len = list.length; i < len; i++) {
+ item = list[i];
+ item = $.extend({}, item, {
+ 'atwho-at': this.context.at
+ });
+ li = this.context.callbacks("tplEval").call(this.context, tpl, item, "onDisplay");
+ $li = $(this.context.callbacks("highlighter").call(this.context, li, this.context.query.text));
+ $li.data("item-data", item);
+ $ul.append($li);
+ }
+ this.show();
+ if (this.context.getOpt('highlightFirst')) {
+ return $ul.find("li:first").addClass("cur");
+ }
+ };
+
+ return View;
+
+})();
+
+var Api;
+
+Api = {
+ load: function(at, data) {
+ var c;
+ if (c = this.controller(at)) {
+ return c.model.load(data);
+ }
+ },
+ isSelecting: function() {
+ var ref;
+ return !!((ref = this.controller()) != null ? ref.view.visible() : void 0);
+ },
+ hide: function() {
+ var ref;
+ return (ref = this.controller()) != null ? ref.view.hide() : void 0;
+ },
+ reposition: function() {
+ var c;
+ if (c = this.controller()) {
+ return c.view.reposition(c.rect());
+ }
+ },
+ setIframe: function(iframe, asRoot) {
+ this.setupRootElement(iframe, asRoot);
+ return null;
+ },
+ run: function() {
+ return this.dispatch();
+ },
+ destroy: function() {
+ this.shutdown();
+ return this.$inputor.data('atwho', null);
+ }
+};
+
+$.fn.atwho = function(method) {
+ var _args, result;
+ _args = arguments;
+ result = null;
+ this.filter('textarea, input, [contenteditable=""], [contenteditable=true]').each(function() {
+ var $this, app;
+ if (!(app = ($this = $(this)).data("atwho"))) {
+ $this.data('atwho', (app = new App(this)));
+ }
+ if (typeof method === 'object' || !method) {
+ return app.reg(method.at, method);
+ } else if (Api[method] && app) {
+ return result = Api[method].apply(app, Array.prototype.slice.call(_args, 1));
+ } else {
+ return $.error("Method " + method + " does not exist on jQuery.atwho");
+ }
+ });
+ if (result != null) {
+ return result;
+ } else {
+ return this;
+ }
+};
+
+$.fn.atwho["default"] = {
+ at: void 0,
+ alias: void 0,
+ data: null,
+ displayTpl: "<li>${name}</li>",
+ insertTpl: "${atwho-at}${name}",
+ headerTpl: null,
+ callbacks: DEFAULT_CALLBACKS,
+ searchKey: "name",
+ suffix: void 0,
+ hideWithoutSuffix: false,
+ startWithSpace: true,
+ acceptSpaceBar: false,
+ highlightFirst: true,
+ limit: 5,
+ maxLen: 20,
+ minLen: 0,
+ displayTimeout: 300,
+ delay: null,
+ spaceSelectsMatch: false,
+ tabSelectsMatch: true,
+ editableAtwhoQueryAttrs: {},
+ scrollDuration: 150,
+ suspendOnComposing: true,
+ lookUpOnClick: true
+};
+
+$.fn.atwho.debug = false;
+
+}));
diff --git a/vendor/assets/javascripts/jquery.caret.js b/vendor/assets/javascripts/jquery.caret.js
new file mode 100644
index 00000000000..811ec63ee47
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.caret.js
@@ -0,0 +1,436 @@
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(["jquery"], function ($) {
+ return (root.returnExportsGlobal = factory($));
+ });
+ } else if (typeof exports === 'object') {
+ // Node. Does not work with strict CommonJS, but
+ // only CommonJS-like enviroments that support module.exports,
+ // like Node.
+ module.exports = factory(require("jquery"));
+ } else {
+ factory(jQuery);
+ }
+}(this, function ($) {
+
+/*
+ Implement Github like autocomplete mentions
+ http://ichord.github.com/At.js
+
+ Copyright (c) 2013 chord.luo@gmail.com
+ Licensed under the MIT license.
+*/
+
+/*
+本插件操作 textarea 或者 input 内的插入符
+只实现了获得插入符在文本框中的位置,我设置
+插入符的位置.
+*/
+
+"use strict";
+var EditableCaret, InputCaret, Mirror, Utils, discoveryIframeOf, methods, oDocument, oFrame, oWindow, pluginName, setContextBy;
+
+pluginName = 'caret';
+
+EditableCaret = (function() {
+ function EditableCaret($inputor) {
+ this.$inputor = $inputor;
+ this.domInputor = this.$inputor[0];
+ }
+
+ EditableCaret.prototype.setPos = function(pos) {
+ var fn, found, offset, sel;
+ if (sel = oWindow.getSelection()) {
+ offset = 0;
+ found = false;
+ (fn = function(pos, parent) {
+ var node, range, _i, _len, _ref, _results;
+ _ref = parent.childNodes;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ node = _ref[_i];
+ if (found) {
+ break;
+ }
+ if (node.nodeType === 3) {
+ if (offset + node.length >= pos) {
+ found = true;
+ range = oDocument.createRange();
+ range.setStart(node, pos - offset);
+ sel.removeAllRanges();
+ sel.addRange(range);
+ break;
+ } else {
+ _results.push(offset += node.length);
+ }
+ } else {
+ _results.push(fn(pos, node));
+ }
+ }
+ return _results;
+ })(pos, this.domInputor);
+ }
+ return this.domInputor;
+ };
+
+ EditableCaret.prototype.getIEPosition = function() {
+ return this.getPosition();
+ };
+
+ EditableCaret.prototype.getPosition = function() {
+ var inputor_offset, offset;
+ offset = this.getOffset();
+ inputor_offset = this.$inputor.offset();
+ offset.left -= inputor_offset.left;
+ offset.top -= inputor_offset.top;
+ return offset;
+ };
+
+ EditableCaret.prototype.getOldIEPos = function() {
+ var preCaretTextRange, textRange;
+ textRange = oDocument.selection.createRange();
+ preCaretTextRange = oDocument.body.createTextRange();
+ preCaretTextRange.moveToElementText(this.domInputor);
+ preCaretTextRange.setEndPoint("EndToEnd", textRange);
+ return preCaretTextRange.text.length;
+ };
+
+ EditableCaret.prototype.getPos = function() {
+ var clonedRange, pos, range;
+ if (range = this.range()) {
+ clonedRange = range.cloneRange();
+ clonedRange.selectNodeContents(this.domInputor);
+ clonedRange.setEnd(range.endContainer, range.endOffset);
+ pos = clonedRange.toString().length;
+ clonedRange.detach();
+ return pos;
+ } else if (oDocument.selection) {
+ return this.getOldIEPos();
+ }
+ };
+
+ EditableCaret.prototype.getOldIEOffset = function() {
+ var range, rect;
+ range = oDocument.selection.createRange().duplicate();
+ range.moveStart("character", -1);
+ rect = range.getBoundingClientRect();
+ return {
+ height: rect.bottom - rect.top,
+ left: rect.left,
+ top: rect.top
+ };
+ };
+
+ EditableCaret.prototype.getOffset = function(pos) {
+ var clonedRange, offset, range, rect, shadowCaret;
+ if (oWindow.getSelection && (range = this.range())) {
+ if (range.endOffset - 1 > 0 && range.endContainer !== this.domInputor) {
+ clonedRange = range.cloneRange();
+ clonedRange.setStart(range.endContainer, range.endOffset - 1);
+ clonedRange.setEnd(range.endContainer, range.endOffset);
+ rect = clonedRange.getBoundingClientRect();
+ offset = {
+ height: rect.height,
+ left: rect.left + rect.width,
+ top: rect.top
+ };
+ clonedRange.detach();
+ }
+ if (!offset || (offset != null ? offset.height : void 0) === 0) {
+ clonedRange = range.cloneRange();
+ shadowCaret = $(oDocument.createTextNode("|"));
+ clonedRange.insertNode(shadowCaret[0]);
+ clonedRange.selectNode(shadowCaret[0]);
+ rect = clonedRange.getBoundingClientRect();
+ offset = {
+ height: rect.height,
+ left: rect.left,
+ top: rect.top
+ };
+ shadowCaret.remove();
+ clonedRange.detach();
+ }
+ } else if (oDocument.selection) {
+ offset = this.getOldIEOffset();
+ }
+ if (offset) {
+ offset.top += $(oWindow).scrollTop();
+ offset.left += $(oWindow).scrollLeft();
+ }
+ return offset;
+ };
+
+ EditableCaret.prototype.range = function() {
+ var sel;
+ if (!oWindow.getSelection) {
+ return;
+ }
+ sel = oWindow.getSelection();
+ if (sel.rangeCount > 0) {
+ return sel.getRangeAt(0);
+ } else {
+ return null;
+ }
+ };
+
+ return EditableCaret;
+
+})();
+
+InputCaret = (function() {
+ function InputCaret($inputor) {
+ this.$inputor = $inputor;
+ this.domInputor = this.$inputor[0];
+ }
+
+ InputCaret.prototype.getIEPos = function() {
+ var endRange, inputor, len, normalizedValue, pos, range, textInputRange;
+ inputor = this.domInputor;
+ range = oDocument.selection.createRange();
+ pos = 0;
+ if (range && range.parentElement() === inputor) {
+ normalizedValue = inputor.value.replace(/\r\n/g, "\n");
+ len = normalizedValue.length;
+ textInputRange = inputor.createTextRange();
+ textInputRange.moveToBookmark(range.getBookmark());
+ endRange = inputor.createTextRange();
+ endRange.collapse(false);
+ if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
+ pos = len;
+ } else {
+ pos = -textInputRange.moveStart("character", -len);
+ }
+ }
+ return pos;
+ };
+
+ InputCaret.prototype.getPos = function() {
+ if (oDocument.selection) {
+ return this.getIEPos();
+ } else {
+ return this.domInputor.selectionStart;
+ }
+ };
+
+ InputCaret.prototype.setPos = function(pos) {
+ var inputor, range;
+ inputor = this.domInputor;
+ if (oDocument.selection) {
+ range = inputor.createTextRange();
+ range.move("character", pos);
+ range.select();
+ } else if (inputor.setSelectionRange) {
+ inputor.setSelectionRange(pos, pos);
+ }
+ return inputor;
+ };
+
+ InputCaret.prototype.getIEOffset = function(pos) {
+ var h, textRange, x, y;
+ textRange = this.domInputor.createTextRange();
+ pos || (pos = this.getPos());
+ textRange.move('character', pos);
+ x = textRange.boundingLeft;
+ y = textRange.boundingTop;
+ h = textRange.boundingHeight;
+ return {
+ left: x,
+ top: y,
+ height: h
+ };
+ };
+
+ InputCaret.prototype.getOffset = function(pos) {
+ var $inputor, offset, position;
+ $inputor = this.$inputor;
+ if (oDocument.selection) {
+ offset = this.getIEOffset(pos);
+ offset.top += $(oWindow).scrollTop() + $inputor.scrollTop();
+ offset.left += $(oWindow).scrollLeft() + $inputor.scrollLeft();
+ return offset;
+ } else {
+ offset = $inputor.offset();
+ position = this.getPosition(pos);
+ return offset = {
+ left: offset.left + position.left - $inputor.scrollLeft(),
+ top: offset.top + position.top - $inputor.scrollTop(),
+ height: position.height
+ };
+ }
+ };
+
+ InputCaret.prototype.getPosition = function(pos) {
+ var $inputor, at_rect, end_range, format, html, mirror, start_range;
+ $inputor = this.$inputor;
+ format = function(value) {
+ value = value.replace(/<|>|`|"|&/g, '?').replace(/\r\n|\r|\n/g, "<br/>");
+ if (/firefox/i.test(navigator.userAgent)) {
+ value = value.replace(/\s/g, '&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;
+
+
+}));
diff --git a/vendor/assets/javascripts/jquery.turbolinks.js b/vendor/assets/javascripts/jquery.turbolinks.js
new file mode 100644
index 00000000000..fd6e95e75d5
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.turbolinks.js
@@ -0,0 +1,49 @@
+// Generated by CoffeeScript 1.7.1
+
+/*
+jQuery.Turbolinks ~ https://github.com/kossnocorp/jquery.turbolinks
+jQuery plugin for drop-in fix binded events problem caused by Turbolinks
+
+The MIT License
+Copyright (c) 2012-2013 Sasha Koss & Rico Sta. Cruz
+ */
+
+(function() {
+ var $, $document;
+
+ $ = window.jQuery || (typeof require === "function" ? require('jquery') : void 0);
+
+ $document = $(document);
+
+ $.turbo = {
+ version: '2.1.0',
+ isReady: false,
+ use: function(load, fetch) {
+ return $document.off('.turbo').on("" + load + ".turbo", this.onLoad).on("" + fetch + ".turbo", this.onFetch);
+ },
+ addCallback: function(callback) {
+ if ($.turbo.isReady) {
+ callback($);
+ }
+ return $document.on('turbo:ready', function() {
+ return callback($);
+ });
+ },
+ onLoad: function() {
+ $.turbo.isReady = true;
+ return $document.trigger('turbo:ready');
+ },
+ onFetch: function() {
+ return $.turbo.isReady = false;
+ },
+ register: function() {
+ $(this.onLoad);
+ return $.fn.ready = this.addCallback;
+ }
+ };
+
+ $.turbo.register();
+
+ $.turbo.use('page:load', 'page:fetch');
+
+}).call(this);
diff --git a/vendor/assets/javascripts/turbolinks.js b/vendor/assets/javascripts/turbolinks.js
new file mode 100644
index 00000000000..17a2635bf2a
--- /dev/null
+++ b/vendor/assets/javascripts/turbolinks.js
@@ -0,0 +1,781 @@
+// Turbolinks Classic v2.5.3 compiled from CoffeeScript
+(function() {
+ var CSRFToken, Click, ComponentUrl, EVENTS, Link, ProgressBar, browserIsntBuggy, browserSupportsCustomEvents, browserSupportsPushState, browserSupportsTurbolinks, bypassOnLoadPopstate, cacheCurrentPage, cacheSize, changePage, clone, constrainPageCacheTo, createDocument, crossOriginRedirect, currentState, enableProgressBar, enableTransitionCache, executeScriptTags, extractTitleAndBody, fetch, fetchHistory, fetchReplacement, historyStateIsDefined, initializeTurbolinks, installDocumentReadyPageEventTriggers, installHistoryChangeHandler, installJqueryAjaxSuccessPageUpdateTrigger, loadedAssets, manuallyTriggerHashChangeForFirefox, pageCache, pageChangePrevented, pagesCached, popCookie, processResponse, progressBar, recallScrollPosition, ref, referer, reflectNewUrl, reflectRedirectedUrl, rememberCurrentState, rememberCurrentUrl, rememberReferer, removeNoscriptTags, requestMethodIsSafe, resetScrollPosition, setAutofocusElement, transitionCacheEnabled, transitionCacheFor, triggerEvent, visit, xhr,
+ indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty,
+ slice = [].slice,
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+
+ pageCache = {};
+
+ cacheSize = 10;
+
+ transitionCacheEnabled = false;
+
+ progressBar = null;
+
+ currentState = null;
+
+ loadedAssets = null;
+
+ referer = null;
+
+ xhr = null;
+
+ EVENTS = {
+ BEFORE_CHANGE: 'page:before-change',
+ FETCH: 'page:fetch',
+ RECEIVE: 'page:receive',
+ CHANGE: 'page:change',
+ UPDATE: 'page:update',
+ LOAD: 'page:load',
+ RESTORE: 'page:restore',
+ BEFORE_UNLOAD: 'page:before-unload',
+ EXPIRE: 'page:expire'
+ };
+
+ fetch = function(url) {
+ var cachedPage;
+ url = new ComponentUrl(url);
+ rememberReferer();
+ cacheCurrentPage();
+ if (progressBar != null) {
+ progressBar.start();
+ }
+ if (transitionCacheEnabled && (cachedPage = transitionCacheFor(url.absolute))) {
+ fetchHistory(cachedPage);
+ return fetchReplacement(url, null, false);
+ } else {
+ return fetchReplacement(url, resetScrollPosition);
+ }
+ };
+
+ transitionCacheFor = function(url) {
+ var cachedPage;
+ cachedPage = pageCache[url];
+ if (cachedPage && !cachedPage.transitionCacheDisabled) {
+ return cachedPage;
+ }
+ };
+
+ enableTransitionCache = function(enable) {
+ if (enable == null) {
+ enable = true;
+ }
+ return transitionCacheEnabled = enable;
+ };
+
+ enableProgressBar = function(enable) {
+ if (enable == null) {
+ enable = true;
+ }
+ if (!browserSupportsTurbolinks) {
+ return;
+ }
+ if (enable) {
+ return progressBar != null ? progressBar : progressBar = new ProgressBar('html');
+ } else {
+ if (progressBar != null) {
+ progressBar.uninstall();
+ }
+ return progressBar = null;
+ }
+ };
+
+ fetchReplacement = function(url, onLoadFunction, showProgressBar) {
+ if (showProgressBar == null) {
+ showProgressBar = true;
+ }
+ triggerEvent(EVENTS.FETCH, {
+ url: url.absolute
+ });
+ if (xhr != null) {
+ xhr.abort();
+ }
+ xhr = new XMLHttpRequest;
+ xhr.open('GET', url.withoutHashForIE10compatibility(), true);
+ xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml');
+ xhr.setRequestHeader('X-XHR-Referer', referer);
+ xhr.onload = function() {
+ var doc;
+ triggerEvent(EVENTS.RECEIVE, {
+ url: url.absolute
+ });
+ if (doc = processResponse()) {
+ reflectNewUrl(url);
+ reflectRedirectedUrl();
+ changePage.apply(null, extractTitleAndBody(doc));
+ manuallyTriggerHashChangeForFirefox();
+ if (typeof onLoadFunction === "function") {
+ onLoadFunction();
+ }
+ return triggerEvent(EVENTS.LOAD);
+ } else {
+ return document.location.href = crossOriginRedirect() || url.absolute;
+ }
+ };
+ if (progressBar && showProgressBar) {
+ xhr.onprogress = (function(_this) {
+ return function(event) {
+ var percent;
+ percent = event.lengthComputable ? event.loaded / event.total * 100 : progressBar.value + (100 - progressBar.value) / 10;
+ return progressBar.advanceTo(percent);
+ };
+ })(this);
+ }
+ xhr.onloadend = function() {
+ return xhr = null;
+ };
+ xhr.onerror = function() {
+ return document.location.href = url.absolute;
+ };
+ return xhr.send();
+ };
+
+ fetchHistory = function(cachedPage) {
+ if (xhr != null) {
+ xhr.abort();
+ }
+ changePage(cachedPage.title, cachedPage.body);
+ recallScrollPosition(cachedPage);
+ return triggerEvent(EVENTS.RESTORE);
+ };
+
+ cacheCurrentPage = function() {
+ var currentStateUrl;
+ currentStateUrl = new ComponentUrl(currentState.url);
+ pageCache[currentStateUrl.absolute] = {
+ url: currentStateUrl.relative,
+ body: document.body,
+ title: document.title,
+ positionY: window.pageYOffset,
+ positionX: window.pageXOffset,
+ cachedAt: new Date().getTime(),
+ transitionCacheDisabled: document.querySelector('[data-no-transition-cache]') != null
+ };
+ return constrainPageCacheTo(cacheSize);
+ };
+
+ pagesCached = function(size) {
+ if (size == null) {
+ size = cacheSize;
+ }
+ if (/^[\d]+$/.test(size)) {
+ return cacheSize = parseInt(size);
+ }
+ };
+
+ constrainPageCacheTo = function(limit) {
+ var cacheTimesRecentFirst, i, key, len, pageCacheKeys, results;
+ pageCacheKeys = Object.keys(pageCache);
+ cacheTimesRecentFirst = pageCacheKeys.map(function(url) {
+ return pageCache[url].cachedAt;
+ }).sort(function(a, b) {
+ return b - a;
+ });
+ results = [];
+ for (i = 0, len = pageCacheKeys.length; i < len; i++) {
+ key = pageCacheKeys[i];
+ if (!(pageCache[key].cachedAt <= cacheTimesRecentFirst[limit])) {
+ continue;
+ }
+ triggerEvent(EVENTS.EXPIRE, pageCache[key]);
+ results.push(delete pageCache[key]);
+ }
+ return results;
+ };
+
+ changePage = function(title, body, csrfToken, runScripts) {
+ triggerEvent(EVENTS.BEFORE_UNLOAD);
+ document.title = title;
+ document.documentElement.replaceChild(body, document.body);
+ if (csrfToken != null) {
+ CSRFToken.update(csrfToken);
+ }
+ setAutofocusElement();
+ if (runScripts) {
+ executeScriptTags();
+ }
+ currentState = window.history.state;
+ if (progressBar != null) {
+ progressBar.done();
+ }
+ triggerEvent(EVENTS.CHANGE);
+ return triggerEvent(EVENTS.UPDATE);
+ };
+
+ executeScriptTags = function() {
+ var attr, copy, i, j, len, len1, nextSibling, parentNode, ref, ref1, script, scripts;
+ scripts = Array.prototype.slice.call(document.body.querySelectorAll('script:not([data-turbolinks-eval="false"])'));
+ for (i = 0, len = scripts.length; i < len; i++) {
+ script = scripts[i];
+ if (!((ref = script.type) === '' || ref === 'text/javascript')) {
+ continue;
+ }
+ copy = document.createElement('script');
+ ref1 = script.attributes;
+ for (j = 0, len1 = ref1.length; j < len1; j++) {
+ attr = ref1[j];
+ copy.setAttribute(attr.name, attr.value);
+ }
+ if (!script.hasAttribute('async')) {
+ copy.async = false;
+ }
+ copy.appendChild(document.createTextNode(script.innerHTML));
+ parentNode = script.parentNode, nextSibling = script.nextSibling;
+ parentNode.removeChild(script);
+ parentNode.insertBefore(copy, nextSibling);
+ }
+ };
+
+ removeNoscriptTags = function(node) {
+ node.innerHTML = node.innerHTML.replace(/<noscript[\S\s]*?<\/noscript>/ig, '');
+ return node;
+ };
+
+ setAutofocusElement = function() {
+ var autofocusElement, list;
+ autofocusElement = (list = document.querySelectorAll('input[autofocus], textarea[autofocus]'))[list.length - 1];
+ if (autofocusElement && document.activeElement !== autofocusElement) {
+ return autofocusElement.focus();
+ }
+ };
+
+ reflectNewUrl = function(url) {
+ if ((url = new ComponentUrl(url)).absolute !== referer) {
+ return window.history.pushState({
+ turbolinks: true,
+ url: url.absolute
+ }, '', url.absolute);
+ }
+ };
+
+ reflectRedirectedUrl = function() {
+ var location, preservedHash;
+ if (location = xhr.getResponseHeader('X-XHR-Redirected-To')) {
+ location = new ComponentUrl(location);
+ preservedHash = location.hasNoHash() ? document.location.hash : '';
+ return window.history.replaceState(window.history.state, '', location.href + preservedHash);
+ }
+ };
+
+ crossOriginRedirect = function() {
+ var redirect;
+ if (((redirect = xhr.getResponseHeader('Location')) != null) && (new ComponentUrl(redirect)).crossOrigin()) {
+ return redirect;
+ }
+ };
+
+ rememberReferer = function() {
+ return referer = document.location.href;
+ };
+
+ rememberCurrentUrl = function() {
+ return window.history.replaceState({
+ turbolinks: true,
+ url: document.location.href
+ }, '', document.location.href);
+ };
+
+ rememberCurrentState = function() {
+ return currentState = window.history.state;
+ };
+
+ manuallyTriggerHashChangeForFirefox = function() {
+ var url;
+ if (navigator.userAgent.match(/Firefox/) && !(url = new ComponentUrl).hasNoHash()) {
+ window.history.replaceState(currentState, '', url.withoutHash());
+ return document.location.hash = url.hash;
+ }
+ };
+
+ recallScrollPosition = function(page) {
+ return window.scrollTo(page.positionX, page.positionY);
+ };
+
+ resetScrollPosition = function() {
+ if (document.location.hash) {
+ return document.location.href = document.location.href;
+ } else {
+ return window.scrollTo(0, 0);
+ }
+ };
+
+ clone = function(original) {
+ var copy, key, value;
+ if ((original == null) || typeof original !== 'object') {
+ return original;
+ }
+ copy = new original.constructor();
+ for (key in original) {
+ value = original[key];
+ copy[key] = clone(value);
+ }
+ return copy;
+ };
+
+ popCookie = function(name) {
+ var ref, value;
+ value = ((ref = document.cookie.match(new RegExp(name + "=(\\w+)"))) != null ? ref[1].toUpperCase() : void 0) || '';
+ document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/';
+ return value;
+ };
+
+ triggerEvent = function(name, data) {
+ var event;
+ if (typeof Prototype !== 'undefined') {
+ Event.fire(document, name, data, true);
+ }
+ event = document.createEvent('Events');
+ if (data) {
+ event.data = data;
+ }
+ event.initEvent(name, true, true);
+ return document.dispatchEvent(event);
+ };
+
+ pageChangePrevented = function(url) {
+ return !triggerEvent(EVENTS.BEFORE_CHANGE, {
+ url: url
+ });
+ };
+
+ processResponse = function() {
+ var assetsChanged, clientOrServerError, doc, extractTrackAssets, intersection, validContent;
+ clientOrServerError = function() {
+ var ref;
+ return (400 <= (ref = xhr.status) && ref < 600);
+ };
+ validContent = function() {
+ var contentType;
+ return ((contentType = xhr.getResponseHeader('Content-Type')) != null) && contentType.match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/);
+ };
+ extractTrackAssets = function(doc) {
+ var i, len, node, ref, results;
+ ref = doc.querySelector('head').childNodes;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ node = ref[i];
+ if ((typeof node.getAttribute === "function" ? node.getAttribute('data-turbolinks-track') : void 0) != null) {
+ results.push(node.getAttribute('src') || node.getAttribute('href'));
+ }
+ }
+ return results;
+ };
+ assetsChanged = function(doc) {
+ var fetchedAssets;
+ loadedAssets || (loadedAssets = extractTrackAssets(document));
+ fetchedAssets = extractTrackAssets(doc);
+ return fetchedAssets.length !== loadedAssets.length || intersection(fetchedAssets, loadedAssets).length !== loadedAssets.length;
+ };
+ intersection = function(a, b) {
+ var i, len, ref, results, value;
+ if (a.length > b.length) {
+ ref = [b, a], a = ref[0], b = ref[1];
+ }
+ results = [];
+ for (i = 0, len = a.length; i < len; i++) {
+ value = a[i];
+ if (indexOf.call(b, value) >= 0) {
+ results.push(value);
+ }
+ }
+ return results;
+ };
+ if (!clientOrServerError() && validContent()) {
+ doc = createDocument(xhr.responseText);
+ if (doc && !assetsChanged(doc)) {
+ return doc;
+ }
+ }
+ };
+
+ extractTitleAndBody = function(doc) {
+ var title;
+ title = doc.querySelector('title');
+ return [title != null ? title.textContent : void 0, removeNoscriptTags(doc.querySelector('body')), CSRFToken.get(doc).token, 'runScripts'];
+ };
+
+ CSRFToken = {
+ get: function(doc) {
+ var tag;
+ if (doc == null) {
+ doc = document;
+ }
+ return {
+ node: tag = doc.querySelector('meta[name="csrf-token"]'),
+ token: tag != null ? typeof tag.getAttribute === "function" ? tag.getAttribute('content') : void 0 : void 0
+ };
+ },
+ update: function(latest) {
+ var current;
+ current = this.get();
+ if ((current.token != null) && (latest != null) && current.token !== latest) {
+ return current.node.setAttribute('content', latest);
+ }
+ }
+ };
+
+ createDocument = function(html) {
+ var doc;
+ doc = document.documentElement.cloneNode();
+ doc.innerHTML = html;
+ doc.head = doc.querySelector('head');
+ doc.body = doc.querySelector('body');
+ return doc;
+ };
+
+ ComponentUrl = (function() {
+ function ComponentUrl(original1) {
+ this.original = original1 != null ? original1 : document.location.href;
+ if (this.original.constructor === ComponentUrl) {
+ return this.original;
+ }
+ this._parse();
+ }
+
+ ComponentUrl.prototype.withoutHash = function() {
+ return this.href.replace(this.hash, '').replace('#', '');
+ };
+
+ ComponentUrl.prototype.withoutHashForIE10compatibility = function() {
+ return this.withoutHash();
+ };
+
+ ComponentUrl.prototype.hasNoHash = function() {
+ return this.hash.length === 0;
+ };
+
+ ComponentUrl.prototype.crossOrigin = function() {
+ return this.origin !== (new ComponentUrl).origin;
+ };
+
+ ComponentUrl.prototype._parse = function() {
+ var ref;
+ (this.link != null ? this.link : this.link = document.createElement('a')).href = this.original;
+ ref = this.link, this.href = ref.href, this.protocol = ref.protocol, this.host = ref.host, this.hostname = ref.hostname, this.port = ref.port, this.pathname = ref.pathname, this.search = ref.search, this.hash = ref.hash;
+ this.origin = [this.protocol, '//', this.hostname].join('');
+ if (this.port.length !== 0) {
+ this.origin += ":" + this.port;
+ }
+ this.relative = [this.pathname, this.search, this.hash].join('');
+ return this.absolute = this.href;
+ };
+
+ return ComponentUrl;
+
+ })();
+
+ Link = (function(superClass) {
+ extend(Link, superClass);
+
+ Link.HTML_EXTENSIONS = ['html'];
+
+ Link.allowExtensions = function() {
+ var extension, extensions, i, len;
+ extensions = 1 <= arguments.length ? slice.call(arguments, 0) : [];
+ for (i = 0, len = extensions.length; i < len; i++) {
+ extension = extensions[i];
+ Link.HTML_EXTENSIONS.push(extension);
+ }
+ return Link.HTML_EXTENSIONS;
+ };
+
+ function Link(link1) {
+ this.link = link1;
+ if (this.link.constructor === Link) {
+ return this.link;
+ }
+ this.original = this.link.href;
+ this.originalElement = this.link;
+ this.link = this.link.cloneNode(false);
+ Link.__super__.constructor.apply(this, arguments);
+ }
+
+ Link.prototype.shouldIgnore = function() {
+ return this.crossOrigin() || this._anchored() || this._nonHtml() || this._optOut() || this._target();
+ };
+
+ Link.prototype._anchored = function() {
+ return (this.hash.length > 0 || this.href.charAt(this.href.length - 1) === '#') && (this.withoutHash() === (new ComponentUrl).withoutHash());
+ };
+
+ Link.prototype._nonHtml = function() {
+ return this.pathname.match(/\.[a-z]+$/g) && !this.pathname.match(new RegExp("\\.(?:" + (Link.HTML_EXTENSIONS.join('|')) + ")?$", 'g'));
+ };
+
+ Link.prototype._optOut = function() {
+ var ignore, link;
+ link = this.originalElement;
+ while (!(ignore || link === document)) {
+ ignore = link.getAttribute('data-no-turbolink') != null;
+ link = link.parentNode;
+ }
+ return ignore;
+ };
+
+ Link.prototype._target = function() {
+ return this.link.target.length !== 0;
+ };
+
+ return Link;
+
+ })(ComponentUrl);
+
+ Click = (function() {
+ Click.installHandlerLast = function(event) {
+ if (!event.defaultPrevented) {
+ document.removeEventListener('click', Click.handle, false);
+ return document.addEventListener('click', Click.handle, false);
+ }
+ };
+
+ Click.handle = function(event) {
+ return new Click(event);
+ };
+
+ function Click(event1) {
+ this.event = event1;
+ if (this.event.defaultPrevented) {
+ return;
+ }
+ this._extractLink();
+ if (this._validForTurbolinks()) {
+ if (!pageChangePrevented(this.link.absolute)) {
+ visit(this.link.href);
+ }
+ this.event.preventDefault();
+ }
+ }
+
+ Click.prototype._extractLink = function() {
+ var link;
+ link = this.event.target;
+ while (!(!link.parentNode || link.nodeName === 'A')) {
+ link = link.parentNode;
+ }
+ if (link.nodeName === 'A' && link.href.length !== 0) {
+ return this.link = new Link(link);
+ }
+ };
+
+ Click.prototype._validForTurbolinks = function() {
+ return (this.link != null) && !(this.link.shouldIgnore() || this._nonStandardClick());
+ };
+
+ Click.prototype._nonStandardClick = function() {
+ return this.event.which > 1 || this.event.metaKey || this.event.ctrlKey || this.event.shiftKey || this.event.altKey;
+ };
+
+ return Click;
+
+ })();
+
+ ProgressBar = (function() {
+ var className;
+
+ className = 'turbolinks-progress-bar';
+
+ function ProgressBar(elementSelector) {
+ this.elementSelector = elementSelector;
+ this._trickle = bind(this._trickle, this);
+ this.value = 0;
+ this.content = '';
+ this.speed = 300;
+ this.opacity = 0.99;
+ this.install();
+ }
+
+ ProgressBar.prototype.install = function() {
+ this.element = document.querySelector(this.elementSelector);
+ this.element.classList.add(className);
+ this.styleElement = document.createElement('style');
+ document.head.appendChild(this.styleElement);
+ return this._updateStyle();
+ };
+
+ ProgressBar.prototype.uninstall = function() {
+ this.element.classList.remove(className);
+ return document.head.removeChild(this.styleElement);
+ };
+
+ ProgressBar.prototype.start = function() {
+ return this.advanceTo(5);
+ };
+
+ ProgressBar.prototype.advanceTo = function(value) {
+ var ref;
+ if ((value > (ref = this.value) && ref <= 100)) {
+ this.value = value;
+ this._updateStyle();
+ if (this.value === 100) {
+ return this._stopTrickle();
+ } else if (this.value > 0) {
+ return this._startTrickle();
+ }
+ }
+ };
+
+ ProgressBar.prototype.done = function() {
+ if (this.value > 0) {
+ this.advanceTo(100);
+ return this._reset();
+ }
+ };
+
+ ProgressBar.prototype._reset = function() {
+ var originalOpacity;
+ originalOpacity = this.opacity;
+ setTimeout((function(_this) {
+ return function() {
+ _this.opacity = 0;
+ return _this._updateStyle();
+ };
+ })(this), this.speed / 2);
+ return setTimeout((function(_this) {
+ return function() {
+ _this.value = 0;
+ _this.opacity = originalOpacity;
+ return _this._withSpeed(0, function() {
+ return _this._updateStyle(true);
+ });
+ };
+ })(this), this.speed);
+ };
+
+ ProgressBar.prototype._startTrickle = function() {
+ if (this.trickling) {
+ return;
+ }
+ this.trickling = true;
+ return setTimeout(this._trickle, this.speed);
+ };
+
+ ProgressBar.prototype._stopTrickle = function() {
+ return delete this.trickling;
+ };
+
+ ProgressBar.prototype._trickle = function() {
+ if (!this.trickling) {
+ return;
+ }
+ this.advanceTo(this.value + Math.random() / 2);
+ return setTimeout(this._trickle, this.speed);
+ };
+
+ ProgressBar.prototype._withSpeed = function(speed, fn) {
+ var originalSpeed, result;
+ originalSpeed = this.speed;
+ this.speed = speed;
+ result = fn();
+ this.speed = originalSpeed;
+ return result;
+ };
+
+ ProgressBar.prototype._updateStyle = function(forceRepaint) {
+ if (forceRepaint == null) {
+ forceRepaint = false;
+ }
+ if (forceRepaint) {
+ this._changeContentToForceRepaint();
+ }
+ return this.styleElement.textContent = this._createCSSRule();
+ };
+
+ ProgressBar.prototype._changeContentToForceRepaint = function() {
+ return this.content = this.content === '' ? ' ' : '';
+ };
+
+ ProgressBar.prototype._createCSSRule = function() {
+ return this.elementSelector + "." + className + "::before {\n content: '" + this.content + "';\n position: fixed;\n top: 0;\n left: 0;\n z-index: 2000;\n background-color: #0076ff;\n height: 3px;\n opacity: " + this.opacity + ";\n width: " + this.value + "%;\n transition: width " + this.speed + "ms ease-out, opacity " + (this.speed / 2) + "ms ease-in;\n transform: translate3d(0,0,0);\n}";
+ };
+
+ return ProgressBar;
+
+ })();
+
+ bypassOnLoadPopstate = function(fn) {
+ return setTimeout(fn, 500);
+ };
+
+ installDocumentReadyPageEventTriggers = function() {
+ return document.addEventListener('DOMContentLoaded', (function() {
+ triggerEvent(EVENTS.CHANGE);
+ return triggerEvent(EVENTS.UPDATE);
+ }), true);
+ };
+
+ installJqueryAjaxSuccessPageUpdateTrigger = function() {
+ if (typeof jQuery !== 'undefined') {
+ return jQuery(document).on('ajaxSuccess', function(event, xhr, settings) {
+ if (!jQuery.trim(xhr.responseText)) {
+ return;
+ }
+ return triggerEvent(EVENTS.UPDATE);
+ });
+ }
+ };
+
+ installHistoryChangeHandler = function(event) {
+ var cachedPage, ref;
+ if ((ref = event.state) != null ? ref.turbolinks : void 0) {
+ if (cachedPage = pageCache[(new ComponentUrl(event.state.url)).absolute]) {
+ cacheCurrentPage();
+ return fetchHistory(cachedPage);
+ } else {
+ return visit(event.target.location.href);
+ }
+ }
+ };
+
+ initializeTurbolinks = function() {
+ rememberCurrentUrl();
+ rememberCurrentState();
+ document.addEventListener('click', Click.installHandlerLast, true);
+ window.addEventListener('hashchange', function(event) {
+ rememberCurrentUrl();
+ return rememberCurrentState();
+ }, false);
+ return bypassOnLoadPopstate(function() {
+ return window.addEventListener('popstate', installHistoryChangeHandler, false);
+ });
+ };
+
+ historyStateIsDefined = window.history.state !== void 0 || navigator.userAgent.match(/Firefox\/2[6|7]/);
+
+ browserSupportsPushState = window.history && window.history.pushState && window.history.replaceState && historyStateIsDefined;
+
+ browserIsntBuggy = !navigator.userAgent.match(/CriOS\//);
+
+ requestMethodIsSafe = (ref = popCookie('request_method')) === 'GET' || ref === '';
+
+ browserSupportsTurbolinks = browserSupportsPushState && browserIsntBuggy && requestMethodIsSafe;
+
+ browserSupportsCustomEvents = document.addEventListener && document.createEvent;
+
+ if (browserSupportsCustomEvents) {
+ installDocumentReadyPageEventTriggers();
+ installJqueryAjaxSuccessPageUpdateTrigger();
+ }
+
+ if (browserSupportsTurbolinks) {
+ visit = fetch;
+ initializeTurbolinks();
+ } else {
+ visit = function(url) {
+ return document.location.href = url;
+ };
+ }
+
+ this.Turbolinks = {
+ visit: visit,
+ pagesCached: pagesCached,
+ enableTransitionCache: enableTransitionCache,
+ enableProgressBar: enableProgressBar,
+ allowLinkExtensions: Link.allowExtensions,
+ supported: browserSupportsTurbolinks,
+ EVENTS: clone(EVENTS)
+ };
+
+}).call(this);