codemirror-rails 2.24 → 2.32
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Rakefile +19 -0
- data/codemirror-rails.gemspec +6 -1
- data/lib/codemirror/rails/version.rb +2 -2
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +56 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/codemirror_rails_integration_test.rb +13 -0
- data/test/test_helper.rb +13 -0
- data/vendor/assets/javascripts/codemirror.js +381 -197
- data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +1 -1
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +649 -94
- data/vendor/assets/javascripts/codemirror/modes/clike.js +53 -7
- data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +12 -7
- data/vendor/assets/javascripts/codemirror/modes/diff.js +24 -5
- data/vendor/assets/javascripts/codemirror/modes/ecl.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/erlang.js +463 -0
- data/vendor/assets/javascripts/codemirror/modes/gfm.js +38 -2
- data/vendor/assets/javascripts/codemirror/modes/go.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/groovy.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/haxe.js +432 -0
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/less.js +93 -93
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +29 -6
- data/vendor/assets/javascripts/codemirror/modes/mysql.js +6 -8
- data/vendor/assets/javascripts/codemirror/modes/ocaml.js +114 -0
- data/vendor/assets/javascripts/codemirror/modes/pascal.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/pig.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/plsql.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/python.js +13 -16
- data/vendor/assets/javascripts/codemirror/modes/ruby.js +3 -8
- data/vendor/assets/javascripts/codemirror/modes/scheme.js +74 -46
- data/vendor/assets/javascripts/codemirror/modes/shell.js +22 -7
- data/vendor/assets/javascripts/codemirror/modes/stex.js +7 -5
- data/vendor/assets/javascripts/codemirror/modes/tiddlywiki.js +14 -14
- data/vendor/assets/javascripts/codemirror/modes/vb.js +260 -0
- data/vendor/assets/javascripts/codemirror/modes/verilog.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/xml.js +2 -1
- data/vendor/assets/javascripts/codemirror/modes/xquery.js +3 -3
- data/vendor/assets/javascripts/codemirror/utils/closetag.js +24 -34
- data/vendor/assets/javascripts/codemirror/utils/dialog.js +5 -1
- data/vendor/assets/javascripts/codemirror/utils/foldcode.js +10 -5
- data/vendor/assets/javascripts/codemirror/utils/formatting.js +8 -3
- data/vendor/assets/javascripts/codemirror/utils/loadmode.js +2 -1
- data/vendor/assets/javascripts/codemirror/utils/match-highlighter.js +1 -1
- data/vendor/assets/javascripts/codemirror/utils/multiplex.js +81 -0
- data/vendor/assets/javascripts/codemirror/utils/overlay.js +2 -1
- data/vendor/assets/javascripts/codemirror/utils/pig-hint.js +123 -0
- data/vendor/assets/javascripts/codemirror/utils/search.js +16 -12
- data/vendor/assets/javascripts/codemirror/utils/searchcursor.js +1 -1
- data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +4 -0
- data/vendor/assets/javascripts/codemirror/utils/xml-hint.js +137 -0
- data/vendor/assets/stylesheets/codemirror.css +59 -4
- data/vendor/assets/stylesheets/codemirror/modes/tiddlywiki.css +14 -21
- data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +1 -2
- data/vendor/assets/stylesheets/codemirror/themes/erlang-dark.css +21 -0
- data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +2 -3
- data/vendor/assets/stylesheets/codemirror/themes/night.css +1 -1
- data/vendor/assets/stylesheets/codemirror/themes/vibrant-ink.css +27 -0
- data/vendor/assets/stylesheets/codemirror/utils/dialog.css +4 -0
- metadata +98 -5
- data/vendor/assets/javascripts/codemirror/modes/rpm-spec.css +0 -5
@@ -0,0 +1,37 @@
|
|
1
|
+
Dummy::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# In the development environment your application's code is reloaded on
|
5
|
+
# every request. This slows down response time but is perfect for development
|
6
|
+
# since you don't have to restart the web server when you make code changes.
|
7
|
+
config.cache_classes = false
|
8
|
+
|
9
|
+
# Log error messages when you accidentally call methods on nil.
|
10
|
+
config.whiny_nils = true
|
11
|
+
|
12
|
+
# Show full error reports and disable caching
|
13
|
+
config.consider_all_requests_local = true
|
14
|
+
config.action_controller.perform_caching = false
|
15
|
+
|
16
|
+
# Don't care if the mailer can't send
|
17
|
+
config.action_mailer.raise_delivery_errors = false
|
18
|
+
|
19
|
+
# Print deprecation notices to the Rails logger
|
20
|
+
config.active_support.deprecation = :log
|
21
|
+
|
22
|
+
# Only use best-standards-support built into browsers
|
23
|
+
config.action_dispatch.best_standards_support = :builtin
|
24
|
+
|
25
|
+
# Raise exception on mass assignment protection for Active Record models
|
26
|
+
config.active_record.mass_assignment_sanitizer = :strict
|
27
|
+
|
28
|
+
# Log the query plan for queries taking more than this (works
|
29
|
+
# with SQLite, MySQL, and PostgreSQL)
|
30
|
+
config.active_record.auto_explain_threshold_in_seconds = 0.5
|
31
|
+
|
32
|
+
# Do not compress assets
|
33
|
+
config.assets.compress = false
|
34
|
+
|
35
|
+
# Expands the lines which load the assets
|
36
|
+
config.assets.debug = true
|
37
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
Dummy::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# Code is not reloaded between requests
|
5
|
+
config.cache_classes = true
|
6
|
+
|
7
|
+
# Full error reports are disabled and caching is turned on
|
8
|
+
config.consider_all_requests_local = false
|
9
|
+
config.action_controller.perform_caching = true
|
10
|
+
|
11
|
+
# Disable Rails's static asset server (Apache or nginx will already do this)
|
12
|
+
config.serve_static_assets = false
|
13
|
+
|
14
|
+
# Compress JavaScripts and CSS
|
15
|
+
config.assets.compress = true
|
16
|
+
|
17
|
+
# Don't fallback to assets pipeline if a precompiled asset is missed
|
18
|
+
config.assets.compile = false
|
19
|
+
|
20
|
+
# Generate digests for assets URLs
|
21
|
+
config.assets.digest = true
|
22
|
+
|
23
|
+
# Defaults to Rails.root.join("public/assets")
|
24
|
+
# config.assets.manifest = YOUR_PATH
|
25
|
+
|
26
|
+
# Specifies the header that your server uses for sending files
|
27
|
+
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
|
28
|
+
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
|
29
|
+
|
30
|
+
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
31
|
+
# config.force_ssl = true
|
32
|
+
|
33
|
+
# See everything in the log (default is :info)
|
34
|
+
# config.log_level = :debug
|
35
|
+
|
36
|
+
# Prepend all log lines with the following tags
|
37
|
+
# config.log_tags = [ :subdomain, :uuid ]
|
38
|
+
|
39
|
+
# Use a different logger for distributed setups
|
40
|
+
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
|
41
|
+
|
42
|
+
# Use a different cache store in production
|
43
|
+
# config.cache_store = :mem_cache_store
|
44
|
+
|
45
|
+
# Enable serving of images, stylesheets, and JavaScripts from an asset server
|
46
|
+
# config.action_controller.asset_host = "http://assets.example.com"
|
47
|
+
|
48
|
+
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
|
49
|
+
# config.assets.precompile += %w( search.js )
|
50
|
+
|
51
|
+
# Disable delivery errors, bad email addresses will be ignored
|
52
|
+
# config.action_mailer.raise_delivery_errors = false
|
53
|
+
|
54
|
+
# Enable threaded mode
|
55
|
+
# config.threadsafe!
|
56
|
+
|
57
|
+
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
58
|
+
# the I18n.default_locale when a translation can not be found)
|
59
|
+
config.i18n.fallbacks = true
|
60
|
+
|
61
|
+
# Send deprecation notices to registered listeners
|
62
|
+
config.active_support.deprecation = :notify
|
63
|
+
|
64
|
+
# Log the query plan for queries taking more than this (works
|
65
|
+
# with SQLite, MySQL, and PostgreSQL)
|
66
|
+
# config.active_record.auto_explain_threshold_in_seconds = 0.5
|
67
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
Dummy::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# The test environment is used exclusively to run your application's
|
5
|
+
# test suite. You never need to work with it otherwise. Remember that
|
6
|
+
# your test database is "scratch space" for the test suite and is wiped
|
7
|
+
# and recreated between test runs. Don't rely on the data there!
|
8
|
+
config.cache_classes = true
|
9
|
+
|
10
|
+
# Configure static asset server for tests with Cache-Control for performance
|
11
|
+
config.serve_static_assets = true
|
12
|
+
config.static_cache_control = "public, max-age=3600"
|
13
|
+
|
14
|
+
# Log error messages when you accidentally call methods on nil
|
15
|
+
config.whiny_nils = true
|
16
|
+
|
17
|
+
# Show full error reports and disable caching
|
18
|
+
config.consider_all_requests_local = true
|
19
|
+
config.action_controller.perform_caching = false
|
20
|
+
|
21
|
+
# Raise exceptions instead of rendering exception templates
|
22
|
+
config.action_dispatch.show_exceptions = false
|
23
|
+
|
24
|
+
# Disable request forgery protection in test environment
|
25
|
+
config.action_controller.allow_forgery_protection = false
|
26
|
+
|
27
|
+
# Tell Action Mailer not to deliver emails to the real world.
|
28
|
+
# The :test delivery method accumulates sent emails in the
|
29
|
+
# ActionMailer::Base.deliveries array.
|
30
|
+
config.action_mailer.delivery_method = :test
|
31
|
+
|
32
|
+
# Raise exception on mass assignment protection for Active Record models
|
33
|
+
config.active_record.mass_assignment_sanitizer = :strict
|
34
|
+
|
35
|
+
# Print deprecation notices to the stderr
|
36
|
+
config.active_support.deprecation = :stderr
|
37
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
|
4
|
+
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
|
5
|
+
|
6
|
+
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
|
7
|
+
# Rails.backtrace_cleaner.remove_silencers!
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Add new inflection rules using the following format
|
4
|
+
# (all these examples are active by default):
|
5
|
+
# ActiveSupport::Inflector.inflections do |inflect|
|
6
|
+
# inflect.plural /^(ox)$/i, '\1en'
|
7
|
+
# inflect.singular /^(ox)en/i, '\1'
|
8
|
+
# inflect.irregular 'person', 'people'
|
9
|
+
# inflect.uncountable %w( fish sheep )
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# These inflection rules are supported but not enabled by default:
|
13
|
+
# ActiveSupport::Inflector.inflections do |inflect|
|
14
|
+
# inflect.acronym 'RESTful'
|
15
|
+
# end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Your secret key for verifying the integrity of signed cookies.
|
4
|
+
# If you change this key, all old signed cookies will become invalid!
|
5
|
+
# Make sure the secret is at least 30 characters and all random,
|
6
|
+
# no regular words or you'll be exposed to dictionary attacks.
|
7
|
+
Dummy::Application.config.secret_token = '17f0c3cb560a96dbd11a2322311215f4457303a24e9e09a49a3d538129decaa98eadf5a27f4e100940452796238c3e54bd131229ca341ea5379f894f09540fa8'
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
|
4
|
+
|
5
|
+
# Use the database for sessions instead of the cookie-based default,
|
6
|
+
# which shouldn't be used to store highly confidential information
|
7
|
+
# (create the session table with "rails generate session_migration")
|
8
|
+
# Dummy::Application.config.session_store :active_record_store
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
#
|
3
|
+
# This file contains settings for ActionController::ParamsWrapper which
|
4
|
+
# is enabled by default.
|
5
|
+
|
6
|
+
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
|
7
|
+
ActiveSupport.on_load(:action_controller) do
|
8
|
+
wrap_parameters format: [:json]
|
9
|
+
end
|
10
|
+
|
11
|
+
# Disable root element in JSON by default.
|
12
|
+
ActiveSupport.on_load(:active_record) do
|
13
|
+
self.include_root_in_json = false
|
14
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
Dummy::Application.routes.draw do
|
2
|
+
# The priority is based upon order of creation:
|
3
|
+
# first created -> highest priority.
|
4
|
+
|
5
|
+
# Sample of regular route:
|
6
|
+
# match 'products/:id' => 'catalog#view'
|
7
|
+
# Keep in mind you can assign values other than :controller and :action
|
8
|
+
|
9
|
+
# Sample of named route:
|
10
|
+
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
|
11
|
+
# This route can be invoked with purchase_url(:id => product.id)
|
12
|
+
|
13
|
+
# Sample resource route (maps HTTP verbs to controller actions automatically):
|
14
|
+
# resources :products
|
15
|
+
|
16
|
+
# Sample resource route with options:
|
17
|
+
# resources :products do
|
18
|
+
# member do
|
19
|
+
# get 'short'
|
20
|
+
# post 'toggle'
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# collection do
|
24
|
+
# get 'sold'
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
|
28
|
+
# Sample resource route with sub-resources:
|
29
|
+
# resources :products do
|
30
|
+
# resources :comments, :sales
|
31
|
+
# resource :seller
|
32
|
+
# end
|
33
|
+
|
34
|
+
# Sample resource route with more complex sub-resources
|
35
|
+
# resources :products do
|
36
|
+
# resources :comments
|
37
|
+
# resources :sales do
|
38
|
+
# get 'recent', :on => :collection
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
|
42
|
+
# Sample resource route within a namespace:
|
43
|
+
# namespace :admin do
|
44
|
+
# # Directs /admin/products/* to Admin::ProductsController
|
45
|
+
# # (app/controllers/admin/products_controller.rb)
|
46
|
+
# resources :products
|
47
|
+
# end
|
48
|
+
|
49
|
+
# You can have the root of your site routed with "root"
|
50
|
+
# just remember to delete public/index.html.
|
51
|
+
# root :to => 'welcome#index'
|
52
|
+
|
53
|
+
# See how all your routes lay out with "rake routes"
|
54
|
+
|
55
|
+
# This is a legacy wild controller route that's not recommended for RESTful applications.
|
56
|
+
# Note: This route will make all actions in every controller accessible via GET requests.
|
57
|
+
# match ':controller(/:action(/:id))(.:format)'
|
58
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/404.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
23
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/422.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The change you wanted was rejected.</h1>
|
23
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/500.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>We're sorry, but something went wrong.</h1>
|
23
|
+
</div>
|
24
|
+
</body>
|
25
|
+
</html>
|
File without changes
|
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe 'codemiror-rails integration' do
|
4
|
+
it 'provides codemirror.js on the asset pipeline' do
|
5
|
+
visit '/assets/codemirror.js'
|
6
|
+
page.text.must_include 'var CodeMirror'
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'provides codemirror css on the asset pipeline' do
|
10
|
+
visit '/assets/codemirror.css'
|
11
|
+
page.text.must_include '.CodeMirror'
|
12
|
+
end
|
13
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
2
|
+
|
3
|
+
require File.expand_path('../dummy/config/environment.rb', __FILE__)
|
4
|
+
require 'rails/test_help'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'capybara/rails'
|
7
|
+
|
8
|
+
Rails.backtrace_cleaner.remove_silencers!
|
9
|
+
|
10
|
+
class IntegrationTest < MiniTest::Spec
|
11
|
+
include Capybara::DSL
|
12
|
+
register_spec_type(/integration$/, self)
|
13
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
// CodeMirror version 2.
|
1
|
+
// CodeMirror version 2.32
|
2
2
|
//
|
3
3
|
// All functions that need access to the editor's state live inside
|
4
4
|
// the CodeMirror function. Below that, at the bottom of the file,
|
@@ -23,14 +23,19 @@ var CodeMirror = (function() {
|
|
23
23
|
'<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
|
24
24
|
'<textarea style="position: absolute; padding: 0; width: 1px; height: 1em" wrap="off" ' +
|
25
25
|
'autocorrect="off" autocapitalize="off"></textarea></div>' +
|
26
|
+
'<div class="CodeMirror-scrollbar">' + // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.
|
27
|
+
'<div class="CodeMirror-scrollbar-inner">' + // The empty scrollbar content, used solely for managing the scrollbar thumb.
|
28
|
+
'</div></div>' + // This must be before the scroll area because it's float-right.
|
26
29
|
'<div class="CodeMirror-scroll" tabindex="-1">' +
|
27
30
|
'<div style="position: relative">' + // Set to the height of the text, causes scrolling
|
28
31
|
'<div style="position: relative">' + // Moved around its parent to cover visible view
|
29
32
|
'<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
|
30
33
|
// Provides positioning relative to (visible) text origin
|
31
34
|
'<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' +
|
32
|
-
|
35
|
+
// Used to measure text size
|
36
|
+
'<div style="position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden;"></div>' +
|
33
37
|
'<pre class="CodeMirror-cursor"> </pre>' + // Absolutely positioned blinky cursor
|
38
|
+
'<pre class="CodeMirror-cursor" style="visibility: hidden"> </pre>' + // Used to force a width
|
34
39
|
'<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code
|
35
40
|
'</div></div></div></div></div>';
|
36
41
|
if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
|
@@ -39,12 +44,13 @@ var CodeMirror = (function() {
|
|
39
44
|
scroller = wrapper.lastChild, code = scroller.firstChild,
|
40
45
|
mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
|
41
46
|
lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
|
42
|
-
cursor = measure.nextSibling,
|
43
|
-
lineDiv = selectionDiv.nextSibling
|
44
|
-
|
47
|
+
cursor = measure.nextSibling, widthForcer = cursor.nextSibling,
|
48
|
+
selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling,
|
49
|
+
scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild;
|
50
|
+
themeChanged(); keyMapChanged();
|
45
51
|
// Needed to hide big blue blinking cursor on Mobile Safari
|
46
52
|
if (ios) input.style.width = "0px";
|
47
|
-
if (!webkit)
|
53
|
+
if (!webkit) scroller.draggable = true;
|
48
54
|
lineSpace.style.outline = "none";
|
49
55
|
if (options.tabindex != null) input.tabIndex = options.tabindex;
|
50
56
|
if (options.autofocus) focusInput();
|
@@ -52,6 +58,17 @@ var CodeMirror = (function() {
|
|
52
58
|
// Needed to handle Tab key in KHTML
|
53
59
|
if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
|
54
60
|
|
61
|
+
// Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and
|
62
|
+
// make it overlap the content. (But we only do this if the scrollbar doesn't already
|
63
|
+
// have a natural width. If the mouse is plugged in or the user sets the system pref
|
64
|
+
// to always show scrollbars, the scrollbar shouldn't overlap.)
|
65
|
+
if (mac_geLion) {
|
66
|
+
scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap");
|
67
|
+
} else if (ie_lt8) {
|
68
|
+
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
|
69
|
+
scrollbar.className += " cm-sb-ie7";
|
70
|
+
}
|
71
|
+
|
55
72
|
// Check for problem with IE innerHTML not working when we have a
|
56
73
|
// P (or similar) parent node.
|
57
74
|
try { stringWidth("x"); }
|
@@ -75,7 +92,7 @@ var CodeMirror = (function() {
|
|
75
92
|
var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
|
76
93
|
// Selection-related flags. shiftSelecting obviously tracks
|
77
94
|
// whether the user is holding shift.
|
78
|
-
var shiftSelecting, lastClick, lastDoubleClick,
|
95
|
+
var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText,
|
79
96
|
overwrite = false, suppressEdits = false;
|
80
97
|
// Variables used by startOperation/endOperation to track what
|
81
98
|
// happened during the operation.
|
@@ -88,7 +105,7 @@ var CodeMirror = (function() {
|
|
88
105
|
var bracketHighlighted;
|
89
106
|
// Tracks the maximum line length so that the horizontal scrollbar
|
90
107
|
// can be kept static when scrolling.
|
91
|
-
var maxLine = "",
|
108
|
+
var maxLine = "", updateMaxLine = false, maxLineChanged = true;
|
92
109
|
var tabCache = {};
|
93
110
|
|
94
111
|
// Initialize the content.
|
@@ -103,12 +120,11 @@ var CodeMirror = (function() {
|
|
103
120
|
// which point we can't mess with it anymore. Context menu is
|
104
121
|
// handled in onMouseDown for Gecko.
|
105
122
|
if (!gecko) connect(scroller, "contextmenu", onContextMenu);
|
106
|
-
connect(scroller, "scroll",
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
});
|
123
|
+
connect(scroller, "scroll", onScroll);
|
124
|
+
connect(scrollbar, "scroll", onScroll);
|
125
|
+
connect(scrollbar, "mousedown", function() {if (focused) setTimeout(focusInput, 0);});
|
126
|
+
connect(scroller, "mousewheel", onMouseWheel);
|
127
|
+
connect(scroller, "DOMMouseScroll", onMouseWheel);
|
112
128
|
connect(window, "resize", function() {updateDisplay(true);});
|
113
129
|
connect(input, "keyup", operation(onKeyUp));
|
114
130
|
connect(input, "input", fastPoll);
|
@@ -118,7 +134,7 @@ var CodeMirror = (function() {
|
|
118
134
|
connect(input, "blur", onBlur);
|
119
135
|
|
120
136
|
if (options.dragDrop) {
|
121
|
-
connect(
|
137
|
+
connect(scroller, "dragstart", onDragStart);
|
122
138
|
function drag_(e) {
|
123
139
|
if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
|
124
140
|
e_stop(e);
|
@@ -166,6 +182,7 @@ var CodeMirror = (function() {
|
|
166
182
|
else if (option == "theme") themeChanged();
|
167
183
|
else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
|
168
184
|
else if (option == "tabSize") updateDisplay(true);
|
185
|
+
else if (option == "keyMap") keyMapChanged();
|
169
186
|
if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
|
170
187
|
gutterChanged();
|
171
188
|
updateDisplay(true);
|
@@ -184,6 +201,15 @@ var CodeMirror = (function() {
|
|
184
201
|
indentSelection: operation(indentSelected),
|
185
202
|
historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
|
186
203
|
clearHistory: function() {history = new History();},
|
204
|
+
setHistory: function(histData) {
|
205
|
+
history = new History();
|
206
|
+
history.done = histData.done;
|
207
|
+
history.undone = histData.undone;
|
208
|
+
},
|
209
|
+
getHistory: function() {
|
210
|
+
history.time = 0;
|
211
|
+
return {done: history.done.concat([]), undone: history.undone.concat([])};
|
212
|
+
},
|
187
213
|
matchBrackets: operation(function(){matchBrackets(true);}),
|
188
214
|
getTokenAt: operation(function(pos) {
|
189
215
|
pos = clipPos(pos);
|
@@ -275,7 +301,7 @@ var CodeMirror = (function() {
|
|
275
301
|
if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
|
276
302
|
}),
|
277
303
|
replaceRange: operation(replaceRange),
|
278
|
-
getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
|
304
|
+
getRange: function(from, to, lineSep) {return getRange(clipPos(from), clipPos(to), lineSep);},
|
279
305
|
|
280
306
|
triggerOnKeyDown: operation(onKeyDown),
|
281
307
|
execCommand: function(cmd) {return commands[cmd](instance);},
|
@@ -313,16 +339,28 @@ var CodeMirror = (function() {
|
|
313
339
|
},
|
314
340
|
scrollTo: function(x, y) {
|
315
341
|
if (x != null) scroller.scrollLeft = x;
|
316
|
-
if (y != null)
|
342
|
+
if (y != null) scrollbar.scrollTop = y;
|
317
343
|
updateDisplay([]);
|
318
344
|
},
|
345
|
+
getScrollInfo: function() {
|
346
|
+
return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
|
347
|
+
height: scrollbar.scrollHeight, width: scroller.scrollWidth};
|
348
|
+
},
|
349
|
+
setSize: function(width, height) {
|
350
|
+
function interpret(val) {
|
351
|
+
val = String(val);
|
352
|
+
return /^\d+$/.test(val) ? val + "px" : val;
|
353
|
+
}
|
354
|
+
if (width != null) wrapper.style.width = interpret(width);
|
355
|
+
if (height != null) scroller.style.height = interpret(height);
|
356
|
+
},
|
319
357
|
|
320
358
|
operation: function(f){return operation(f)();},
|
321
359
|
compoundChange: function(f){return compoundChange(f);},
|
322
360
|
refresh: function(){
|
323
|
-
updateDisplay(true);
|
324
|
-
if (
|
325
|
-
|
361
|
+
updateDisplay(true, null, lastScrollTop);
|
362
|
+
if (scrollbar.scrollHeight > lastScrollTop)
|
363
|
+
scrollbar.scrollTop = lastScrollTop;
|
326
364
|
},
|
327
365
|
getInputField: function(){return input;},
|
328
366
|
getWrapperElement: function(){return wrapper;},
|
@@ -343,10 +381,24 @@ var CodeMirror = (function() {
|
|
343
381
|
splitLines(code), top, top);
|
344
382
|
updateInput = true;
|
345
383
|
}
|
346
|
-
function getValue() {
|
384
|
+
function getValue(lineSep) {
|
347
385
|
var text = [];
|
348
386
|
doc.iter(0, doc.size, function(line) { text.push(line.text); });
|
349
|
-
return text.join("\n");
|
387
|
+
return text.join(lineSep || "\n");
|
388
|
+
}
|
389
|
+
|
390
|
+
function onScroll(e) {
|
391
|
+
if (scroller.scrollTop) {
|
392
|
+
scrollbar.scrollTop += scroller.scrollTop;
|
393
|
+
scroller.scrollTop = 0;
|
394
|
+
}
|
395
|
+
if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) {
|
396
|
+
lastScrollTop = scrollbar.scrollTop;
|
397
|
+
lastScrollLeft = scroller.scrollLeft;
|
398
|
+
updateDisplay([]);
|
399
|
+
if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
|
400
|
+
if (options.onScroll) options.onScroll(instance);
|
401
|
+
}
|
350
402
|
}
|
351
403
|
|
352
404
|
function onMouseDown(e) {
|
@@ -367,10 +419,12 @@ var CodeMirror = (function() {
|
|
367
419
|
|
368
420
|
switch (e_button(e)) {
|
369
421
|
case 3:
|
370
|
-
if (gecko
|
422
|
+
if (gecko) onContextMenu(e);
|
371
423
|
return;
|
372
424
|
case 2:
|
373
425
|
if (start) setCursor(start.line, start.ch, true);
|
426
|
+
setTimeout(focusInput, 20);
|
427
|
+
e_preventDefault(e);
|
374
428
|
return;
|
375
429
|
}
|
376
430
|
// For button 1, if it was clicked inside the editor
|
@@ -380,24 +434,27 @@ var CodeMirror = (function() {
|
|
380
434
|
|
381
435
|
if (!focused) onFocus();
|
382
436
|
|
383
|
-
var now = +new Date;
|
437
|
+
var now = +new Date, type = "single";
|
384
438
|
if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
|
439
|
+
type = "triple";
|
385
440
|
e_preventDefault(e);
|
386
441
|
setTimeout(focusInput, 20);
|
387
|
-
|
442
|
+
selectLine(start.line);
|
388
443
|
} else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
|
444
|
+
type = "double";
|
389
445
|
lastDoubleClick = {time: now, pos: start};
|
390
446
|
e_preventDefault(e);
|
391
|
-
|
447
|
+
var word = findWordAt(start);
|
448
|
+
setSelectionUser(word.from, word.to);
|
392
449
|
} else { lastClick = {time: now, pos: start}; }
|
393
450
|
|
394
451
|
var last = start, going;
|
395
452
|
if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
|
396
|
-
!posLess(start, sel.from) && !posLess(sel.to, start)) {
|
453
|
+
!posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") {
|
397
454
|
// Let the drag handler handle this.
|
398
|
-
if (webkit)
|
455
|
+
if (webkit) scroller.draggable = true;
|
399
456
|
function dragEnd(e2) {
|
400
|
-
if (webkit)
|
457
|
+
if (webkit) scroller.draggable = false;
|
401
458
|
draggingText = false;
|
402
459
|
up(); drop();
|
403
460
|
if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
|
@@ -410,18 +467,33 @@ var CodeMirror = (function() {
|
|
410
467
|
var drop = connect(scroller, "drop", operation(dragEnd), true);
|
411
468
|
draggingText = true;
|
412
469
|
// IE's approach to draggable
|
413
|
-
if (
|
470
|
+
if (scroller.dragDrop) scroller.dragDrop();
|
414
471
|
return;
|
415
472
|
}
|
416
473
|
e_preventDefault(e);
|
417
|
-
setCursor(start.line, start.ch, true);
|
474
|
+
if (type == "single") setCursor(start.line, start.ch, true);
|
475
|
+
|
476
|
+
var startstart = sel.from, startend = sel.to;
|
477
|
+
|
478
|
+
function doSelect(cur) {
|
479
|
+
if (type == "single") {
|
480
|
+
setSelectionUser(start, cur);
|
481
|
+
} else if (type == "double") {
|
482
|
+
var word = findWordAt(cur);
|
483
|
+
if (posLess(cur, startstart)) setSelectionUser(word.from, startend);
|
484
|
+
else setSelectionUser(startstart, word.to);
|
485
|
+
} else if (type == "triple") {
|
486
|
+
if (posLess(cur, startstart)) setSelectionUser(startend, clipPos({line: cur.line, ch: 0}));
|
487
|
+
else setSelectionUser(startstart, clipPos({line: cur.line + 1, ch: 0}));
|
488
|
+
}
|
489
|
+
}
|
418
490
|
|
419
491
|
function extend(e) {
|
420
492
|
var cur = posFromMouse(e, true);
|
421
493
|
if (cur && !posEq(cur, last)) {
|
422
494
|
if (!focused) onFocus();
|
423
495
|
last = cur;
|
424
|
-
|
496
|
+
doSelect(cur);
|
425
497
|
updateInput = false;
|
426
498
|
var visible = visibleLines();
|
427
499
|
if (cur.line >= visible.to || cur.line < visible.from)
|
@@ -432,7 +504,7 @@ var CodeMirror = (function() {
|
|
432
504
|
function done(e) {
|
433
505
|
clearTimeout(going);
|
434
506
|
var cur = posFromMouse(e);
|
435
|
-
if (cur)
|
507
|
+
if (cur) doSelect(cur);
|
436
508
|
e_preventDefault(e);
|
437
509
|
focusInput();
|
438
510
|
updateInput = true;
|
@@ -449,11 +521,7 @@ var CodeMirror = (function() {
|
|
449
521
|
function onDoubleClick(e) {
|
450
522
|
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
451
523
|
if (n.parentNode == gutterText) return e_preventDefault(e);
|
452
|
-
var start = posFromMouse(e);
|
453
|
-
if (!start) return;
|
454
|
-
lastDoubleClick = {time: +new Date, pos: start};
|
455
524
|
e_preventDefault(e);
|
456
|
-
selectWordAt(start);
|
457
525
|
}
|
458
526
|
function onDrop(e) {
|
459
527
|
if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
|
@@ -477,8 +545,9 @@ var CodeMirror = (function() {
|
|
477
545
|
}
|
478
546
|
var n = files.length, text = Array(n), read = 0;
|
479
547
|
for (var i = 0; i < n; ++i) loadFile(files[i], i);
|
480
|
-
}
|
481
|
-
|
548
|
+
} else {
|
549
|
+
// Don't do a replace if the drop happened inside of the selected text.
|
550
|
+
if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
|
482
551
|
try {
|
483
552
|
var text = e.dataTransfer.getData("Text");
|
484
553
|
if (text) {
|
@@ -499,7 +568,7 @@ var CodeMirror = (function() {
|
|
499
568
|
e.dataTransfer.setData("Text", txt);
|
500
569
|
|
501
570
|
// Use dummy image instead of default browsers image.
|
502
|
-
if (gecko || chrome) {
|
571
|
+
if (gecko || chrome || opera) {
|
503
572
|
var img = document.createElement('img');
|
504
573
|
img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image
|
505
574
|
e.dataTransfer.setDragImage(img, 0, 0);
|
@@ -556,6 +625,7 @@ var CodeMirror = (function() {
|
|
556
625
|
if (stopped) handled = false;
|
557
626
|
if (handled) {
|
558
627
|
e_preventDefault(e);
|
628
|
+
restartBlink();
|
559
629
|
if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
|
560
630
|
}
|
561
631
|
return handled;
|
@@ -563,7 +633,10 @@ var CodeMirror = (function() {
|
|
563
633
|
function handleCharBinding(e, ch) {
|
564
634
|
var handled = lookupKey("'" + ch + "'", options.extraKeys,
|
565
635
|
options.keyMap, function(b) { return doHandleBinding(b, true); });
|
566
|
-
if (handled)
|
636
|
+
if (handled) {
|
637
|
+
e_preventDefault(e);
|
638
|
+
restartBlink();
|
639
|
+
}
|
567
640
|
return handled;
|
568
641
|
}
|
569
642
|
|
@@ -578,7 +651,7 @@ var CodeMirror = (function() {
|
|
578
651
|
setShift(code == 16 || e_prop(e, "shiftKey"));
|
579
652
|
// First give onKeyEvent option a chance to handle this.
|
580
653
|
var handled = handleKeyBinding(e);
|
581
|
-
if (
|
654
|
+
if (opera) {
|
582
655
|
lastStoppedKey = handled ? code : null;
|
583
656
|
// Opera has no cut event... we try to at least catch the key combo
|
584
657
|
if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
|
@@ -589,8 +662,8 @@ var CodeMirror = (function() {
|
|
589
662
|
if (pollingFast) readInput();
|
590
663
|
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
591
664
|
var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
|
592
|
-
if (
|
593
|
-
if (((
|
665
|
+
if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
|
666
|
+
if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return;
|
594
667
|
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
|
595
668
|
if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
|
596
669
|
if (mode.electricChars.indexOf(ch) > -1)
|
@@ -609,8 +682,8 @@ var CodeMirror = (function() {
|
|
609
682
|
if (!focused) {
|
610
683
|
if (options.onFocus) options.onFocus(instance);
|
611
684
|
focused = true;
|
612
|
-
if (
|
613
|
-
|
685
|
+
if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
|
686
|
+
scroller.className += " CodeMirror-focused";
|
614
687
|
if (!leaveInputAlone) resetInput(true);
|
615
688
|
}
|
616
689
|
slowPoll();
|
@@ -624,12 +697,48 @@ var CodeMirror = (function() {
|
|
624
697
|
operation(function(){
|
625
698
|
if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
|
626
699
|
})();
|
627
|
-
|
700
|
+
scroller.className = scroller.className.replace(" CodeMirror-focused", "");
|
628
701
|
}
|
629
702
|
clearInterval(blinker);
|
630
703
|
setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
|
631
704
|
}
|
632
705
|
|
706
|
+
function chopDelta(delta) {
|
707
|
+
// Make sure we always scroll a little bit for any nonzero delta.
|
708
|
+
if (delta > 0.0 && delta < 1.0) return 1;
|
709
|
+
else if (delta > -1.0 && delta < 0.0) return -1;
|
710
|
+
else return Math.round(delta);
|
711
|
+
}
|
712
|
+
|
713
|
+
function onMouseWheel(e) {
|
714
|
+
var deltaX = 0, deltaY = 0;
|
715
|
+
if (e.type == "DOMMouseScroll") { // Firefox
|
716
|
+
var delta = -e.detail * 8.0;
|
717
|
+
if (e.axis == e.HORIZONTAL_AXIS) deltaX = delta;
|
718
|
+
else if (e.axis == e.VERTICAL_AXIS) deltaY = delta;
|
719
|
+
} else if (e.wheelDeltaX !== undefined && e.wheelDeltaY !== undefined) { // WebKit
|
720
|
+
deltaX = e.wheelDeltaX / 3.0;
|
721
|
+
deltaY = e.wheelDeltaY / 3.0;
|
722
|
+
} else if (e.wheelDelta !== undefined) { // IE or Opera
|
723
|
+
deltaY = e.wheelDelta / 3.0;
|
724
|
+
}
|
725
|
+
|
726
|
+
var scrolled = false;
|
727
|
+
deltaX = chopDelta(deltaX);
|
728
|
+
deltaY = chopDelta(deltaY);
|
729
|
+
if ((deltaX > 0 && scroller.scrollLeft > 0) ||
|
730
|
+
(deltaX < 0 && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth)) {
|
731
|
+
scroller.scrollLeft -= deltaX;
|
732
|
+
scrolled = true;
|
733
|
+
}
|
734
|
+
if ((deltaY > 0 && scrollbar.scrollTop > 0) ||
|
735
|
+
(deltaY < 0 && scrollbar.scrollTop + scrollbar.clientHeight < scrollbar.scrollHeight)) {
|
736
|
+
scrollbar.scrollTop -= deltaY;
|
737
|
+
scrolled = true;
|
738
|
+
}
|
739
|
+
if (scrolled) e_stop(e);
|
740
|
+
}
|
741
|
+
|
633
742
|
// Replace the range from from to to by the strings in newText.
|
634
743
|
// Afterwards, set the selection to selFrom, selTo.
|
635
744
|
function updateLines(from, to, newText, selFrom, selTo) {
|
@@ -650,8 +759,8 @@ var CodeMirror = (function() {
|
|
650
759
|
var replaced = [], end = change.start + change.added;
|
651
760
|
doc.iter(change.start, end, function(line) { replaced.push(line.text); });
|
652
761
|
out.push({start: change.start, added: change.old.length, old: replaced});
|
653
|
-
var pos =
|
654
|
-
|
762
|
+
var pos = {line: change.start + change.old.length - 1,
|
763
|
+
ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])};
|
655
764
|
updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
|
656
765
|
}
|
657
766
|
updateInput = true;
|
@@ -665,7 +774,7 @@ var CodeMirror = (function() {
|
|
665
774
|
var recomputeMaxLength = false, maxLineLength = maxLine.length;
|
666
775
|
if (!options.lineWrapping)
|
667
776
|
doc.iter(from.line, to.line + 1, function(line) {
|
668
|
-
if (line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
|
777
|
+
if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
|
669
778
|
});
|
670
779
|
if (from.line != to.line || newText.length > 1) gutterDirty = true;
|
671
780
|
|
@@ -721,20 +830,12 @@ var CodeMirror = (function() {
|
|
721
830
|
} else {
|
722
831
|
doc.iter(from.line, from.line + newText.length, function(line) {
|
723
832
|
var l = line.text;
|
724
|
-
if (l.length > maxLineLength) {
|
725
|
-
maxLine = l; maxLineLength = l.length;
|
833
|
+
if (!line.hidden && l.length > maxLineLength) {
|
834
|
+
maxLine = l; maxLineLength = l.length; maxLineChanged = true;
|
726
835
|
recomputeMaxLength = false;
|
727
836
|
}
|
728
837
|
});
|
729
|
-
if (recomputeMaxLength)
|
730
|
-
maxLineLength = 0; maxLine = ""; maxWidth = null;
|
731
|
-
doc.iter(0, doc.size, function(line) {
|
732
|
-
var l = line.text;
|
733
|
-
if (l.length > maxLineLength) {
|
734
|
-
maxLineLength = l.length; maxLine = l;
|
735
|
-
}
|
736
|
-
});
|
737
|
-
}
|
838
|
+
if (recomputeMaxLength) updateMaxLine = true;
|
738
839
|
}
|
739
840
|
|
740
841
|
// Add these lines to the work array, so that they will be
|
@@ -760,11 +861,55 @@ var CodeMirror = (function() {
|
|
760
861
|
|
761
862
|
// Update the selection
|
762
863
|
function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
|
763
|
-
setSelection(selFrom, selTo
|
864
|
+
setSelection(clipPos(selFrom), clipPos(selTo),
|
865
|
+
updateLine(sel.from.line), updateLine(sel.to.line));
|
866
|
+
}
|
867
|
+
|
868
|
+
function needsScrollbar() {
|
869
|
+
var realHeight = doc.height * textHeight() + 2 * paddingTop();
|
870
|
+
return realHeight - 1 > scroller.offsetHeight ? realHeight : false;
|
871
|
+
}
|
872
|
+
|
873
|
+
function updateVerticalScroll(scrollTop) {
|
874
|
+
var scrollHeight = needsScrollbar();
|
875
|
+
scrollbar.style.display = scrollHeight ? "block" : "none";
|
876
|
+
if (scrollHeight) {
|
877
|
+
scrollbarInner.style.height = scrollHeight + "px";
|
878
|
+
scrollbar.style.height = scroller.offsetHeight + "px";
|
879
|
+
if (scrollTop != null) scrollbar.scrollTop = scrollTop;
|
880
|
+
}
|
881
|
+
// Position the mover div to align with the current virtual scroll position
|
882
|
+
mover.style.top = (displayOffset * textHeight() - scrollbar.scrollTop) + "px";
|
883
|
+
}
|
884
|
+
|
885
|
+
// On Mac OS X Lion and up, detect whether the mouse is plugged in by measuring
|
886
|
+
// the width of a div with a scrollbar in it. If the width is <= 1, then
|
887
|
+
// the mouse isn't plugged in and scrollbars should overlap the content.
|
888
|
+
function overlapScrollbars() {
|
889
|
+
var tmpSb = document.createElement('div'),
|
890
|
+
tmpSbInner = document.createElement('div');
|
891
|
+
tmpSb.className = "CodeMirror-scrollbar";
|
892
|
+
tmpSb.style.cssText = "position: absolute; left: -9999px; height: 100px;";
|
893
|
+
tmpSbInner.className = "CodeMirror-scrollbar-inner";
|
894
|
+
tmpSbInner.style.height = "200px";
|
895
|
+
tmpSb.appendChild(tmpSbInner);
|
896
|
+
|
897
|
+
document.body.appendChild(tmpSb);
|
898
|
+
var result = (tmpSb.offsetWidth <= 1);
|
899
|
+
document.body.removeChild(tmpSb);
|
900
|
+
return result;
|
901
|
+
}
|
764
902
|
|
765
|
-
|
766
|
-
|
767
|
-
|
903
|
+
function computeMaxLength() {
|
904
|
+
var maxLineLength = 0;
|
905
|
+
maxLine = ""; maxLineChanged = true;
|
906
|
+
doc.iter(0, doc.size, function(line) {
|
907
|
+
var l = line.text;
|
908
|
+
if (!line.hidden && l.length > maxLineLength) {
|
909
|
+
maxLineLength = l.length; maxLine = l;
|
910
|
+
}
|
911
|
+
});
|
912
|
+
updateMaxLine = false;
|
768
913
|
}
|
769
914
|
|
770
915
|
function replaceRange(code, from, to) {
|
@@ -800,16 +945,16 @@ var CodeMirror = (function() {
|
|
800
945
|
updateLines(from, to, code, newSel.from, newSel.to);
|
801
946
|
}
|
802
947
|
|
803
|
-
function getRange(from, to) {
|
948
|
+
function getRange(from, to, lineSep) {
|
804
949
|
var l1 = from.line, l2 = to.line;
|
805
950
|
if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
|
806
951
|
var code = [getLine(l1).text.slice(from.ch)];
|
807
952
|
doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
|
808
953
|
code.push(getLine(l2).text.slice(0, to.ch));
|
809
|
-
return code.join("\n");
|
954
|
+
return code.join(lineSep || "\n");
|
810
955
|
}
|
811
|
-
function getSelection() {
|
812
|
-
return getRange(sel.from, sel.to);
|
956
|
+
function getSelection(lineSep) {
|
957
|
+
return getRange(sel.from, sel.to, lineSep);
|
813
958
|
}
|
814
959
|
|
815
960
|
var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
|
@@ -853,7 +998,8 @@ var CodeMirror = (function() {
|
|
853
998
|
else if (overwrite && posEq(sel.from, sel.to))
|
854
999
|
sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
|
855
1000
|
replaceSelection(text.slice(same), "end");
|
856
|
-
prevInput =
|
1001
|
+
if (text.length > 1000) { input.value = prevInput = ""; }
|
1002
|
+
else prevInput = text;
|
857
1003
|
return true;
|
858
1004
|
}
|
859
1005
|
function resetInput(user) {
|
@@ -869,44 +1015,50 @@ var CodeMirror = (function() {
|
|
869
1015
|
}
|
870
1016
|
|
871
1017
|
function scrollEditorIntoView() {
|
872
|
-
if (!cursor.getBoundingClientRect) return;
|
873
1018
|
var rect = cursor.getBoundingClientRect();
|
874
1019
|
// IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
|
875
1020
|
if (ie && rect.top == rect.bottom) return;
|
876
1021
|
var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
|
877
|
-
if (rect.top < 0 || rect.bottom > winH)
|
1022
|
+
if (rect.top < 0 || rect.bottom > winH) scrollCursorIntoView();
|
878
1023
|
}
|
879
1024
|
function scrollCursorIntoView() {
|
1025
|
+
var coords = calculateCursorCoords();
|
1026
|
+
return scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
|
1027
|
+
}
|
1028
|
+
function calculateCursorCoords() {
|
880
1029
|
var cursor = localCoords(sel.inverted ? sel.from : sel.to);
|
881
1030
|
var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
|
882
|
-
return
|
1031
|
+
return {x: x, y: cursor.y, yBot: cursor.yBot};
|
883
1032
|
}
|
884
1033
|
function scrollIntoView(x1, y1, x2, y2) {
|
1034
|
+
var scrollPos = calculateScrollPos(x1, y1, x2, y2), scrolled = false;
|
1035
|
+
if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft; scrolled = true;}
|
1036
|
+
if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scrollPos.scrollTop; scrolled = true;}
|
1037
|
+
if (scrolled && options.onScroll) options.onScroll(instance);
|
1038
|
+
}
|
1039
|
+
function calculateScrollPos(x1, y1, x2, y2) {
|
885
1040
|
var pl = paddingLeft(), pt = paddingTop();
|
886
1041
|
y1 += pt; y2 += pt; x1 += pl; x2 += pl;
|
887
|
-
var screen = scroller.clientHeight, screentop =
|
888
|
-
|
889
|
-
|
1042
|
+
var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {};
|
1043
|
+
var docBottom = scroller.scrollHeight;
|
1044
|
+
var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;;
|
1045
|
+
if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
|
1046
|
+
else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen;
|
890
1047
|
|
891
1048
|
var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
|
892
1049
|
var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
|
893
1050
|
var atLeft = x1 < gutterw + pl + 10;
|
894
1051
|
if (x1 < screenleft + gutterw || atLeft) {
|
895
1052
|
if (atLeft) x1 = 0;
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
else if (x2 > screenw + screenleft - 3) {
|
900
|
-
scroller.scrollLeft = x2 + 10 - screenw;
|
901
|
-
scrolled = true;
|
902
|
-
if (x2 > code.clientWidth) result = false;
|
1053
|
+
result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
|
1054
|
+
} else if (x2 > screenw + screenleft - 3) {
|
1055
|
+
result.scrollLeft = x2 + 10 - screenw;
|
903
1056
|
}
|
904
|
-
if (scrolled && options.onScroll) options.onScroll(instance);
|
905
1057
|
return result;
|
906
1058
|
}
|
907
1059
|
|
908
|
-
function visibleLines() {
|
909
|
-
var lh = textHeight(), top =
|
1060
|
+
function visibleLines(scrollTop) {
|
1061
|
+
var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop();
|
910
1062
|
var fromHeight = Math.max(0, Math.floor(top / lh));
|
911
1063
|
var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
|
912
1064
|
return {from: lineAtHeight(doc, fromHeight),
|
@@ -915,15 +1067,20 @@ var CodeMirror = (function() {
|
|
915
1067
|
// Uses a set of changes plus the current scroll position to
|
916
1068
|
// determine which DOM updates have to be made, and makes the
|
917
1069
|
// updates.
|
918
|
-
function updateDisplay(changes, suppressCallback) {
|
1070
|
+
function updateDisplay(changes, suppressCallback, scrollTop) {
|
919
1071
|
if (!scroller.clientWidth) {
|
920
1072
|
showingFrom = showingTo = displayOffset = 0;
|
921
1073
|
return;
|
922
1074
|
}
|
923
1075
|
// Compute the new visible window
|
924
|
-
|
1076
|
+
// If scrollTop is specified, use that to determine which lines
|
1077
|
+
// to render instead of the current scrollbar position.
|
1078
|
+
var visible = visibleLines(scrollTop);
|
925
1079
|
// Bail out if the visible area is already rendered and nothing changed.
|
926
|
-
if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo)
|
1080
|
+
if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) {
|
1081
|
+
updateVerticalScroll(scrollTop);
|
1082
|
+
return;
|
1083
|
+
}
|
927
1084
|
var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
|
928
1085
|
if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
|
929
1086
|
if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
|
@@ -941,7 +1098,10 @@ var CodeMirror = (function() {
|
|
941
1098
|
if (range.from >= range.to) intact.splice(i--, 1);
|
942
1099
|
else intactLines += range.to - range.from;
|
943
1100
|
}
|
944
|
-
if (intactLines == to - from && from == showingFrom && to == showingTo)
|
1101
|
+
if (intactLines == to - from && from == showingFrom && to == showingTo) {
|
1102
|
+
updateVerticalScroll(scrollTop);
|
1103
|
+
return;
|
1104
|
+
}
|
945
1105
|
intact.sort(function(a, b) {return a.domStart - b.domStart;});
|
946
1106
|
|
947
1107
|
var th = textHeight(), gutterDisplay = gutter.style.display;
|
@@ -949,17 +1109,12 @@ var CodeMirror = (function() {
|
|
949
1109
|
patchDisplay(from, to, intact);
|
950
1110
|
lineDiv.style.display = gutter.style.display = "";
|
951
1111
|
|
952
|
-
// Position the mover div to align with the lines it's supposed
|
953
|
-
// to be showing (which will cover the visible display)
|
954
1112
|
var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
|
955
1113
|
// This is just a bogus formula that detects when the editor is
|
956
1114
|
// resized or the font size changes.
|
957
1115
|
if (different) lastSizeC = scroller.clientHeight + th;
|
958
1116
|
showingFrom = from; showingTo = to;
|
959
1117
|
displayOffset = heightAtLine(doc, from);
|
960
|
-
mover.style.top = (displayOffset * th) + "px";
|
961
|
-
if (scroller.clientHeight)
|
962
|
-
code.style.height = (doc.height * th + 2 * paddingTop()) + "px";
|
963
1118
|
|
964
1119
|
// Since this is all rather error prone, it is honoured with the
|
965
1120
|
// only assertion in the whole file.
|
@@ -968,7 +1123,6 @@ var CodeMirror = (function() {
|
|
968
1123
|
" nodes=" + lineDiv.childNodes.length);
|
969
1124
|
|
970
1125
|
function checkHeights() {
|
971
|
-
maxWidth = scroller.clientWidth;
|
972
1126
|
var curNode = lineDiv.firstChild, heightChanged = false;
|
973
1127
|
doc.iter(showingFrom, showingTo, function(line) {
|
974
1128
|
if (!line.hidden) {
|
@@ -980,22 +1134,17 @@ var CodeMirror = (function() {
|
|
980
1134
|
}
|
981
1135
|
curNode = curNode.nextSibling;
|
982
1136
|
});
|
983
|
-
if (heightChanged)
|
984
|
-
code.style.height = (doc.height * th + 2 * paddingTop()) + "px";
|
985
1137
|
return heightChanged;
|
986
1138
|
}
|
987
1139
|
|
988
1140
|
if (options.lineWrapping) {
|
989
1141
|
checkHeights();
|
990
|
-
|
991
|
-
|
992
|
-
if (
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
code.style.width = scroller.scrollWidth + "px";
|
997
|
-
} else {
|
998
|
-
lineSpace.style.width = code.style.width = "";
|
1142
|
+
var scrollHeight = needsScrollbar();
|
1143
|
+
var shouldHaveScrollbar = scrollHeight ? "block" : "none";
|
1144
|
+
if (scrollbar.style.display != shouldHaveScrollbar) {
|
1145
|
+
scrollbar.style.display = shouldHaveScrollbar;
|
1146
|
+
if (scrollHeight) scrollbarInner.style.height = scrollHeight + "px";
|
1147
|
+
checkHeights();
|
999
1148
|
}
|
1000
1149
|
}
|
1001
1150
|
|
@@ -1004,6 +1153,7 @@ var CodeMirror = (function() {
|
|
1004
1153
|
// If the gutter grew in size, re-check heights. If those changed, re-draw gutter.
|
1005
1154
|
updateGutter() && options.lineWrapping && checkHeights() && updateGutter();
|
1006
1155
|
}
|
1156
|
+
updateVerticalScroll(scrollTop);
|
1007
1157
|
updateSelection();
|
1008
1158
|
if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
|
1009
1159
|
return true;
|
@@ -1083,7 +1233,7 @@ var CodeMirror = (function() {
|
|
1083
1233
|
html.push("<pre></pre>");
|
1084
1234
|
} else {
|
1085
1235
|
var marker = line.gutterMarker;
|
1086
|
-
var text = options.lineNumbers ? i + options.firstLineNumber : null;
|
1236
|
+
var text = options.lineNumbers ? options.lineNumberFormatter(i + options.firstLineNumber) : null;
|
1087
1237
|
if (marker && marker.text)
|
1088
1238
|
text = marker.text.replace("%N%", text != null ? text : "");
|
1089
1239
|
else if (text == null)
|
@@ -1098,9 +1248,9 @@ var CodeMirror = (function() {
|
|
1098
1248
|
gutter.style.display = "none";
|
1099
1249
|
gutterText.innerHTML = html.join("");
|
1100
1250
|
// Make sure scrolling doesn't cause number gutter size to pop
|
1101
|
-
if (normalNode != null) {
|
1251
|
+
if (normalNode != null && options.lineNumbers) {
|
1102
1252
|
var node = gutterText.childNodes[normalNode - showingFrom];
|
1103
|
-
var minwidth = String(doc.size).length, val = eltText(node), pad = "";
|
1253
|
+
var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = "";
|
1104
1254
|
while (val.length + pad.length < minwidth) pad += "\u00a0";
|
1105
1255
|
if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild);
|
1106
1256
|
}
|
@@ -1282,17 +1432,19 @@ var CodeMirror = (function() {
|
|
1282
1432
|
if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
|
1283
1433
|
else if (unit == "line") dist = textHeight();
|
1284
1434
|
var target = coordsChar(pos.x, pos.y + dist * dir + 2);
|
1285
|
-
if (unit == "page")
|
1435
|
+
if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y;
|
1286
1436
|
setCursor(target.line, target.ch, true);
|
1287
1437
|
goalColumn = pos.x;
|
1288
1438
|
}
|
1289
1439
|
|
1290
|
-
function
|
1440
|
+
function findWordAt(pos) {
|
1291
1441
|
var line = getLine(pos.line).text;
|
1292
1442
|
var start = pos.ch, end = pos.ch;
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1443
|
+
var check = isWordChar(line.charAt(start < line.length ? start : start - 1)) ?
|
1444
|
+
isWordChar : function(ch) {return !isWordChar(ch);};
|
1445
|
+
while (start > 0 && check(line.charAt(start - 1))) --start;
|
1446
|
+
while (end < line.length && check(line.charAt(end))) ++end;
|
1447
|
+
return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}};
|
1296
1448
|
}
|
1297
1449
|
function selectLine(line) {
|
1298
1450
|
setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
|
@@ -1312,26 +1464,23 @@ var CodeMirror = (function() {
|
|
1312
1464
|
|
1313
1465
|
var line = getLine(n), curSpace = line.indentation(options.tabSize),
|
1314
1466
|
curSpaceString = line.text.match(/^\s*/)[0], indentation;
|
1467
|
+
if (how == "smart") {
|
1468
|
+
indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
|
1469
|
+
if (indentation == Pass) how = "prev";
|
1470
|
+
}
|
1315
1471
|
if (how == "prev") {
|
1316
1472
|
if (n) indentation = getLine(n-1).indentation(options.tabSize);
|
1317
1473
|
else indentation = 0;
|
1318
1474
|
}
|
1319
|
-
else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
|
1320
1475
|
else if (how == "add") indentation = curSpace + options.indentUnit;
|
1321
1476
|
else if (how == "subtract") indentation = curSpace - options.indentUnit;
|
1322
1477
|
indentation = Math.max(0, indentation);
|
1323
1478
|
var diff = indentation - curSpace;
|
1324
1479
|
|
1325
|
-
|
1326
|
-
|
1327
|
-
var
|
1328
|
-
}
|
1329
|
-
else {
|
1330
|
-
var indentString = "", pos = 0;
|
1331
|
-
if (options.indentWithTabs)
|
1332
|
-
for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
|
1333
|
-
while (pos < indentation) {++pos; indentString += " ";}
|
1334
|
-
}
|
1480
|
+
var indentString = "", pos = 0;
|
1481
|
+
if (options.indentWithTabs)
|
1482
|
+
for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
|
1483
|
+
while (pos < indentation) {++pos; indentString += " ";}
|
1335
1484
|
|
1336
1485
|
replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
|
1337
1486
|
}
|
@@ -1358,9 +1507,10 @@ var CodeMirror = (function() {
|
|
1358
1507
|
if (guess != 1) updateLineHeight(line, guess);
|
1359
1508
|
});
|
1360
1509
|
lineSpace.style.width = code.style.width = "";
|
1510
|
+
widthForcer.style.left = "";
|
1361
1511
|
} else {
|
1362
1512
|
wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
|
1363
|
-
|
1513
|
+
maxLine = ""; maxLineChanged = true;
|
1364
1514
|
doc.iter(0, doc.size, function(line) {
|
1365
1515
|
if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
|
1366
1516
|
if (line.text.length > maxLine.length) maxLine = line.text;
|
@@ -1378,6 +1528,11 @@ var CodeMirror = (function() {
|
|
1378
1528
|
scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
|
1379
1529
|
options.theme.replace(/(^|\s)\s*/g, " cm-s-");
|
1380
1530
|
}
|
1531
|
+
function keyMapChanged() {
|
1532
|
+
var style = keyMap[options.keyMap].style;
|
1533
|
+
wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
|
1534
|
+
(style ? " cm-keymap-" + style : "");
|
1535
|
+
}
|
1381
1536
|
|
1382
1537
|
function TextMarker() { this.set = []; }
|
1383
1538
|
TextMarker.prototype.clear = operation(function() {
|
@@ -1485,6 +1640,14 @@ var CodeMirror = (function() {
|
|
1485
1640
|
return changeLine(handle, function(line, no) {
|
1486
1641
|
if (line.hidden != hidden) {
|
1487
1642
|
line.hidden = hidden;
|
1643
|
+
if (!options.lineWrapping) {
|
1644
|
+
var l = line.text;
|
1645
|
+
if (hidden && l.length == maxLine.length) {
|
1646
|
+
updateMaxLine = true;
|
1647
|
+
} else if (!hidden && l.length > maxLine.length) {
|
1648
|
+
maxLine = l; updateMaxLine = false;
|
1649
|
+
}
|
1650
|
+
}
|
1488
1651
|
updateLineHeight(line, hidden ? 0 : 1);
|
1489
1652
|
var fline = sel.from.line, tline = sel.to.line;
|
1490
1653
|
if (hidden && (fline == no || tline == no)) {
|
@@ -1505,8 +1668,7 @@ var CodeMirror = (function() {
|
|
1505
1668
|
var n = line;
|
1506
1669
|
line = getLine(line);
|
1507
1670
|
if (!line) return null;
|
1508
|
-
}
|
1509
|
-
else {
|
1671
|
+
} else {
|
1510
1672
|
var n = lineNo(line);
|
1511
1673
|
if (n == null) return null;
|
1512
1674
|
}
|
@@ -1655,8 +1817,8 @@ var CodeMirror = (function() {
|
|
1655
1817
|
return coordsChar(x - offL.left, y - offL.top);
|
1656
1818
|
}
|
1657
1819
|
function onContextMenu(e) {
|
1658
|
-
var pos = posFromMouse(e), scrollPos =
|
1659
|
-
if (!pos ||
|
1820
|
+
var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
|
1821
|
+
if (!pos || opera) return; // Opera is difficult.
|
1660
1822
|
if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
|
1661
1823
|
operation(setCursor)(pos.line, pos.ch);
|
1662
1824
|
|
@@ -1671,10 +1833,10 @@ var CodeMirror = (function() {
|
|
1671
1833
|
selectInput(input);
|
1672
1834
|
function rehide() {
|
1673
1835
|
var newVal = splitLines(input.value).join("\n");
|
1674
|
-
if (newVal != val) operation(replaceSelection)(newVal, "end");
|
1836
|
+
if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end");
|
1675
1837
|
inputDiv.style.position = "relative";
|
1676
1838
|
input.style.cssText = oldCSS;
|
1677
|
-
if (ie_lt9)
|
1839
|
+
if (ie_lt9) scrollbar.scrollTop = scrollPos;
|
1678
1840
|
leaveInputAlone = false;
|
1679
1841
|
resetInput(true);
|
1680
1842
|
slowPoll();
|
@@ -1716,7 +1878,7 @@ var CodeMirror = (function() {
|
|
1716
1878
|
var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
|
1717
1879
|
for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
|
1718
1880
|
var text = st[i];
|
1719
|
-
if (st[i+1] !=
|
1881
|
+
if (st[i+1] != style) {pos += d * text.length; continue;}
|
1720
1882
|
for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
|
1721
1883
|
if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
|
1722
1884
|
var match = matching[cur];
|
@@ -1836,14 +1998,24 @@ var CodeMirror = (function() {
|
|
1836
1998
|
changes = []; selectionChanged = false; callbacks = [];
|
1837
1999
|
}
|
1838
2000
|
function endOperation() {
|
1839
|
-
|
1840
|
-
if (
|
1841
|
-
|
2001
|
+
if (updateMaxLine) computeMaxLength();
|
2002
|
+
if (maxLineChanged && !options.lineWrapping) {
|
2003
|
+
var cursorWidth = widthForcer.offsetWidth, left = stringWidth(maxLine);
|
2004
|
+
widthForcer.style.left = left + "px";
|
2005
|
+
lineSpace.style.minWidth = (left + cursorWidth) + "px";
|
2006
|
+
maxLineChanged = false;
|
2007
|
+
}
|
2008
|
+
var newScrollPos, updated;
|
2009
|
+
if (selectionChanged) {
|
2010
|
+
var coords = calculateCursorCoords();
|
2011
|
+
newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot);
|
2012
|
+
}
|
2013
|
+
if (changes.length) updated = updateDisplay(changes, true, (newScrollPos ? newScrollPos.scrollTop : null));
|
1842
2014
|
else {
|
1843
2015
|
if (selectionChanged) updateSelection();
|
1844
2016
|
if (gutterDirty) updateGutter();
|
1845
2017
|
}
|
1846
|
-
if (
|
2018
|
+
if (newScrollPos) scrollCursorIntoView();
|
1847
2019
|
if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
|
1848
2020
|
|
1849
2021
|
if (focused && !leaveInputAlone &&
|
@@ -1855,11 +2027,11 @@ var CodeMirror = (function() {
|
|
1855
2027
|
if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
|
1856
2028
|
if (posEq(sel.from, sel.to)) matchBrackets(false);
|
1857
2029
|
}), 20);
|
1858
|
-
var
|
1859
|
-
if (
|
2030
|
+
var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks
|
2031
|
+
if (textChanged && options.onChange && instance)
|
2032
|
+
options.onChange(instance, textChanged);
|
2033
|
+
if (sc && options.onCursorActivity)
|
1860
2034
|
options.onCursorActivity(instance);
|
1861
|
-
if (tc && options.onChange && instance)
|
1862
|
-
options.onChange(instance, tc);
|
1863
2035
|
for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
|
1864
2036
|
if (updated && options.onUpdate) options.onUpdate(instance);
|
1865
2037
|
}
|
@@ -1919,7 +2091,8 @@ var CodeMirror = (function() {
|
|
1919
2091
|
pollInterval: 100,
|
1920
2092
|
undoDepth: 40,
|
1921
2093
|
tabindex: null,
|
1922
|
-
autofocus: null
|
2094
|
+
autofocus: null,
|
2095
|
+
lineNumberFormatter: function(integer) { return integer; }
|
1923
2096
|
};
|
1924
2097
|
|
1925
2098
|
var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
|
@@ -2008,6 +2181,10 @@ var CodeMirror = (function() {
|
|
2008
2181
|
indentMore: function(cm) {cm.indentSelection("add");},
|
2009
2182
|
indentLess: function(cm) {cm.indentSelection("subtract");},
|
2010
2183
|
insertTab: function(cm) {cm.replaceSelection("\t", "end");},
|
2184
|
+
defaultTab: function(cm) {
|
2185
|
+
if (cm.somethingSelected()) cm.indentSelection("add");
|
2186
|
+
else cm.replaceSelection("\t", "end");
|
2187
|
+
},
|
2011
2188
|
transposeChars: function(cm) {
|
2012
2189
|
var cur = cm.getCursor(), line = cm.getLine(cur.line);
|
2013
2190
|
if (cur.ch > 0 && cur.ch < line.length - 1)
|
@@ -2025,7 +2202,7 @@ var CodeMirror = (function() {
|
|
2025
2202
|
keyMap.basic = {
|
2026
2203
|
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
|
2027
2204
|
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
|
2028
|
-
"Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "
|
2205
|
+
"Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
|
2029
2206
|
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
|
2030
2207
|
};
|
2031
2208
|
// Note that the save and find-related commands aren't defined by
|
@@ -2193,8 +2370,7 @@ var CodeMirror = (function() {
|
|
2193
2370
|
if (consume !== false) this.pos += pattern.length;
|
2194
2371
|
return true;
|
2195
2372
|
}
|
2196
|
-
}
|
2197
|
-
else {
|
2373
|
+
} else {
|
2198
2374
|
var match = this.string.slice(this.pos).match(pattern);
|
2199
2375
|
if (match && consume !== false) this.pos += match[0].length;
|
2200
2376
|
return match;
|
@@ -2361,11 +2537,20 @@ var CodeMirror = (function() {
|
|
2361
2537
|
fixMarkEnds: function(other) {
|
2362
2538
|
var mk = this.marked, omk = other.marked;
|
2363
2539
|
if (!mk) return;
|
2364
|
-
for (var i = 0; i < mk.length; ++i) {
|
2540
|
+
outer: for (var i = 0; i < mk.length; ++i) {
|
2365
2541
|
var mark = mk[i], close = mark.to == null;
|
2366
2542
|
if (close && omk) {
|
2367
|
-
for (var j = 0; j < omk.length; ++j)
|
2368
|
-
|
2543
|
+
for (var j = 0; j < omk.length; ++j) {
|
2544
|
+
var om = omk[j];
|
2545
|
+
if (!om.sameSet(mark) || om.from != null) continue
|
2546
|
+
if (mark.from == this.text.length && om.to == 0) {
|
2547
|
+
omk.splice(j, 1);
|
2548
|
+
mk.splice(i--, 1);
|
2549
|
+
continue outer;
|
2550
|
+
} else {
|
2551
|
+
close = false; break;
|
2552
|
+
}
|
2553
|
+
}
|
2369
2554
|
}
|
2370
2555
|
if (close) mark.to = this.text.length;
|
2371
2556
|
}
|
@@ -2472,15 +2657,22 @@ var CodeMirror = (function() {
|
|
2472
2657
|
if (wrapWBR) html.push("<wbr>");
|
2473
2658
|
}
|
2474
2659
|
html.push(open);
|
2475
|
-
|
2660
|
+
var cut = wrapAt - outPos;
|
2661
|
+
span_(opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
|
2476
2662
|
html.push("</span>");
|
2663
|
+
if (opera) span_(text.slice(cut + 1), style);
|
2477
2664
|
wrapAt--;
|
2478
2665
|
outPos += l;
|
2479
2666
|
} else {
|
2480
2667
|
outPos += l;
|
2481
2668
|
span_(text, style);
|
2482
2669
|
// Output empty wrapper when at end of line
|
2483
|
-
|
2670
|
+
// (Gecko and IE8+ do strange wrapping when adding a space
|
2671
|
+
// to the end of the line. Other browsers don't react well
|
2672
|
+
// to zero-width spaces. So we do hideous browser sniffing
|
2673
|
+
// to determine which to use.)
|
2674
|
+
if (outPos == wrapAt && outPos == len)
|
2675
|
+
html.push(open + (gecko || (ie && !ie_lt8) ? "​" : " ") + "</span>");
|
2484
2676
|
// Stop outputting HTML when gone sufficiently far beyond measure
|
2485
2677
|
else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
|
2486
2678
|
}
|
@@ -2515,7 +2707,8 @@ var CodeMirror = (function() {
|
|
2515
2707
|
}
|
2516
2708
|
nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
|
2517
2709
|
for (var i = 0; i < marks.length; ++i) {
|
2518
|
-
var to = marks[i].to
|
2710
|
+
var to = marks[i].to;
|
2711
|
+
if (to == null) to = Infinity;
|
2519
2712
|
if (to == pos) marks.splice(i--, 1);
|
2520
2713
|
else nextChange = Math.min(to, nextChange);
|
2521
2714
|
}
|
@@ -2553,8 +2746,7 @@ var CodeMirror = (function() {
|
|
2553
2746
|
if (state == 0) {
|
2554
2747
|
if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
|
2555
2748
|
if (end >= from) state = 1;
|
2556
|
-
}
|
2557
|
-
else if (state == 1) {
|
2749
|
+
} else if (state == 1) {
|
2558
2750
|
if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
|
2559
2751
|
else dest.push(part, source[i+1]);
|
2560
2752
|
}
|
@@ -2589,11 +2781,7 @@ var CodeMirror = (function() {
|
|
2589
2781
|
},
|
2590
2782
|
insertHeight: function(at, lines, height) {
|
2591
2783
|
this.height += height;
|
2592
|
-
|
2593
|
-
// occasionally corrupts this.lines (duplicating elements) when
|
2594
|
-
// it is used.
|
2595
|
-
if (ie) this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
|
2596
|
-
else this.lines.splice.apply(this.lines, [at, 0].concat(lines));
|
2784
|
+
this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
|
2597
2785
|
for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
|
2598
2786
|
},
|
2599
2787
|
iterN: function(at, n, op) {
|
@@ -2814,10 +3002,14 @@ var CodeMirror = (function() {
|
|
2814
3002
|
|
2815
3003
|
function e_target(e) {return e.target || e.srcElement;}
|
2816
3004
|
function e_button(e) {
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
2820
|
-
|
3005
|
+
var b = e.which;
|
3006
|
+
if (b == null) {
|
3007
|
+
if (e.button & 1) b = 1;
|
3008
|
+
else if (e.button & 2) b = 3;
|
3009
|
+
else if (e.button & 4) b = 2;
|
3010
|
+
}
|
3011
|
+
if (mac && e.ctrlKey && b == 1) b = 3;
|
3012
|
+
return b;
|
2821
3013
|
}
|
2822
3014
|
|
2823
3015
|
// Allow 3rd-party code to override event properties by adding an override
|
@@ -2833,8 +3025,7 @@ var CodeMirror = (function() {
|
|
2833
3025
|
if (typeof node.addEventListener == "function") {
|
2834
3026
|
node.addEventListener(type, handler, false);
|
2835
3027
|
if (disconnect) return function() {node.removeEventListener(type, handler, false);};
|
2836
|
-
}
|
2837
|
-
else {
|
3028
|
+
} else {
|
2838
3029
|
var wrapHandler = function(event) {handler(event || window.event);};
|
2839
3030
|
node.attachEvent("on" + type, wrapHandler);
|
2840
3031
|
if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
|
@@ -2849,12 +3040,15 @@ var CodeMirror = (function() {
|
|
2849
3040
|
|
2850
3041
|
var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
|
2851
3042
|
var ie = /MSIE \d/.test(navigator.userAgent);
|
3043
|
+
var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
|
2852
3044
|
var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
|
2853
3045
|
var quirksMode = ie && document.documentMode == 5;
|
2854
3046
|
var webkit = /WebKit\//.test(navigator.userAgent);
|
2855
3047
|
var chrome = /Chrome\//.test(navigator.userAgent);
|
3048
|
+
var opera = /Opera\//.test(navigator.userAgent);
|
2856
3049
|
var safari = /Apple Computer/.test(navigator.vendor);
|
2857
3050
|
var khtml = /KHTML\//.test(navigator.userAgent);
|
3051
|
+
var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent);
|
2858
3052
|
|
2859
3053
|
// Detect drag-and-drop
|
2860
3054
|
var dragAndDrop = function() {
|
@@ -2904,26 +3098,7 @@ var CodeMirror = (function() {
|
|
2904
3098
|
return window.getComputedStyle(elt, null);
|
2905
3099
|
}
|
2906
3100
|
|
2907
|
-
// Find the position of an element by following the offsetParent chain.
|
2908
|
-
// If screen==true, it returns screen (rather than page) coordinates.
|
2909
3101
|
function eltOffset(node, screen) {
|
2910
|
-
var bod = node.ownerDocument.body;
|
2911
|
-
var x = 0, y = 0, skipBody = false;
|
2912
|
-
for (var n = node; n; n = n.offsetParent) {
|
2913
|
-
var ol = n.offsetLeft, ot = n.offsetTop;
|
2914
|
-
// Firefox reports weird inverted offsets when the body has a border.
|
2915
|
-
if (n == bod) { x += Math.abs(ol); y += Math.abs(ot); }
|
2916
|
-
else { x += ol, y += ot; }
|
2917
|
-
if (screen && computedStyle(n).position == "fixed")
|
2918
|
-
skipBody = true;
|
2919
|
-
}
|
2920
|
-
var e = screen && !skipBody ? null : bod;
|
2921
|
-
for (var n = node.parentNode; n != e; n = n.parentNode)
|
2922
|
-
if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;}
|
2923
|
-
return {left: x, top: y};
|
2924
|
-
}
|
2925
|
-
// Use the faster and saner getBoundingClientRect method when possible.
|
2926
|
-
if (document.documentElement.getBoundingClientRect != null) eltOffset = function(node, screen) {
|
2927
3102
|
// Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
|
2928
3103
|
// since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
|
2929
3104
|
try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
|
@@ -2939,7 +3114,7 @@ var CodeMirror = (function() {
|
|
2939
3114
|
}
|
2940
3115
|
}
|
2941
3116
|
return box;
|
2942
|
-
}
|
3117
|
+
}
|
2943
3118
|
|
2944
3119
|
// Get a node's text content.
|
2945
3120
|
function eltText(node) {
|
@@ -2964,18 +3139,19 @@ var CodeMirror = (function() {
|
|
2964
3139
|
}
|
2965
3140
|
// Recent (late 2011) Opera betas insert bogus newlines at the start
|
2966
3141
|
// of the textContent, so we strip those.
|
2967
|
-
if (htmlEscape("a") == "\na")
|
3142
|
+
if (htmlEscape("a") == "\na") {
|
2968
3143
|
htmlEscape = function(str) {
|
2969
3144
|
escapeElement.textContent = str;
|
2970
3145
|
return escapeElement.innerHTML.slice(1);
|
2971
3146
|
};
|
2972
3147
|
// Some IEs don't preserve tabs through innerHTML
|
2973
|
-
else if (htmlEscape("\t") != "\t")
|
3148
|
+
} else if (htmlEscape("\t") != "\t") {
|
2974
3149
|
htmlEscape = function(str) {
|
2975
3150
|
escapeElement.innerHTML = "";
|
2976
3151
|
escapeElement.appendChild(document.createTextNode(str));
|
2977
3152
|
return escapeElement.innerHTML;
|
2978
3153
|
};
|
3154
|
+
}
|
2979
3155
|
CodeMirror.htmlEscape = htmlEscape;
|
2980
3156
|
|
2981
3157
|
// Used to position the cursor after an undo/redo by finding the
|
@@ -3001,14 +3177,22 @@ var CodeMirror = (function() {
|
|
3001
3177
|
// See if "".split is the broken IE version, if so, provide an
|
3002
3178
|
// alternative way to split lines.
|
3003
3179
|
var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
|
3004
|
-
var pos = 0,
|
3005
|
-
while (
|
3006
|
-
|
3007
|
-
|
3180
|
+
var pos = 0, result = [], l = string.length;
|
3181
|
+
while (pos <= l) {
|
3182
|
+
var nl = string.indexOf("\n", pos);
|
3183
|
+
if (nl == -1) nl = string.length;
|
3184
|
+
var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
|
3185
|
+
var rt = line.indexOf("\r");
|
3186
|
+
if (rt != -1) {
|
3187
|
+
result.push(line.slice(0, rt));
|
3188
|
+
pos += rt + 1;
|
3189
|
+
} else {
|
3190
|
+
result.push(line);
|
3191
|
+
pos = nl + 1;
|
3192
|
+
}
|
3008
3193
|
}
|
3009
|
-
result.push(string.slice(pos));
|
3010
3194
|
return result;
|
3011
|
-
} : function(string){return string.split(/\r
|
3195
|
+
} : function(string){return string.split(/\r\n?|\n/);};
|
3012
3196
|
CodeMirror.splitLines = splitLines;
|
3013
3197
|
|
3014
3198
|
var hasSelection = window.getSelection ? function(te) {
|
@@ -3029,10 +3213,10 @@ var CodeMirror = (function() {
|
|
3029
3213
|
var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
|
3030
3214
|
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
|
3031
3215
|
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
|
3032
|
-
46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod",
|
3033
|
-
|
3034
|
-
|
3035
|
-
63233: "Down", 63302: "Insert", 63272: "Delete"};
|
3216
|
+
46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
|
3217
|
+
186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
|
3218
|
+
221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
|
3219
|
+
63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
|
3036
3220
|
CodeMirror.keyNames = keyNames;
|
3037
3221
|
(function() {
|
3038
3222
|
// Number keys
|