Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5781ac6bbd | |||
| a51bc4427a | |||
| 80854584bb | |||
| a27b882493 | |||
| ba6f957692 | |||
| ec0e1bf26f | |||
| e4df298bb4 | |||
| 804d21e31d | |||
| 6d33687866 | |||
| 21bb1efb46 | |||
| 9d0986f1ca | |||
| fd483f397f | |||
| 09364850ee | |||
| 4d3a8bad4c | |||
| cc39b0aa41 | |||
| 6fc3b4be75 | |||
| af6d690fc8 | |||
| eea5152444 | |||
| 1ca38b625b | |||
| f964407c47 | |||
| 3be2e76ec0 | |||
| f9a9b90ed7 | |||
| 1f2917ac22 | |||
| fe1a8569f6 | |||
| 33e8d4f328 | |||
| e183260d0a | |||
| b4023942b4 | |||
| c10c24d90d | |||
| 915f63cac4 | |||
| 5c30ff4d3e | |||
| 3269f02ba7 | |||
| e5c2e3b3eb | |||
| 77f4aee0af | |||
| 868cbdfc7b | |||
| a650c0eab8 | |||
| a7dc8d8c6f | |||
| 355db16d2c | |||
| c54ce41eb7 | |||
| afb7d4c9d1 | |||
| b55cdde9da | |||
| 93cbc6c770 | |||
| 3b1b4a0a96 | |||
| 10b45cb54d | |||
| 9d289e571b | |||
| cce871c30e | |||
| c2b605a90f | |||
| 09149592b5 | |||
| e7410e551b | |||
| 9d77bc4192 | |||
| 537fa0c423 | |||
| c78dbc8bc1 | |||
| 249eed5c2c | |||
| 55eb3b24f7 | |||
| 508c255d0f | |||
| 9f8a90c0ac | |||
| 861dc935cb | |||
| 96ef8cacea | |||
| 5f3ecc8713 | |||
| 8b8ef0eb46 | |||
| 2dbea54c84 | |||
| a776d9fb6f | |||
| 57b7bbff5a | |||
| a832b0ed54 | |||
| 3ec75b84ae | |||
| b932763080 | |||
| 374f8f2f69 | |||
| 226c253d5a | |||
| c78a9f7950 | |||
| 7264510ab2 | |||
| 3458ec6511 | |||
| 2c80db6678 | |||
| 439aa6e4f5 | |||
| adf544dca9 | |||
| 0965269ee9 | |||
| 19d370c4e9 | |||
| cee0f8b652 | |||
| 37664d3487 | |||
| 5a78015d81 | |||
| 7250962ba3 | |||
| 442120bfdb | |||
| de624d1e54 | |||
| 523029cc45 | |||
| 934affe419 | |||
| 55b9af1589 | |||
| 16dd7e46ef | |||
| 851c77d8f2 | |||
| ee55b74898 | |||
| 13fc1e5c66 | |||
| 87112c2942 | |||
| 2664fdca30 | |||
| e05f523145 | |||
| 1148d29439 | |||
| 7ba52978d1 | |||
| 138a9fee43 | |||
| 1d522eaf0d | |||
| b5c5da64c9 | |||
| 8466425836 | |||
| b774ee5cd0 | |||
| 7e2e0e926b | |||
| 30f673c63c | |||
| bb5be728e3 | |||
| 0be5d1c657 | |||
| d143e6be06 | |||
| e65a78a5f5 | |||
| 4f443a3c62 | |||
| ff82ddea97 | |||
| 08dd36e1b0 |
@@ -3,6 +3,7 @@ rvm:
|
||||
- 2.0.0
|
||||
- 2.1.0
|
||||
- 2.1.1
|
||||
- jruby-19mode
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install libicu-dev
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
gem 'rake', '~> 10.2.2'
|
||||
gem 'rake', '~> 10.4'
|
||||
|
||||
+18
@@ -1,3 +1,21 @@
|
||||
# 3.1.1 /2014-12-04
|
||||
|
||||
* Security fix for [remote code execution issue](https://github.com/gollum/gollum/issues/913). Please update!
|
||||
|
||||
# 3.1 / 2014-11-28
|
||||
|
||||
* New features
|
||||
* Drag-and-drop uploading in the editor [@lucas-clemente](https://github.com/lucas-clemente)
|
||||
* Latest changes view [@etienneCharignon](https://github.com/etienneCharignon) (#707)
|
||||
* Option `--no-edit` to disable editing from the web interface [@bambycha](https://github.com/bambycha) (#879)
|
||||
* Option `--mathjax-config` to specify custom mathjax configuration [@hardywu](https://github.com/hardywu) (#842)
|
||||
* Major enhancements
|
||||
* Made the Gollum theme responsive [@rtrvrtg](https://github.com/rtrvrtg) (#831)
|
||||
* Depends on new [gollum-lib](https://github.com/gollum/gollum-lib) `4.0.0`
|
||||
* Allows specifiying [git adapter](https://github.com/gollum/gollum/wiki/Git-adapters) with `--adapter` [@bartkamphorst](https://github.com/bartkamphorst), [@dometto](https://github.com/dometto)
|
||||
* Numerous bugfixes
|
||||
* **NB**: please pass `--h1-title` if you do not want page titles to default to the page's filepath. See [here](https://github.com/gollum/gollum/wiki/Page-titles).
|
||||
|
||||
# 2.4.11 / 2013-01-08
|
||||
|
||||
* Numerous security issues have been fixed. Please update to `2.4.11`
|
||||
|
||||
@@ -29,7 +29,7 @@ Gollum follows the rules of [Semantic Versioning](http://semver.org/) and uses
|
||||
|
||||
## SECURITY
|
||||
|
||||
Don't enable `--custom-css` or `--custom-js` unless you trust every user who has the ability to edit the wiki.
|
||||
Don't enable `--custom-css`, `--custom-js` or `--mathjax-config` unless you trust every user who has the ability to edit the wiki.
|
||||
A better solution with more security is being tracked in [#665](https://github.com/gollum/gollum/issues/665).
|
||||
|
||||
## INSTALLATION
|
||||
@@ -39,6 +39,7 @@ The best way to install Gollum is with RubyGems:
|
||||
```bash
|
||||
$ [sudo] gem install gollum
|
||||
```
|
||||
You may first need to install some additional [development packages](https://github.com/gollum/gollum/wiki/Installation) for your OS.
|
||||
|
||||
If you're installing from source, you can use [Bundler][bundler] to pick up all the
|
||||
gems:
|
||||
@@ -51,15 +52,15 @@ In order to use the various formats that Gollum supports, you will need to
|
||||
separately install the necessary dependencies for each format. You only need
|
||||
to install the dependencies for the formats that you plan to use.
|
||||
|
||||
* [ASCIIDoc](http://www.methods.co.nz/asciidoc/) -- `brew install asciidoc` on mac or `apt-get install -y asciidoc` on Ubuntu
|
||||
* [Creole](http://wikicreole.org/) -- `gem install creole`
|
||||
* [AsciiDoc](http://asciidoctor.org) -- `gem install asciidoctor`
|
||||
* [Creole](http://www.wikicreole.org/) -- `gem install creole`
|
||||
* [Markdown](http://daringfireball.net/projects/markdown/) -- `gem install redcarpet`
|
||||
* [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown) -- `gem install github-markdown`
|
||||
* [Org](http://orgmode.org/) -- `gem install org-ruby`
|
||||
* [Pod](http://search.cpan.org/dist/perl/pod/perlpod.pod) -- `Pod::Simple::HTML` comes with Perl >= 5.10. Lower versions should install Pod::Simple from CPAN.
|
||||
* [RDoc](http://rdoc.sourceforge.net/)
|
||||
* [ReStructuredText](http://docutils.sourceforge.net/rst.html) -- `easy_install docutils`
|
||||
* [Textile](http://www.textism.com/tools/textile/) -- `gem install RedCloth`
|
||||
* [Textile](http://en.wikipedia.org/wiki/Textile_(markup_language)) -- `gem install RedCloth`
|
||||
* [MediaWiki](http://www.mediawiki.org/wiki/Help:Formatting) -- `gem install wikicloth`
|
||||
|
||||
[bundler]: http://gembundler.com/
|
||||
@@ -98,32 +99,35 @@ Options:
|
||||
--port [PORT] Bind port (default 4567).
|
||||
--host [HOST] Hostname or IP address to listen on (default 0.0.0.0).
|
||||
--version Display current version.
|
||||
--config [CONFIG] Path to additional configuration file
|
||||
--config [CONFIG] Path to additional configuration file.
|
||||
--adapter [ADAPTER] Git adapter to use in the backend. Defaults to grit.
|
||||
--irb Start an irb process with gollum loaded for the current wiki.
|
||||
--css Inject custom css. Uses custom.css from root repository
|
||||
--js Inject custom js. Uses custom.js from root repository
|
||||
--template-dir [PATH] Specify custom template directory
|
||||
--css Inject custom css. Uses custom.css from root repository.
|
||||
--js Inject custom js. Uses custom.js from root repository.
|
||||
--template-dir [PATH] Specify custom template directory.
|
||||
--page-file-dir [PATH] Specify the sub directory for all page files (default: repository root).
|
||||
--base-path [PATH] Specify the base path.
|
||||
--gollum-path [PATH] Specify the gollum path.
|
||||
--base-path [PATH] Specify the base path for the served pages (default: /) Example: --base-path wiki yields the home page accessible at http://localhost:4567/wiki/.
|
||||
--gollum-path [PATH] Specify the path to the git repository to be served.
|
||||
--ref [REF] Specify the repository ref to use (default: master).
|
||||
--bare Specify that the repository is bare (only necessary when using the grit adapter).
|
||||
--no-edit Restricts editing capability through frontend.
|
||||
--no-live-preview Disables livepreview.
|
||||
--live-preview Enables livepreview.
|
||||
--allow-uploads Allows file uploads.
|
||||
--mathjax Enables mathjax.
|
||||
--allow-uploads [MODE] Allows file uploads. Modes: dir (default, store all uploads in the same directory), page (store each upload at the same location as the page).
|
||||
--mathjax Enables mathjax for rendering mathematical equations. Uses the TeX-AMS-MML_HTMLorMML config with the autoload-all extension by default.
|
||||
--mathjax-config [SOURCE] Inject custom mathjax config file. Uses mathjax.config.js from root repository by default.
|
||||
--user-icons [SOURCE] Set the history user icons. Valid values: gravatar, identicon, none. Default: none.
|
||||
--show-all Shows all files in file view. By default only valid pages are shown.
|
||||
--collapse-tree Collapse file view tree. By default, expanded tree is shown.
|
||||
--h1-title Sets page title to value of first h1
|
||||
--h1-title Sets page title to value of first h1.
|
||||
```
|
||||
|
||||
Note that the gollum server will not run on Windows because of [an issue](https://github.com/rtomayko/posix-spawn/issues/9) with posix-spawn (which is used by Grit).
|
||||
|
||||
### RACK
|
||||
|
||||
You can also run gollum with any rack-compatible server by placing this config.ru
|
||||
file inside your wiki repository. This allows you to utilize any Rack middleware
|
||||
like Rack::Auth, OmniAuth, etc.
|
||||
You can also run gollum with any rack-compatible server by placing configuring a config.ru
|
||||
file. This allows you to utilize any Rack middleware like Rack::Auth, OmniAuth, etc. See below for an example of a `config.ru`. You can define all the [options available on the command line](#running) by configuring the app's `:wiki_options` hash. See [here](https://github.com/gollum/gollum/wiki/Using-Gollum-with-Rack) for the names of the options corresponding to the command line switches.
|
||||
|
||||
```ruby
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
+20
-3
@@ -22,6 +22,7 @@ options = { 'port' => 4567, 'bind' => '0.0.0.0' }
|
||||
wiki_options = {
|
||||
:live_preview => false,
|
||||
:allow_uploads => false,
|
||||
:allow_editing => true,
|
||||
}
|
||||
|
||||
opts = OptionParser.new do |opts|
|
||||
@@ -44,6 +45,10 @@ opts = OptionParser.new do |opts|
|
||||
options['config'] = config
|
||||
end
|
||||
|
||||
opts.on("--adapter [ADAPTER]", "Git adapter to use in the backend. Defaults to grit.") do |adapter|
|
||||
Gollum::GIT_ADAPTER = adapter
|
||||
end
|
||||
|
||||
opts.on("--irb", "Start an irb process with gollum loaded for the current wiki.") do
|
||||
options['irb'] = true
|
||||
end
|
||||
@@ -64,11 +69,11 @@ opts = OptionParser.new do |opts|
|
||||
wiki_options[:page_file_dir] = path
|
||||
end
|
||||
|
||||
opts.on("--base-path [PATH]", "Specify the base path.") do |path|
|
||||
opts.on("--base-path [PATH]", "Specify the base path for the served pages (default: /) Example: --base-path wiki yields the home page accessible at http://localhost:4567/wiki/.") do |path|
|
||||
wiki_options[:base_path] = path
|
||||
end
|
||||
|
||||
opts.on("--gollum-path [PATH]", "Specify the gollum path.") do |path|
|
||||
opts.on("--gollum-path [PATH]", "Specify the path to the git repository to be served.") do |path|
|
||||
wiki_options[:gollum_path] = path
|
||||
end
|
||||
|
||||
@@ -76,6 +81,14 @@ opts = OptionParser.new do |opts|
|
||||
wiki_options[:ref] = ref
|
||||
end
|
||||
|
||||
opts.on("--bare", "Specify that the repository is bare (only necessary when using the grit adapter).") do
|
||||
wiki_options[:repo_is_bare] = true
|
||||
end
|
||||
|
||||
opts.on("--no-edit", "Restricts editing capability through frontend.") do
|
||||
wiki_options[:allow_editing] = false
|
||||
end
|
||||
|
||||
opts.on("--no-live-preview", "Disables livepreview.") do
|
||||
wiki_options[:live_preview] = false
|
||||
end
|
||||
@@ -89,10 +102,14 @@ opts = OptionParser.new do |opts|
|
||||
wiki_options[:per_page_uploads] = true if mode == :page
|
||||
end
|
||||
|
||||
opts.on("--mathjax", "Enables mathjax.") do
|
||||
opts.on("--mathjax", "Enables mathjax for rendering mathematical equations. Uses the TeX-AMS-MML_HTMLorMML config with the autoload-all extension by default.") do
|
||||
wiki_options[:mathjax] = true
|
||||
end
|
||||
|
||||
opts.on("--mathjax-config [SOURCE]", "Inject custom mathjax config file. Uses mathjax.config.js from root repository by default") do |source|
|
||||
wiki_options[:mathjax_config] = source || 'mathjax.config.js'
|
||||
end
|
||||
|
||||
opts.on("--user-icons [SOURCE]", "Set the history user icons. Valid values: gravatar, identicon, none. Default: none.") do |source|
|
||||
wiki_options[:user_icons] = source
|
||||
end
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=Gollum wiki server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=%i
|
||||
ExecStart=/usr/bin/gollum
|
||||
Restart=on-abort
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
+567
-31
@@ -5,8 +5,8 @@ Gem::Specification.new do |s|
|
||||
s.required_ruby_version = '>= 1.9'
|
||||
|
||||
s.name = 'gollum'
|
||||
s.version = '3.0.0'
|
||||
s.date = '2014-04-05'
|
||||
s.version = '4.0.0'
|
||||
s.date = '2015-04-11'
|
||||
s.rubyforge_project = 'gollum'
|
||||
s.license = 'MIT'
|
||||
|
||||
@@ -24,8 +24,8 @@ Gem::Specification.new do |s|
|
||||
s.rdoc_options = ['--charset=UTF-8']
|
||||
s.extra_rdoc_files = %w[README.md LICENSE]
|
||||
|
||||
s.add_dependency 'gollum-lib', '~> 3.0'
|
||||
s.add_dependency 'github-markdown', '~> 0.6.5'
|
||||
s.add_dependency 'gollum-lib', '~> 4.0', '>= 4.0.1'
|
||||
s.add_dependency 'kramdown', '~> 1.6.0'
|
||||
s.add_dependency 'sinatra', '~> 1.4', '>= 1.4.4'
|
||||
s.add_dependency 'mustache', ['>= 0.99.5', '< 1.0.0']
|
||||
s.add_dependency 'useragent', '~> 0.10.0'
|
||||
@@ -45,6 +45,9 @@ Gem::Specification.new do |s|
|
||||
Rakefile
|
||||
bin/gollum
|
||||
config.rb
|
||||
contrib/openrc/conf.d/gollum
|
||||
contrib/openrc/init.d/gollum
|
||||
contrib/systemd/gollum@.service
|
||||
docs/sanitization.md
|
||||
gollum.gemspec
|
||||
lib/gollum.rb
|
||||
@@ -95,16 +98,21 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/images/lr_24.png
|
||||
lib/gollum/public/gollum/livepreview/images/save_24.png
|
||||
lib/gollum/public/gollum/livepreview/images/savecomment_24.png
|
||||
lib/gollum/public/gollum/livepreview/index.html
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ace.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/anchor.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/anchor_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/autocomplete.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/autocomplete/popup.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/autocomplete/text_completer.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/autocomplete/util.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/background_tokenizer.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/background_tokenizer_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/commands/command_manager.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/commands/command_manager_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/commands/default_commands.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/commands/incremental_search_commands.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/commands/multi_select_commands.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/commands/occur_commands.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/config.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/config_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/css/codefolding-fold-button-states.png
|
||||
@@ -123,28 +131,57 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/editor_highlight_selected_word_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/editor_navigation_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/editor_text_edit_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/beautify.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/beautify/php_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/chromevox.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/elastic_tabstops_lite.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/emmet.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/error_marker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/keybinding_menu.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/language_tools.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/linking.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/menu_tools/add_editor_menu_options.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/menu_tools/element_generator.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/menu_tools/generate_settings_menu.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/menu_tools/get_set_functions.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/menu_tools/overlay_page.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/menu_tools/settings_menu.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/modelist.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/old_ie.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/old_ie_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/searchbox.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/searchbox.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/settings_menu.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/spellcheck.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/split.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/static.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/static_highlight.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/static_highlight_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/statusbar.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/textarea.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/themelist.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/whitespace.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/ext/whitespace_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/incremental_search.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/incremental_search_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/emacs.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/emacs_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/hash_handler.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/keybinding.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/keybinding_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/state_handler.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/textarea.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/textinput.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/commands.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/maps/aliases.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/maps/motions.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/maps/operators.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/maps/util.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/registers.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/layer/cursor.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/layer/font_metrics.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/layer/gutter.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/layer/marker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/layer/text.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/layer/text_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/lib/browser_focus.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/lib/app_config.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/lib/dom.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/lib/es5-shim.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/lib/event.js
|
||||
@@ -157,56 +194,158 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/lib/oop.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/lib/regexp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/lib/useragent.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/line_widgets.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/Readme.md
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/package.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/test_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_asciidoc.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_coffee.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_curly.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_html.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_javascript.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_livescript.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_lucene.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_markdown.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_php.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_ruby.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/text_xml.txt
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_abap.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_abc.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_actionscript.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_ada.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_asciidoc.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_assembly_x86.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_autohotkey.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_batchfile.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_c9search.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_c_cpp.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_cirru.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_clojure.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_cobol.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_coffee.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_coldfusion.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_csharp.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_css.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_curly.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_d.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_dart.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_diff.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_dot.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_eiffel.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_ejs.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_elixir.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_elm.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_erlang.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_forth.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_ftl.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_gcode.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_gherkin.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_gitignore.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_glsl.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_golang.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_groovy.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_haml.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_handlebars.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_haskell.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_haxe.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_html.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_html_ruby.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_ini.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_io.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_jack.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_jade.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_java.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_javascript.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_json.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_jsoniq.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_jsp.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_jsx.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_julia.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_latex.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_less.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_liquid.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_lisp.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_livescript.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_logiql.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_lsl.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_lua.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_luapage.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_lucene.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_markdown.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_mask.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_matlab.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_mel.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_mushcode.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_mysql.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_nix.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_objectivec.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_ocaml.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_pascal.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_perl.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_pgsql.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_php.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_powershell.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_prolog.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_properties.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_protobuf.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_python.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_r.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_rdoc.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_rhtml.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_ruby.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_rust.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_sass.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_scad.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_scala.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_scheme.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_scss.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_sh.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_sjs.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_smarty.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_snippets.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_soy_template.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_space.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_sql.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_stylus.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_svg.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_tcl.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_tex.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_text.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_textile.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_toml.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_twig.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_typescript.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_vala.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_vbscript.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_velocity.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_verilog.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_vhdl.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_xml.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_xquery.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/_test/tokens_yaml.json
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/abap.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/abap_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/abc.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/abc_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/actionscript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/actionscript_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ada.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ada_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/apache_conf.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/apache_conf_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/applescript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/applescript_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/asciidoc.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/asciidoc_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/assembly_x86.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/assembly_x86_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/autohotkey.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/autohotkey_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/batchfile.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/batchfile_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/behaviour_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/css.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/cstyle.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/html.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/xml.js
|
||||
@@ -215,8 +354,12 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/c9search_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/c_cpp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/c_cpp_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/cirru.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/cirru_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/clojure.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/clojure_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/cobol.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/cobol_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coffee.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/coffee-script.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/helpers.js
|
||||
@@ -227,7 +370,6 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/rewriter.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/scope.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coffee_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coffee_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coffee_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coldfusion.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/coldfusion_highlight_rules.js
|
||||
@@ -237,33 +379,63 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/css.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/css/csslint.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/css_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/css_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/css_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/css_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/css_worker_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/curly.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/curly_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/d.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/d_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/dart.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/dart_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/diff.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/diff_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/django.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/doc_comment_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/dockerfile.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/dockerfile_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/dot.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/dot_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/eiffel.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/eiffel_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ejs.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/elixir.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/elixir_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/elm.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/elm_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/erlang.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/erlang_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/asciidoc.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/c9search.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/coffee.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/coffee_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/csharp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/cstyle.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/cstyle_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/diff.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/fold_mode.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/html.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/html_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/ini.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/latex.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/lua.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/markdown.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/mixed.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/pythonic.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/pythonic_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/velocity.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/xml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/folding/xml_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/forth.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/forth_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ftl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ftl_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/gcode.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/gcode_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/gherkin.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/gherkin_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/gitignore.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/gitignore_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/glsl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/glsl_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/golang.js
|
||||
@@ -272,12 +444,26 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/groovy_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/haml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/haml_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/handlebars.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/handlebars_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/haskell.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/haskell_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/haxe.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/haxe_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html/saxparser.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html_completions.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html_ruby.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html_ruby_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/html_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ini.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ini_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/io.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/io_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jack.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jack_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jade.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jade_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/java.js
|
||||
@@ -285,54 +471,89 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/javascript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/javascript/jshint.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_worker_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/js_regex_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/json.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/json/json_parse.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/json_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/json_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/json_worker_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jsoniq.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jsp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jsp_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jsx.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/jsx_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/julia.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/julia_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/latex.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/latex_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/less.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/less_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/liquid.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/liquid_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/liquid_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lisp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lisp_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/livescript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/logiql.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/logiql_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/logiql_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lsl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lsl_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lua.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lua/luaparse.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lua_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lua_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/luapage.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/luapage_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lucene.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lucene_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/lucene_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/makefile.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/makefile_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/markdown.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/markdown_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/markdown_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/mask.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/mask_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/matching_brace_outdent.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/matching_parens_outdent.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/matlab.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/matlab_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/mel.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/mel_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/mushcode.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/mushcode_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/mysql.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/mysql_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/nix.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/nix_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/objectivec.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/objectivec_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ocaml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ocaml_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/pascal.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/pascal_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/perl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/perl_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/pgsql.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/pgsql_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/php.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/php/php.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/php_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/php_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/php_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/plain_text.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/plain_text_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/powershell.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/powershell_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/praat.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/praat_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/prolog.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/prolog_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/properties.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/properties_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/protobuf.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/protobuf_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/python.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/python_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/python_test.js
|
||||
@@ -344,15 +565,30 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/rhtml_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ruby.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ruby_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ruby_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/ruby_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/rust.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/rust_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/sass.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/sass_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/scad.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/scad_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/scala.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/scala_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/scheme.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/scheme_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/scss.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/scss_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/sh.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/sh_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/sjs.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/sjs_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/smarty.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/smarty_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/snippets.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/soy_template.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/soy_template_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/space.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/space_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/sql.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/sql_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/stylus.js
|
||||
@@ -368,32 +604,50 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/text_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/textile.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/textile_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/toml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/toml_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/twig.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/twig_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/typescript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/typescript_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/vala.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/vala_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/vbscript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/vbscript_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/velocity.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/velocity_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/verilog.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/verilog_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/vhdl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/vhdl_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml/dom-parser.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml/dom.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml/sax.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml_highlight_rules_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml_util.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xml_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/JSONParseTreeHandler.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/Readme.md
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/XQueryParser.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/visitors/SyntaxHighlighter.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/jsoniq_lexer.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/xqlint.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/xquery_lexer.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/xquery_worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/yaml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mode/yaml_highlight_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/model/editor.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/default_gutter_handler.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/default_handlers.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/dragdrop.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/dragdrop_handler.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/fold_handler.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/mouse_event.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/mouse_handler.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/mouse_handler_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/mouse/multi_select_handler.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/multi_select.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/multi_select_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/occur.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/occur_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/placeholder.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/placeholder_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/range.js
|
||||
@@ -402,12 +656,282 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/range_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/renderloop.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/requirejs/text.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/requirejs/text_build.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/scrollbar.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/search.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/search_highlight.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/search_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/selection.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/selection_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/_.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/_all_modes.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/_all_modes.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/abap.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/abap.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/abc.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/abc.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/actionscript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/actionscript.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ada.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ada.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/all_modes.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/all_modes.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/apache.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/apache_conf.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/apache_conf.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/applescript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/applescript.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/asciidoc.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/asciidoc.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/assembly_x86.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/assembly_x86.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/autohotkey.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/autohotkey.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/autoit.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/batchfile.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/batchfile.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/c.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/c9search.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/c9search.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/c_cpp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/c_cpp.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/chef.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/cirru.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/cirru.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/clojure.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/clojure.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/cmake.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/cobol.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/cobol.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/coffee.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/coffee.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/coldfusion.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/coldfusion.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/cs.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/csharp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/csharp.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/css.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/css.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/curly.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/curly.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/d.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/d.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/dart.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/dart.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/diff.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/diff.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/django.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/django.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/dockerfile.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/dockerfile.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/dot.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/dot.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/dummy.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/dummy_syntax.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/eiffel.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/eiffel.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ejs.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ejs.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/elixir.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/elixir.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/elm.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/elm.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/erlang.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/erlang.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/eruby.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/falcon.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/forth.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/forth.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ftl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ftl.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/gcode.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/gcode.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/gherkin.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/gherkin.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/gitignore.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/gitignore.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/glsl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/glsl.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/go.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/golang.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/golang.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/groovy.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/groovy.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/haml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/haml.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/handlebars.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/handlebars.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/haskell.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/haskell.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/haxe.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/haxe.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/html.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/html.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/html_ruby.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/html_ruby.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/htmldjango.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/htmltornado.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ini.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ini.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/io.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/io.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jack.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jack.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jade.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jade.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/java.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/java.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/javascript-jquery.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/javascript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/javascript.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/json.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/json.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jsoniq.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jsoniq.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jsp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jsp.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jsx.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/jsx.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/julia.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/julia.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/latex.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/latex.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ledger.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/less.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/less.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/liquid.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/liquid.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/lisp.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/lisp.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/livescript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/livescript.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/logiql.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/logiql.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/lsl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/lsl.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/lua.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/lua.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/luapage.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/luapage.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/lucene.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/lucene.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/makefile.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/makefile.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mako.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/markdown.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/markdown.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/matlab.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/matlab.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mel.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mel.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mushcode.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mushcode.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mushcode_high_rules.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mushcode_high_rules.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mysql.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/mysql.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/nix.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/nix.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/objc.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/objectivec.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/objectivec.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ocaml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ocaml.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/pascal.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/pascal.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/perl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/perl.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/pgsql.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/pgsql.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/php.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/php.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/plain_text.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/plain_text.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/powershell.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/powershell.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/praat.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/praat.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/prolog.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/prolog.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/properties.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/properties.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/protobuf.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/protobuf.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/python.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/python.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/r.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/r.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/rdoc.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/rdoc.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/rhtml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/rhtml.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/rst.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ruby.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/ruby.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/rust.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/rust.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/sass.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/sass.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/scad.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/scad.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/scala.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/scala.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/scheme.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/scheme.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/scss.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/scss.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/sh.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/sh.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/sjs.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/sjs.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/smarty.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/smarty.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/snippets.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/snippets.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/soy_template.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/soy_template.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/space.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/space.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/sql.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/sql.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/stylus.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/stylus.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/svg.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/svg.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/tcl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/tcl.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/tex.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/tex.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/text.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/text.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/textile.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/textile.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/tmsnippet.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/toml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/toml.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/twig.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/twig.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/typescript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/typescript.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/vala.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/vala.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/vbscript.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/vbscript.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/velocity.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/velocity.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/verilog.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/verilog.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/vhdl.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/vhdl.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/xml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/xml.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/xquery.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/xquery.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/xslt.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/yaml.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets/yaml.snippets
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/snippets_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/split.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/test/all.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/test/all_browser.js
|
||||
@@ -423,6 +947,8 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/test/tests.html
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/ambiance.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/ambiance.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/chaos.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/chaos.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/chrome.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/chrome.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/clouds.css
|
||||
@@ -443,8 +969,12 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/github.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/idle_fingers.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/idle_fingers.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/katzenmilch.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/katzenmilch.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/kr_theme.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/kr_theme.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/kuroir.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/kuroir.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/merbivore.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/merbivore.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/merbivore_soft.css
|
||||
@@ -459,6 +989,8 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/solarized_dark.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/solarized_light.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/solarized_light.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/terminal.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/terminal.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/textmate.css
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/textmate.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow.css
|
||||
@@ -481,6 +1013,8 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/token_iterator_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/tokenizer.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/tokenizer_dev.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/tokenizer_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/tooltip.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/undomanager.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/unicode.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/virtual_renderer.js
|
||||
@@ -488,7 +1022,7 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/worker/mirror.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/worker/worker.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/worker/worker_client.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/worker/worker_sourcemint.js
|
||||
lib/gollum/public/gollum/livepreview/js/ace/lib/ace/worker/worker_test.js
|
||||
lib/gollum/public/gollum/livepreview/js/jquery.ba-throttle-debounce.min.js
|
||||
lib/gollum/public/gollum/livepreview/js/livepreview.js
|
||||
lib/gollum/public/gollum/livepreview/js/md_sundown.js
|
||||
@@ -517,7 +1051,9 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/templates/history_authors/gravatar.mustache
|
||||
lib/gollum/templates/history_authors/identicon.mustache
|
||||
lib/gollum/templates/history_authors/none.mustache
|
||||
lib/gollum/templates/latest_changes.mustache
|
||||
lib/gollum/templates/layout.mustache
|
||||
lib/gollum/templates/livepreview.mustache
|
||||
lib/gollum/templates/page.mustache
|
||||
lib/gollum/templates/pages.mustache
|
||||
lib/gollum/templates/search.mustache
|
||||
@@ -531,15 +1067,15 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/views/file_view.rb
|
||||
lib/gollum/views/has_page.rb
|
||||
lib/gollum/views/history.rb
|
||||
lib/gollum/views/latest_changes.rb
|
||||
lib/gollum/views/layout.rb
|
||||
lib/gollum/views/livepreview.rb
|
||||
lib/gollum/views/page.rb
|
||||
lib/gollum/views/pages.rb
|
||||
lib/gollum/views/search.rb
|
||||
licenses/css_tree_menu_thecssninja/license.txt
|
||||
licenses/licenses.txt
|
||||
licenses/unity_asset_pool/COPYRIGHT
|
||||
openrc/conf.d/gollum
|
||||
openrc/init.d/gollum
|
||||
]
|
||||
# = MANIFEST =
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ require File.expand_path('../gollum/uri_encode_component', __FILE__)
|
||||
$KCODE = 'U' if RUBY_VERSION[0, 3] == '1.8'
|
||||
|
||||
module Gollum
|
||||
VERSION = '3.0.0'
|
||||
VERSION = '4.0.0'
|
||||
|
||||
def self.assets_path
|
||||
::File.expand_path('gollum/public', ::File.dirname(__FILE__))
|
||||
|
||||
+61
-14
@@ -20,6 +20,13 @@ Gollum::set_git_max_filesize(190 * 10**6)
|
||||
# Fix to_url
|
||||
class String
|
||||
alias :upstream_to_url :to_url
|
||||
|
||||
if defined?(Gollum::GIT_ADAPTER) && Gollum::GIT_ADAPTER != 'grit'
|
||||
def to_ascii
|
||||
self # Do not transliterate utf-8 url's unless using Grit
|
||||
end
|
||||
end
|
||||
|
||||
# _Header => header which causes errors
|
||||
def to_url
|
||||
return nil if self.nil?
|
||||
@@ -86,11 +93,16 @@ module Precious
|
||||
end
|
||||
|
||||
before do
|
||||
settings.wiki_options[:allow_editing] = settings.wiki_options.fetch(:allow_editing, true)
|
||||
@allow_editing = settings.wiki_options[:allow_editing]
|
||||
forbid unless @allow_editing || request.request_method == "GET"
|
||||
Precious::App.set(:mustache, {:templates => settings.wiki_options[:template_dir]}) if settings.wiki_options[:template_dir]
|
||||
@base_url = url('/', false).chomp('/')
|
||||
# above will detect base_path when it's used with map in a config.ru
|
||||
settings.wiki_options.merge!({ :base_path => @base_url })
|
||||
@css = settings.wiki_options[:css]
|
||||
@js = settings.wiki_options[:js]
|
||||
@mathjax_config = settings.wiki_options[:mathjax_config]
|
||||
end
|
||||
|
||||
get '/' do
|
||||
@@ -105,7 +117,6 @@ module Precious
|
||||
# name, path, version
|
||||
def wiki_page(name, path = nil, version = nil, exact = true)
|
||||
wiki = wiki_new
|
||||
|
||||
path = name if path.nil?
|
||||
name = extract_name(name) || wiki.index_page
|
||||
path = extract_path(path)
|
||||
@@ -126,14 +137,17 @@ module Precious
|
||||
end
|
||||
|
||||
get '/edit/*' do
|
||||
forbid unless @allow_editing
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
@name = wikip.name
|
||||
@path = wikip.path
|
||||
@upload_dest = find_upload_dest(@path)
|
||||
|
||||
wiki = wikip.wiki
|
||||
@allow_uploads = wiki.allow_uploads
|
||||
if page = wikip.page
|
||||
if wiki.live_preview && page.format.to_s.include?('markdown') && supported_useragent?(request.user_agent)
|
||||
live_preview_url = '/livepreview/index.html?page=' + encodeURIComponent(@name)
|
||||
live_preview_url = '/livepreview/?page=' + encodeURIComponent(@name)
|
||||
if @path
|
||||
live_preview_url << '&path=' + encodeURIComponent(@path)
|
||||
end
|
||||
@@ -163,7 +177,8 @@ module Precious
|
||||
tempfile = params[:file][:tempfile]
|
||||
end
|
||||
|
||||
dir = wiki.per_page_uploads ? params[:upload_dest] : 'uploads'
|
||||
# Remove page file dir prefix from upload path if necessary -- committer handles this itself
|
||||
dir = wiki.per_page_uploads ? params[:upload_dest].match(/^(#{wiki.page_file_dir}\/+)?(.*)/)[2] : 'uploads'
|
||||
ext = ::File.extname(fullname)
|
||||
format = ext.split('.').last || 'txt'
|
||||
filename = ::File.basename(fullname, ext)
|
||||
@@ -251,21 +266,27 @@ module Precious
|
||||
end
|
||||
|
||||
get '/delete/*' do
|
||||
forbid unless @allow_editing
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
name = wikip.name
|
||||
wiki = wikip.wiki
|
||||
page = wikip.page
|
||||
unless page.nil?
|
||||
wiki.delete_page(page, { :message => "Destroyed #{name} (#{page.format})" })
|
||||
commit = commit_message
|
||||
commit[:message] = "Destroyed #{name} (#{page.format})"
|
||||
wiki.delete_page(page, commit)
|
||||
end
|
||||
|
||||
redirect to('/')
|
||||
end
|
||||
|
||||
get '/create/*' do
|
||||
forbid unless @allow_editing
|
||||
wikip = wiki_page(params[:splat].first.gsub('+', '-'))
|
||||
@name = wikip.name.to_url
|
||||
@path = wikip.path
|
||||
@allow_uploads = wikip.wiki.allow_uploads
|
||||
@upload_dest = find_upload_dest(@path)
|
||||
|
||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
unless page_dir.empty?
|
||||
@@ -297,7 +318,7 @@ module Precious
|
||||
wiki.write_page(name, format, params[:content], commit_message, path)
|
||||
|
||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
redirect to("/#{clean_url(::File.join(page_dir, path, name))}")
|
||||
redirect to("/#{clean_url(::File.join(page_dir, path, encodeURIComponent(name)))}")
|
||||
rescue Gollum::DuplicatePageError => e
|
||||
@message = "Duplicate page: #{e.message}"
|
||||
mustache :error
|
||||
@@ -340,6 +361,12 @@ module Precious
|
||||
mustache :page
|
||||
end
|
||||
|
||||
get '/livepreview/' do
|
||||
wiki = wiki_new
|
||||
@mathjax = wiki.mathjax
|
||||
mustache :livepreview, { :layout => false }
|
||||
end
|
||||
|
||||
get '/history/*' do
|
||||
@page = wiki_page(params[:splat].first).page
|
||||
@page_num = [params[:page].to_i, 1].max
|
||||
@@ -351,8 +378,15 @@ module Precious
|
||||
end
|
||||
end
|
||||
|
||||
get '/latest_changes' do
|
||||
@wiki = wiki_new
|
||||
max_count = settings.wiki_options.fetch(:latest_changes_count, 10)
|
||||
@versions = @wiki.latest_changes({:max_count => max_count})
|
||||
mustache :latest_changes
|
||||
end
|
||||
|
||||
post '/compare/*' do
|
||||
@file = params[:splat].first
|
||||
@file = encodeURIComponent(params[:splat].first)
|
||||
@versions = params[:versions] || []
|
||||
if @versions.size < 2
|
||||
redirect to("/history/#{@file}")
|
||||
@@ -396,6 +430,8 @@ module Precious
|
||||
@content = page.formatted_data
|
||||
@version = version
|
||||
mustache :page
|
||||
elsif file = wikip.wiki.file("#{file_path}", version, true)
|
||||
show_file(file)
|
||||
else
|
||||
halt 404
|
||||
end
|
||||
@@ -421,6 +457,7 @@ module Precious
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
|
||||
@results = wiki.pages
|
||||
@results += wiki.files if settings.wiki_options[:show_all]
|
||||
@results = @results.sort_by { |p| p.name.downcase } # Sort Results alphabetically, fixes 922
|
||||
@ref = wiki.ref
|
||||
mustache :pages
|
||||
end
|
||||
@@ -453,10 +490,7 @@ module Precious
|
||||
@page = page
|
||||
@name = name
|
||||
@content = page.formatted_data
|
||||
@upload_dest = settings.wiki_options[:allow_uploads] ?
|
||||
(settings.wiki_options[:per_page_uploads] ?
|
||||
"#{path}/#{@name}".sub(/^\/\//, '') : 'uploads'
|
||||
) : ''
|
||||
@upload_dest = find_upload_dest(path)
|
||||
|
||||
# Extensions and layout data
|
||||
@editable = true
|
||||
@@ -469,16 +503,22 @@ module Precious
|
||||
|
||||
mustache :page
|
||||
elsif file = wiki.file(fullpath, wiki.ref, true)
|
||||
show_file(file)
|
||||
else
|
||||
not_found unless @allow_editing
|
||||
page_path = [path, name].compact.join('/')
|
||||
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
||||
end
|
||||
end
|
||||
|
||||
def show_file(file)
|
||||
return unless file
|
||||
if file.on_disk?
|
||||
send_file file.on_disk_path, :disposition => 'inline'
|
||||
else
|
||||
content_type file.mime_type
|
||||
file.raw_data
|
||||
end
|
||||
else
|
||||
page_path = [path, name].compact.join('/')
|
||||
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
||||
end
|
||||
end
|
||||
|
||||
def update_wiki_page(wiki, page, content, commit, name = nil, format = nil)
|
||||
@@ -505,5 +545,12 @@ module Precious
|
||||
commit_message.merge! author_parameters unless author_parameters.nil?
|
||||
commit_message
|
||||
end
|
||||
|
||||
def find_upload_dest(path)
|
||||
settings.wiki_options[:allow_uploads] ?
|
||||
(settings.wiki_options[:per_page_uploads] ?
|
||||
"#{path}/#{@name}".sub(/^\/\//, '') : 'uploads'
|
||||
) : ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,5 +39,17 @@ module Precious
|
||||
url.gsub('%2F', '/').gsub(/^\/+/, '').gsub('//', '/')
|
||||
end
|
||||
|
||||
def forbid(msg = "Forbidden. This wiki is set to no-edit mode.")
|
||||
@message = msg
|
||||
status 403
|
||||
halt mustache :error
|
||||
end
|
||||
|
||||
def not_found(msg = nil)
|
||||
@message = msg || "The requested page does not exist."
|
||||
status 404
|
||||
return mustache :error
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
display: block;
|
||||
overflow: visible;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog.active {
|
||||
@@ -13,24 +16,117 @@
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-inner {
|
||||
margin: 0 0 0 -225px;
|
||||
position: relative;
|
||||
width: 450px;
|
||||
margin: 0px;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-bg {
|
||||
background-color: #fff;
|
||||
padding: 1em;
|
||||
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media all and (min-width: 480px) {
|
||||
#gollum-dialog-dialog {
|
||||
display: block;
|
||||
overflow: visible;
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999999;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-inner {
|
||||
margin: auto;
|
||||
position: fixed;
|
||||
|
||||
width: auto;
|
||||
height: auto;
|
||||
|
||||
min-width: 280px;
|
||||
min-height: 380px;
|
||||
|
||||
max-width: 450px;
|
||||
max-height: 450px;
|
||||
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
|
||||
border: 7px solid #999;
|
||||
border: 7px solid rgba(0, 0, 0, 0.3);
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-bg {
|
||||
#gollum-dialog-dialog-bg {
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
padding: 1em;
|
||||
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#ffffff));
|
||||
background: -moz-linear-gradient(top, #f7f7f7, #ffffff);
|
||||
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#gollum-dialog-dialog {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-inner {
|
||||
margin: 0 0 0 -225px;
|
||||
position: relative;
|
||||
|
||||
width: 450px;
|
||||
height: auto;
|
||||
|
||||
top: auto;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
|
||||
border: 7px solid #999;
|
||||
border: 7px solid rgba(0, 0, 0, 0.3);
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-bg {
|
||||
height: auto;
|
||||
|
||||
box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box;
|
||||
}
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-inner h4 {
|
||||
@@ -52,10 +148,16 @@
|
||||
display: block;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body fieldset:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body fieldset .field {
|
||||
margin: 0 0 1.5em 0;
|
||||
padding: 0;
|
||||
|
||||
@@ -19,15 +19,15 @@ a {
|
||||
}
|
||||
|
||||
#gollum-editor {
|
||||
border: 1px solid #e4e4e4;
|
||||
background: #f9f9f9;
|
||||
margin: 1em 0 5em;
|
||||
overflow: hidden;
|
||||
padding: 1em 1em 0.4em;
|
||||
margin: 0 0 5em;
|
||||
padding: 0em 1em 0.4em;
|
||||
}
|
||||
|
||||
border-radius: 1em;
|
||||
-moz-border-radius: 1em;
|
||||
-webkit-border-radius: 1em;
|
||||
#gollum-editor:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.ff #gollum-editor,
|
||||
@@ -35,6 +35,18 @@ a {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#gollum-editor {
|
||||
border: 1px solid #e4e4e4;
|
||||
background: #f9f9f9;
|
||||
margin: 1em 0 5em;
|
||||
|
||||
border-radius: 1em;
|
||||
-moz-border-radius: 1em;
|
||||
-webkit-border-radius: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
#gollum-editor form fieldset {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
@@ -45,7 +57,13 @@ a {
|
||||
#gollum-editor .singleline {
|
||||
display: block;
|
||||
margin: 0 0 0.7em 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#gollum-editor .singleline:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#gollum-editor .singleline input {
|
||||
@@ -94,7 +112,6 @@ a {
|
||||
/* @control function-bar */
|
||||
#gollum-editor #gollum-editor-function-bar {
|
||||
border-bottom: 1px solid #ddd;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -109,9 +126,21 @@ a {
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar.active #gollum-editor-function-buttons {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#gollum-editor #gollum-editor-function-bar {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar.active #gollum-editor-function-buttons {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0 0 1.1em 0;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar a.function-button {
|
||||
@@ -120,12 +149,12 @@ a {
|
||||
color: #333;
|
||||
display: block;
|
||||
float: left;
|
||||
height: 25px;
|
||||
height: 32px;
|
||||
overflow: hidden;
|
||||
margin: 0.2em 0.5em 0 0;
|
||||
margin: 1px 1px 0 0;
|
||||
/* text-indent: -5000px; */
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
width: 25px;
|
||||
width: 32px;
|
||||
|
||||
border-radius: 0.3em;
|
||||
-moz-border-radius: 0.3em;
|
||||
@@ -150,41 +179,84 @@ a {
|
||||
background-image: url(../images/icon-sprite.png);
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
height: 25px;
|
||||
height: 32px;
|
||||
overflow: hidden;
|
||||
text-indent: -5000px;
|
||||
width: 25px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
a#function-bold span { background-position: 0 0; }
|
||||
a#function-italic span { background-position: -27px 0; }
|
||||
a#function-underline span { background-position: -54px 0; }
|
||||
a#function-code span { background-position: -82px 0; }
|
||||
a#function-ul span { background-position: -109px 0; }
|
||||
a#function-ol span { background-position: -136px 0; }
|
||||
a#function-blockquote span { background-position: -163px 0; }
|
||||
a#function-hr span { background-position: -190px 0; }
|
||||
a#function-h1 span { background-position: -217px 0; }
|
||||
a#function-h2 span { background-position: -244px 0; }
|
||||
a#function-h3 span { background-position: -271px 0; }
|
||||
a#function-link span { background-position: -298px 0; }
|
||||
a#function-image span { background-position: -324px 0; }
|
||||
a#function-help span { background-position: -405px 0; }
|
||||
a#function-bold span { background-position: 3px 3px; }
|
||||
a#function-italic span { background-position: -24px 3px; }
|
||||
a#function-underline span { background-position: -51px 3px; }
|
||||
a#function-code span { background-position: -79px 3px; }
|
||||
a#function-ul span { background-position: -106px 3px; }
|
||||
a#function-ol span { background-position: -133px 3px; }
|
||||
a#function-blockquote span { background-position: -160px 3px; }
|
||||
a#function-hr span { background-position: -187px 3px; }
|
||||
a#function-h1 span { background-position: -214px 3px; }
|
||||
a#function-h2 span { background-position: -241px 3px; }
|
||||
a#function-h3 span { background-position: -268px 3px; }
|
||||
a#function-link span { background-position: -295px 3px; }
|
||||
a#function-image span { background-position: -321px 3px; }
|
||||
a#function-help span { background-position: -402px 3px; }
|
||||
|
||||
a#function-bold:hover span { background-position: 0 -28px; }
|
||||
a#function-italic:hover span { background-position: -27px -28px; }
|
||||
a#function-underline:hover span { background-position: -54px -28px; }
|
||||
a#function-code:hover span { background-position: -82px -28px; }
|
||||
a#function-ul:hover span { background-position: -109px -28px; }
|
||||
a#function-ol:hover span { background-position: -136px -28px; }
|
||||
a#function-blockquote:hover span { background-position: -163px -28px; }
|
||||
a#function-hr:hover span { background-position: -190px -28px; }
|
||||
a#function-h1:hover span { background-position: -217px -28px; }
|
||||
a#function-h2:hover span { background-position: -244px -28px; }
|
||||
a#function-h3:hover span { background-position: -271px -28px; }
|
||||
a#function-link:hover span { background-position: -298px -28px; }
|
||||
a#function-image:hover span { background-position: -324px -28px; }
|
||||
a#function-help:hover span { background-position: -405px -28px; }
|
||||
a#function-bold:hover span { background-position: 3px -25px; }
|
||||
a#function-italic:hover span { background-position: -24px -25px; }
|
||||
a#function-underline:hover span { background-position: -51px -25px; }
|
||||
a#function-code:hover span { background-position: -79px -25px; }
|
||||
a#function-ul:hover span { background-position: -106px -25px; }
|
||||
a#function-ol:hover span { background-position: -133px -25px; }
|
||||
a#function-blockquote:hover span { background-position: -160px -25px; }
|
||||
a#function-hr:hover span { background-position: -187px -25px; }
|
||||
a#function-h1:hover span { background-position: -214px -25px; }
|
||||
a#function-h2:hover span { background-position: -241px -25px; }
|
||||
a#function-h3:hover span { background-position: -268px -25px; }
|
||||
a#function-link:hover span { background-position: -295px -25px; }
|
||||
a#function-image:hover span { background-position: -321px -25px; }
|
||||
a#function-help:hover span { background-position: -402px -25px; }
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#gollum-editor #gollum-editor-function-bar a.function-button {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
margin: 0.2em 0.5em 0 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar a span {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
a#function-bold span { background-position: 0 0; }
|
||||
a#function-italic span { background-position: -27px 0; }
|
||||
a#function-underline span { background-position: -54px 0; }
|
||||
a#function-code span { background-position: -82px 0; }
|
||||
a#function-ul span { background-position: -109px 0; }
|
||||
a#function-ol span { background-position: -136px 0; }
|
||||
a#function-blockquote span { background-position: -163px 0; }
|
||||
a#function-hr span { background-position: -190px 0; }
|
||||
a#function-h1 span { background-position: -217px 0; }
|
||||
a#function-h2 span { background-position: -244px 0; }
|
||||
a#function-h3 span { background-position: -271px 0; }
|
||||
a#function-link span { background-position: -298px 0; }
|
||||
a#function-image span { background-position: -324px 0; }
|
||||
a#function-help span { background-position: -405px 0; }
|
||||
|
||||
a#function-bold:hover span { background-position: 0 -28px; }
|
||||
a#function-italic:hover span { background-position: -27px -28px; }
|
||||
a#function-underline:hover span { background-position: -54px -28px; }
|
||||
a#function-code:hover span { background-position: -82px -28px; }
|
||||
a#function-ul:hover span { background-position: -109px -28px; }
|
||||
a#function-ol:hover span { background-position: -136px -28px; }
|
||||
a#function-blockquote:hover span { background-position: -163px -28px; }
|
||||
a#function-hr:hover span { background-position: -190px -28px; }
|
||||
a#function-h1:hover span { background-position: -217px -28px; }
|
||||
a#function-h2:hover span { background-position: -244px -28px; }
|
||||
a#function-h3:hover span { background-position: -271px -28px; }
|
||||
a#function-link:hover span { background-position: -298px -28px; }
|
||||
a#function-image:hover span { background-position: -324px -28px; }
|
||||
a#function-help:hover span { background-position: -405px -28px; }
|
||||
}
|
||||
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar a.disabled {
|
||||
@@ -192,14 +264,19 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar span.function-divider {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 0.5em;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar #gollum-editor-format-selector {
|
||||
overflow: hidden;
|
||||
padding: .2em 0 .5em 0;
|
||||
padding: 0.2em 0 0.5em 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar #gollum-editor-format-selector:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
@@ -208,13 +285,12 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
|
||||
float: right;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
padding: 0.3em 0.4em;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
@@ -224,11 +300,11 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector label {
|
||||
color: #999;
|
||||
float: right;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
padding: .3em 0.5em 0 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
@@ -236,6 +312,56 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
content: ':';
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#gollum-editor #gollum-editor-function-bar span.function-divider {
|
||||
display: block;
|
||||
width: 0.5em;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar span.function-divider {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector {
|
||||
clear: none;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector select {
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector label {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* @section uploads */
|
||||
|
||||
#gollum-editor-body.dragging {
|
||||
box-shadow: 0 0 10px #AAE000;
|
||||
}
|
||||
|
||||
#gollum-editor-body.uploading {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#gollum-editor-body + div {
|
||||
display: none;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
#gollum-editor-body + div > i {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#gollum-editor-body.uploading + div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* @section form-fields */
|
||||
|
||||
@@ -245,12 +371,18 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
font-size: 1em;
|
||||
font-family: Consolas, "Liberation Mono", Courier, monospace;
|
||||
line-height: 1.4em;
|
||||
margin: 1em 0 0.4em;
|
||||
margin: 0 0 0.4em;
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
height: 20em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#gollum-editor textarea {
|
||||
margin: 1em 0 0.4em;
|
||||
}
|
||||
}
|
||||
|
||||
#gollum-editor input#gollum-editor-submit {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #d4d4d4;
|
||||
@@ -445,6 +577,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
|
||||
/* @section help */
|
||||
#gollum-editor-help {
|
||||
clear: both;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
@@ -455,13 +588,13 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
#gollum-editor-help-parent,
|
||||
#gollum-editor-help-list {
|
||||
display: block;
|
||||
float: left;
|
||||
height: 17em;
|
||||
list-style-type: none;
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
padding: 1em 0;
|
||||
width: 18%;
|
||||
float: left;
|
||||
width: 50%;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent {
|
||||
@@ -491,6 +624,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
width: auto;
|
||||
padding: 0.2em 1em;
|
||||
text-shadow: 0 -1px 0 #fff;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent li a:hover,
|
||||
@@ -518,6 +652,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
overflow: auto;
|
||||
height: 17em;
|
||||
padding: 1em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#gollum-editor-help-content {
|
||||
@@ -532,6 +667,29 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#gollum-editor-help {
|
||||
clear: none;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent,
|
||||
#gollum-editor-help-list {
|
||||
height: 17em;
|
||||
width: 18%;
|
||||
overflow: auto;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent li a,
|
||||
#gollum-editor-help-list li a {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#gollum-editor-help-wrapper {
|
||||
clear: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* IE */
|
||||
.ie #gollum-editor .singleline input {
|
||||
padding-top: 0.25em;
|
||||
|
||||
@@ -21,9 +21,15 @@ body, html {
|
||||
#wiki-wrapper {
|
||||
margin: 0 auto;
|
||||
overflow: visible;
|
||||
width: 920px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#wiki-wrapper {
|
||||
max-width: 920px;
|
||||
padding-left:20px;
|
||||
padding-right:20px;
|
||||
}
|
||||
}
|
||||
|
||||
a:link {
|
||||
@@ -39,22 +45,41 @@ a:hover, a:visited {
|
||||
|
||||
/* @section head */
|
||||
#head {
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 4em 0 1.5em;
|
||||
padding-bottom: 0.3em;
|
||||
margin: 1em 0 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#head h1 {
|
||||
font-size: 2.5em;
|
||||
font-size: 1.5em;
|
||||
float: left;
|
||||
line-height: normal;
|
||||
margin: 0;
|
||||
padding: 2px 0 0 0;
|
||||
padding: 0 0 0 0.667em;
|
||||
}
|
||||
|
||||
#head ul.actions {
|
||||
clear: both;
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#head {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-bottom: 0.3em;
|
||||
margin: 4em 0 1.5em;
|
||||
}
|
||||
|
||||
#head h1 {
|
||||
font-size: 2.5em;
|
||||
padding: 2px 0 0 0;
|
||||
}
|
||||
|
||||
#head ul.actions {
|
||||
clear: none;
|
||||
float: right;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* @section content */
|
||||
@@ -89,6 +114,12 @@ a:hover, a:visited {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#wiki-body table {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.has-sidebar #wiki-body {
|
||||
width: 68%;
|
||||
}
|
||||
@@ -244,6 +275,16 @@ a:hover, a:visited {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#footer .actions {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#footer .actions {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* @section history */
|
||||
.history h1 {
|
||||
@@ -257,7 +298,7 @@ a:hover, a:visited {
|
||||
}
|
||||
|
||||
#wiki-history {
|
||||
margin-top: 2em;
|
||||
margin: 2em 1em 0 1em;
|
||||
}
|
||||
|
||||
#wiki-history fieldset {
|
||||
@@ -283,7 +324,8 @@ a:hover, a:visited {
|
||||
}
|
||||
|
||||
#wiki-history table tr td {
|
||||
border: 1px solid #c0dce9;
|
||||
border-top: 1px solid #c0dce9;
|
||||
border-bottom: 1px solid #c0dce9;
|
||||
font-size: 1em;
|
||||
line-height: 1.6em;
|
||||
margin: 0;
|
||||
@@ -291,8 +333,8 @@ a:hover, a:visited {
|
||||
}
|
||||
|
||||
#wiki-history table tr td.checkbox {
|
||||
width: 4em;
|
||||
padding: 0.3em;
|
||||
width: auto;
|
||||
padding: 0 0.2em 0 0;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.checkbox input {
|
||||
@@ -364,6 +406,25 @@ a:hover, a:visited {
|
||||
margin: 0 0.6em 0 0;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#wiki-history {
|
||||
margin: 2em 0 0 0;
|
||||
}
|
||||
|
||||
#wiki-history table tr td {
|
||||
border: 1px solid #c0dce9;
|
||||
font-size: 1em;
|
||||
line-height: 1.6em;
|
||||
margin: 0;
|
||||
padding: 0.3em 0.7em;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.checkbox {
|
||||
width: 4em;
|
||||
padding: 0.3em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* @section edit */
|
||||
.edit h1 {
|
||||
@@ -378,6 +439,7 @@ a:hover, a:visited {
|
||||
|
||||
|
||||
/* @section search */
|
||||
|
||||
.results h1 {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
@@ -390,6 +452,8 @@ a:hover, a:visited {
|
||||
|
||||
.results #results {
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 2em;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
@@ -400,12 +464,33 @@ a:hover, a:visited {
|
||||
}
|
||||
|
||||
.results #results ul li {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
list-style-position: outside;
|
||||
list-style: none;
|
||||
padding: 0.2em 0;
|
||||
}
|
||||
|
||||
.results #results ul li a {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
@media all and (min-width: 640px) {
|
||||
.results #results ul li {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
.results #results {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.results #results ul li {
|
||||
list-style: disc;
|
||||
list-style-position: outside;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
}
|
||||
|
||||
.results #results ul li span.count {
|
||||
color: #999;
|
||||
}
|
||||
@@ -522,8 +607,8 @@ ul.actions {
|
||||
ul.actions li {
|
||||
float: left;
|
||||
font-size: 0.9em;
|
||||
margin-left: 0.6em;
|
||||
margin-bottom: 0.6em;
|
||||
margin-left: 1px;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.minibutton a {
|
||||
@@ -533,7 +618,7 @@ ul.actions {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0.4em 1em;
|
||||
padding: 0.6em 1em;
|
||||
height: 1.4em;
|
||||
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
@@ -547,6 +632,18 @@ ul.actions {
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
ul.actions li {
|
||||
margin-left: 0.6em;
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
.minibutton a {
|
||||
padding: 0.4em 1em;
|
||||
height: 1.4em;
|
||||
}
|
||||
}
|
||||
|
||||
#search-submit {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #d4d4d4;
|
||||
@@ -627,7 +724,7 @@ ul.actions {
|
||||
/* @control searchbar */
|
||||
#head #searchbar {
|
||||
float: right;
|
||||
padding: 0;
|
||||
padding: 2px 0 0 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -684,7 +781,7 @@ ul.actions {
|
||||
height: inherit;
|
||||
overflow: hidden;
|
||||
text-indent: -5000px;
|
||||
width: 28px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.ff #head #searchbar #searchbar-fauxtext #search-submit span,
|
||||
@@ -697,11 +794,31 @@ ul.actions {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#head #searchbar {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit span {
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit:hover span {
|
||||
background-position: -431px -28px;
|
||||
}
|
||||
}
|
||||
|
||||
/* @section pages */
|
||||
|
||||
#pages {
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 20px;
|
||||
margin: 0 1em 20px 1em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
#pages {
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
#pages ul {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
/* IE7-specific styles */
|
||||
|
||||
.ie #wiki-wrapper {
|
||||
width: 920px;
|
||||
padding-left:20px;
|
||||
padding-right:20px;
|
||||
}
|
||||
|
||||
.ie #head #searchbar #searchbar-fauxtext input#search-query {
|
||||
border: 0;
|
||||
float: left;
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
Gollum v3 Template
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
src: url('../fonts/fontawesome-webfont.eot?v=4.0.3');
|
||||
@@ -23,6 +27,51 @@
|
||||
content: "\f0c1";
|
||||
}
|
||||
|
||||
.fa-spinner:before {
|
||||
content: "\f110";
|
||||
}
|
||||
|
||||
.fa-spin {
|
||||
-webkit-animation: spin 2s infinite linear;
|
||||
-moz-animation: spin 2s infinite linear;
|
||||
-o-animation: spin 2s infinite linear;
|
||||
animation: spin 2s infinite linear;
|
||||
}
|
||||
@-moz-keyframes spin {
|
||||
0% {
|
||||
-moz-transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-moz-transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@-o-keyframes spin {
|
||||
0% {
|
||||
-o-transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-o-transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* margin & padding reset*/
|
||||
* {
|
||||
margin: 0;
|
||||
@@ -48,7 +97,6 @@ body {
|
||||
font: 13.34px Helvetica, arial, freesans, clean, sans-serif;
|
||||
font-size: small;
|
||||
line-height: 1.4;
|
||||
min-width: 980px;
|
||||
}
|
||||
|
||||
img {
|
||||
@@ -82,13 +130,19 @@ a:active, a:hover {
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
padding: 30px;
|
||||
padding: 1em;
|
||||
font-size: 15px;
|
||||
line-height: 1.7;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
@media all and (min-width: 940px) {
|
||||
.markdown-body {
|
||||
padding: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.markdown-body > *:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,52 @@
|
||||
$('#gollum-editor-help').removeClass('jaws');
|
||||
}
|
||||
} // EditorHas.functionBar
|
||||
|
||||
if ( EditorHas.dragDropUpload() ) {
|
||||
var $editorBody = $('#gollum-editor-body');
|
||||
var editorBody = $('#gollum-editor-body')[0];
|
||||
editorBody.ondragover = function(e) {
|
||||
$editorBody.addClass('dragging');
|
||||
return false;
|
||||
};
|
||||
editorBody.ondragleave = function() {
|
||||
$editorBody.removeClass('dragging');
|
||||
return false;
|
||||
};
|
||||
editorBody.ondrop = function(e) {
|
||||
debug("dropped file");
|
||||
e.preventDefault();
|
||||
$editorBody.removeClass('dragging').addClass('uploading');
|
||||
|
||||
var file = e.dataTransfer.files[0],
|
||||
formData = new FormData();
|
||||
formData.append('upload_dest', uploadDest);
|
||||
formData.append('file', file);
|
||||
|
||||
$.ajax({
|
||||
url: baseUrl + '/uploadFile',
|
||||
data: formData,
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
type: 'POST',
|
||||
success: function(){
|
||||
$editorBody.removeClass('uploading');
|
||||
var text = '[[/' + uploadDest + '/' + file.name + ']]';
|
||||
var pos = editorBody.selectionStart || 0;
|
||||
editorBody.value = editorBody.value.substring(0, pos) + text + editorBody.value.substring(pos);
|
||||
editorBody.selectionStart = pos + text.length;
|
||||
editorBody.selectionEnd = pos + text.length;
|
||||
},
|
||||
error: function(r, textStatus) {
|
||||
alert('Error uploading file: ' + textStatus);
|
||||
$editorBody.removeClass('uploading');
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
} // EditorHas.dragDropUpload
|
||||
} // EditorHas.baseEditorMarkup
|
||||
};
|
||||
|
||||
@@ -444,6 +490,17 @@
|
||||
*/
|
||||
titleDisplayed: function() {
|
||||
return ( ActiveOptions.NewFile );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* EditorHas.dragDropUpload
|
||||
* True if the editor is supports drag and drop file uploads, false otherwise.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
dragDropUpload: function() {
|
||||
return $('#gollum-editor.uploads-allowed').length;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -546,9 +603,12 @@
|
||||
typeof definitionObject.replace == 'string' ) {
|
||||
debug('Running replacement - using ' + definitionObject.replace);
|
||||
var rt = definitionObject.replace;
|
||||
|
||||
repText = escape( repText );
|
||||
repText = repText.replace( searchExp, rt );
|
||||
// remove backreferences
|
||||
repText = repText.replace( /\$[\d]/g, '' );
|
||||
repText = unescape( repText );
|
||||
|
||||
if ( repText === '' ) {
|
||||
debug('Search string is empty');
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* ASCIIDoc Language Definition
|
||||
* AsciiDoc Language Definition
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
var ASCIIDoc = {
|
||||
var AsciiDoc = {
|
||||
|
||||
'function-bold' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
@@ -19,7 +19,7 @@ var ASCIIDoc = {
|
||||
|
||||
'function-code' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "+$1+$2"
|
||||
replace: "`$1`$2"
|
||||
},
|
||||
|
||||
'function-ul' : {
|
||||
@@ -37,6 +37,21 @@ var ASCIIDoc = {
|
||||
replace: "----\n$1$2\n----\n"
|
||||
},
|
||||
|
||||
'function-h1' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "= $1$2"
|
||||
},
|
||||
|
||||
'function-h2' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "== $1$2"
|
||||
},
|
||||
|
||||
'function-h3' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "=== $1$2"
|
||||
},
|
||||
|
||||
'function-link' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
@@ -102,20 +117,20 @@ var ASCIIDoc = {
|
||||
|
||||
};
|
||||
|
||||
$.GollumEditor.defineLanguage('asciidoc', ASCIIDoc);
|
||||
$.GollumEditor.defineLanguage('asciidoc', AsciiDoc);
|
||||
|
||||
|
||||
var ASCIIDocHelp = [
|
||||
var AsciiDocHelp = [
|
||||
{
|
||||
menuName: 'Text Formatting',
|
||||
content: [
|
||||
{
|
||||
menuName: 'Headers',
|
||||
data: '<p>ASCIIDoc headers can be written in two ways: with differing underlines or with different indentation using <code>=</code> (equals sign). ASCIIDoc supports headings 1-4. The editor will automatically use the <code>=</code> notation. To create a level one header, prefix your line with one <code>=</code>. Level two headers are created with <code>==</code> and so on.</p>'
|
||||
data: '<p>AsciiDoc headers can be written in two ways: with differing underlines or with different indentation using <code>=</code> (equals sign). AsciiDoc supports headings 1-4. The editor will automatically use the <code>=</code> notation. To create a level one header, prefix your line with one <code>=</code>. Level two headers are created with <code>==</code> and so on.</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Bold / Italic',
|
||||
data: '<p>To display text as <strong>bold</strong>, wrap the text in <code>*</code> (asterisks). To display text as <em>italic</em>, wrap the text in <code>_</code> (underscores). To create <code>monospace</code> text, wrap the text in <code>+</code> (plus signs).'
|
||||
data: '<p>To display text as <strong>bold</strong>, wrap the text in <code>*</code> (asterisks). To display text as <em>italic</em>, wrap the text in <code>_</code> (underscores). To create <code>monospace</code> text, wrap the text in <code>`</code> (backtick).'
|
||||
},
|
||||
{
|
||||
menuName: 'Scripts',
|
||||
@@ -123,7 +138,7 @@ var ASCIIDocHelp = [
|
||||
},
|
||||
{
|
||||
menuName: 'Special Characters',
|
||||
data: '<p>ASCIIDoc will automatically convert textual representations of commonly-used special characters. For example, <code>(R)</code> becomes ®, <code>(C)</code> becomes © and <code>(TM)</code> becomes ™.</p>'
|
||||
data: '<p>AsciiDoc will automatically convert textual representations of commonly-used special characters. For example, <code>(R)</code> becomes ®, <code>(C)</code> becomes © and <code>(TM)</code> becomes ™.</p>'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -132,7 +147,7 @@ var ASCIIDocHelp = [
|
||||
content: [
|
||||
{
|
||||
menuName: 'Paragraphs',
|
||||
data: '<p>ASCIIDoc allows paragraphs to have optional titles or icons to denote special sections. To make a normal paragraph, simply add a line between blocks and a new paragraph will start. If you want to title your paragraphs, adda line prefixed by <code>.</code> (full stop). An example paragraph with optional title is displayed below:<br><br><code>.Optional Title<br><br>This is my paragraph. It is two sentences long.</code></p>'
|
||||
data: '<p>AsciiDoc allows paragraphs to have optional titles or icons to denote special sections. To make a normal paragraph, simply add a line between blocks and a new paragraph will start. If you want to title your paragraphs, adda line prefixed by <code>.</code> (full stop). An example paragraph with optional title is displayed below:<br><br><code>.Optional Title<br><br>This is my paragraph. It is two sentences long.</code></p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Source Blocks',
|
||||
@@ -157,12 +172,12 @@ var ASCIIDocHelp = [
|
||||
},
|
||||
{
|
||||
menuName: 'Images',
|
||||
data: '<p>Images in ASCIIDoc work much like hyperlinks, but image URLs are prefixed with <code>image:</code>. For example, to link to an image at <code>images/icons/home.png</code>, write <code>image:images/icons/home.png</code>. Alt text can be added by appending the text to the URI in <code>[</code> (brackets).</p>'
|
||||
data: '<p>Images in AsciiDoc work much like hyperlinks, but image URLs are prefixed with <code>image:</code>. For example, to link to an image at <code>images/icons/home.png</code>, write <code>image:images/icons/home.png</code>. Alt text can be added by appending the text to the URI in <code>[</code> (brackets).</p>'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
$.GollumEditor.defineHelp('asciidoc', ASCIIDocHelp);
|
||||
$.GollumEditor.defineHelp('asciidoc', AsciiDocHelp);
|
||||
|
||||
})(jQuery);
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
markupCreated: false,
|
||||
markup: '',
|
||||
|
||||
currentAspect: function(){
|
||||
if (window.innerWidth < 480) return "small-mobile";
|
||||
if ($('#gollum-dialog-dialog').css('position') == 'fixed') return "large-mobile";
|
||||
return "desktop";
|
||||
},
|
||||
|
||||
attachEvents: function( evtOK ) {
|
||||
$('#gollum-dialog-action-ok').click(function( e ) {
|
||||
Dialog.eventOK( e, evtOK );
|
||||
@@ -185,6 +191,8 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(window).unbind('resize', Dialog.resize);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -268,15 +276,29 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(window).bind('resize', Dialog.resize);
|
||||
}
|
||||
},
|
||||
|
||||
resize: function(){
|
||||
Dialog.position();
|
||||
},
|
||||
|
||||
position: function() {
|
||||
if (Dialog.currentAspect() == "small-mobile") {
|
||||
$('#gollum-dialog-dialog-inner').css('height', '100%').css('margin-top', 'auto');
|
||||
}
|
||||
else if (Dialog.currentAspect() == "large-mobile") {
|
||||
$('#gollum-dialog-dialog-inner').css('height', 'auto').css('margin-top', 'auto');
|
||||
}
|
||||
else if (Dialog.currentAspect() == "desktop") {
|
||||
var dialogHeight = $('#gollum-dialog-dialog-inner').height();
|
||||
$('#gollum-dialog-dialog-inner')
|
||||
.css('height', dialogHeight + 'px')
|
||||
.css('margin-top', -1 * parseInt( dialogHeight / 2 ));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ($.facebox) {
|
||||
|
||||
@@ -46,13 +46,16 @@ var Editor = require("./editor").Editor;
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var UndoManager = require("./undomanager").UndoManager;
|
||||
var Renderer = require("./virtual_renderer").VirtualRenderer;
|
||||
var MultiSelect = require("./multi_select").MultiSelect;
|
||||
|
||||
// The following require()s are for inclusion in the built ace file
|
||||
require("./worker/worker_client");
|
||||
require("./keyboard/hash_handler");
|
||||
require("./placeholder");
|
||||
require("./multi_select");
|
||||
require("./mode/folding/fold_mode");
|
||||
require("./theme/textmate");
|
||||
require("./ext/error_marker");
|
||||
|
||||
exports.config = require("./config");
|
||||
|
||||
/**
|
||||
@@ -71,34 +74,53 @@ exports.require = require;
|
||||
exports.edit = function(el) {
|
||||
if (typeof(el) == "string") {
|
||||
var _id = el;
|
||||
var el = document.getElementById(_id);
|
||||
el = document.getElementById(_id);
|
||||
if (!el)
|
||||
throw "ace.edit can't find div #" + _id;
|
||||
throw new Error("ace.edit can't find div #" + _id);
|
||||
}
|
||||
|
||||
if (el.env && el.env.editor instanceof Editor)
|
||||
if (el && el.env && el.env.editor instanceof Editor)
|
||||
return el.env.editor;
|
||||
|
||||
var doc = exports.createEditSession(dom.getInnerText(el));
|
||||
var value = "";
|
||||
if (el && /input|textarea/i.test(el.tagName)) {
|
||||
var oldNode = el;
|
||||
value = oldNode.value;
|
||||
el = dom.createElement("pre");
|
||||
oldNode.parentNode.replaceChild(el, oldNode);
|
||||
} else {
|
||||
value = dom.getInnerText(el);
|
||||
el.innerHTML = '';
|
||||
}
|
||||
|
||||
var doc = exports.createEditSession(value);
|
||||
|
||||
var editor = new Editor(new Renderer(el));
|
||||
new MultiSelect(editor);
|
||||
editor.setSession(doc);
|
||||
|
||||
var env = {
|
||||
document: doc,
|
||||
editor: editor,
|
||||
onResize: editor.resize.bind(editor)
|
||||
onResize: editor.resize.bind(editor, null)
|
||||
};
|
||||
if (oldNode) env.textarea = oldNode;
|
||||
event.addListener(window, "resize", env.onResize);
|
||||
el.env = editor.env = env;
|
||||
editor.on("destroy", function() {
|
||||
event.removeListener(window, "resize", env.onResize);
|
||||
env.editor.container.env = null; // prevent memory leak on old ie
|
||||
});
|
||||
editor.container.env = editor.env = env;
|
||||
return editor;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new [[EditSession]], and returns the associated [[Document]].
|
||||
* @param {Document | String} text {:textParam}
|
||||
* @param {TextMode} mode {:modeParam}
|
||||
*
|
||||
**/
|
||||
exports.createEditSession = function(text, mode) {
|
||||
var doc = new EditSession(text, doc);
|
||||
var doc = new EditSession(text, mode);
|
||||
doc.setUndoManager(new UndoManager());
|
||||
return doc;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
|
||||
/**
|
||||
*
|
||||
* Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated.
|
||||
* Defines a floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the anchor is updated.
|
||||
*
|
||||
* @class Anchor
|
||||
**/
|
||||
@@ -52,15 +52,13 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
**/
|
||||
|
||||
var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
this.document = doc;
|
||||
this.$onChange = this.onChange.bind(this);
|
||||
this.attach(doc);
|
||||
|
||||
if (typeof column == "undefined")
|
||||
this.setPosition(row.row, row.column);
|
||||
else
|
||||
this.setPosition(row, column);
|
||||
|
||||
this.$onChange = this.onChange.bind(this);
|
||||
doc.on("change", this.$onChange);
|
||||
};
|
||||
|
||||
(function() {
|
||||
@@ -71,7 +69,6 @@ var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
* Returns an object identifying the `row` and `column` position of the current anchor.
|
||||
* @returns {Object}
|
||||
**/
|
||||
|
||||
this.getPosition = function() {
|
||||
return this.$clipPositionToDocument(this.row, this.column);
|
||||
};
|
||||
@@ -81,11 +78,14 @@ var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
* Returns the current document.
|
||||
* @returns {Document}
|
||||
**/
|
||||
|
||||
this.getDocument = function() {
|
||||
return this.document;
|
||||
};
|
||||
|
||||
/**
|
||||
* experimental: allows anchor to stick to the next on the left
|
||||
*/
|
||||
this.$insertRight = false;
|
||||
/**
|
||||
* Fires whenever the anchor position changes.
|
||||
*
|
||||
@@ -98,9 +98,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
* - `old`: An object describing the old Anchor position
|
||||
* - `value`: An object describing the new Anchor position
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
this.onChange = function(e) {
|
||||
var delta = e.data;
|
||||
var range = delta.range;
|
||||
@@ -116,48 +114,50 @@ var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
|
||||
var row = this.row;
|
||||
var column = this.column;
|
||||
var start = range.start;
|
||||
var end = range.end;
|
||||
|
||||
if (delta.action === "insertText") {
|
||||
if (range.start.row === row && range.start.column <= column) {
|
||||
if (range.start.row === range.end.row) {
|
||||
column += range.end.column - range.start.column;
|
||||
if (start.row === row && start.column <= column) {
|
||||
if (start.column === column && this.$insertRight) {
|
||||
// do nothing
|
||||
} else if (start.row === end.row) {
|
||||
column += end.column - start.column;
|
||||
} else {
|
||||
column -= start.column;
|
||||
row += end.row - start.row;
|
||||
}
|
||||
else {
|
||||
column -= range.start.column;
|
||||
row += range.end.row - range.start.row;
|
||||
}
|
||||
}
|
||||
else if (range.start.row !== range.end.row && range.start.row < row) {
|
||||
row += range.end.row - range.start.row;
|
||||
} else if (start.row !== end.row && start.row < row) {
|
||||
row += end.row - start.row;
|
||||
}
|
||||
} else if (delta.action === "insertLines") {
|
||||
if (range.start.row <= row) {
|
||||
row += range.end.row - range.start.row;
|
||||
if (start.row === row && column === 0 && this.$insertRight) {
|
||||
// do nothing
|
||||
}
|
||||
else if (start.row <= row) {
|
||||
row += end.row - start.row;
|
||||
}
|
||||
else if (delta.action == "removeText") {
|
||||
if (range.start.row == row && range.start.column < column) {
|
||||
if (range.end.column >= column)
|
||||
column = range.start.column;
|
||||
} else if (delta.action === "removeText") {
|
||||
if (start.row === row && start.column < column) {
|
||||
if (end.column >= column)
|
||||
column = start.column;
|
||||
else
|
||||
column = Math.max(0, column - (range.end.column - range.start.column));
|
||||
column = Math.max(0, column - (end.column - start.column));
|
||||
|
||||
} else if (range.start.row !== range.end.row && range.start.row < row) {
|
||||
if (range.end.row == row) {
|
||||
column = Math.max(0, column - range.end.column) + range.start.column;
|
||||
}
|
||||
row -= (range.end.row - range.start.row);
|
||||
}
|
||||
else if (range.end.row == row) {
|
||||
row -= range.end.row - range.start.row;
|
||||
column = Math.max(0, column - range.end.column) + range.start.column;
|
||||
} else if (start.row !== end.row && start.row < row) {
|
||||
if (end.row === row)
|
||||
column = Math.max(0, column - end.column) + start.column;
|
||||
row -= (end.row - start.row);
|
||||
} else if (end.row === row) {
|
||||
row -= end.row - start.row;
|
||||
column = Math.max(0, column - end.column) + start.column;
|
||||
}
|
||||
} else if (delta.action == "removeLines") {
|
||||
if (range.start.row <= row) {
|
||||
if (range.end.row <= row)
|
||||
row -= range.end.row - range.start.row;
|
||||
if (start.row <= row) {
|
||||
if (end.row <= row)
|
||||
row -= end.row - start.row;
|
||||
else {
|
||||
row = range.start.row;
|
||||
row = start.row;
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
@@ -172,10 +172,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
* @param {Number} column The column index to move the anchor to
|
||||
* @param {Boolean} noClip Identifies if you want the position to be clipped
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
this.setPosition = function(row, column, noClip) {
|
||||
var pos;
|
||||
if (noClip) {
|
||||
@@ -183,8 +180,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
row: row,
|
||||
column: column
|
||||
};
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pos = this.$clipPositionToDocument(row, column);
|
||||
}
|
||||
|
||||
@@ -198,28 +194,29 @@ var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
|
||||
this.row = pos.row;
|
||||
this.column = pos.column;
|
||||
this._emit("change", {
|
||||
this._signal("change", {
|
||||
old: old,
|
||||
value: pos
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* When called, the `'change'` event listener is removed.
|
||||
* When called, the `"change"` event listener is removed.
|
||||
*
|
||||
**/
|
||||
|
||||
this.detach = function() {
|
||||
this.document.removeEventListener("change", this.$onChange);
|
||||
};
|
||||
this.attach = function(doc) {
|
||||
this.document = doc || this.document;
|
||||
this.document.on("change", this.$onChange);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clips the anchor position to the specified row and column.
|
||||
* @param {Number} row The row index to clip the anchor to
|
||||
* @param {Number} column The column index to clip the anchor to
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.$clipPositionToDocument = function(row, column) {
|
||||
var pos = {};
|
||||
|
||||
@@ -58,6 +58,15 @@ module.exports = {
|
||||
assert.position(anchor.getPosition(), 1, 7);
|
||||
},
|
||||
|
||||
"test insert text at anchor should not move anchor when insertRight is true": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
anchor.$insertRight = true;
|
||||
|
||||
doc.insert({row: 1, column: 4}, "123");
|
||||
assert.position(anchor.getPosition(), 1, 4);
|
||||
},
|
||||
|
||||
"test insert lines before cursor should move anchor row": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
@@ -66,6 +75,32 @@ module.exports = {
|
||||
assert.position(anchor.getPosition(), 3, 4);
|
||||
},
|
||||
|
||||
"test insert lines at anchor position should move anchor down": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 0);
|
||||
|
||||
doc.insertLines(1, ["line"]);
|
||||
assert.position(anchor.getPosition(), 2, 0);
|
||||
},
|
||||
|
||||
"test insert lines at anchor position should not move anchor down when insertRight is true and column is 0": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 0);
|
||||
anchor.$insertRight = true;
|
||||
|
||||
doc.insertLines(1, ["line"]);
|
||||
assert.position(anchor.getPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test insert lines at anchor row should move anchor down when column > 0": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 2);
|
||||
anchor.$insertRight = true;
|
||||
|
||||
doc.insertLines(1, ["line"]);
|
||||
assert.position(anchor.getPosition(), 2, 2);
|
||||
},
|
||||
|
||||
"test insert new line before cursor should move anchor column": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
@@ -167,6 +202,17 @@ module.exports = {
|
||||
});
|
||||
|
||||
doc.remove(new Range(2, 0, 2, 1));
|
||||
},
|
||||
|
||||
"test insert/remove lines at the end of the document": function() {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 2, 4);
|
||||
|
||||
doc.removeLines(0, 3);
|
||||
assert.position(anchor.getPosition(), 0, 0);
|
||||
doc.insertLines(0, ["a", "b", "c"]);
|
||||
assert.position(anchor.getPosition(), 3, 0);
|
||||
assert.equal(doc.getValue(), "a\nb\nc\n");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,497 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var HashHandler = require("./keyboard/hash_handler").HashHandler;
|
||||
var AcePopup = require("./autocomplete/popup").AcePopup;
|
||||
var util = require("./autocomplete/util");
|
||||
var event = require("./lib/event");
|
||||
var lang = require("./lib/lang");
|
||||
var dom = require("./lib/dom");
|
||||
var snippetManager = require("./snippets").snippetManager;
|
||||
|
||||
var Autocomplete = function() {
|
||||
this.autoInsert = false;
|
||||
this.autoSelect = true;
|
||||
this.exactMatch = false;
|
||||
this.gatherCompletionsId = 0;
|
||||
this.keyboardHandler = new HashHandler();
|
||||
this.keyboardHandler.bindKeys(this.commands);
|
||||
|
||||
this.blurListener = this.blurListener.bind(this);
|
||||
this.changeListener = this.changeListener.bind(this);
|
||||
this.mousedownListener = this.mousedownListener.bind(this);
|
||||
this.mousewheelListener = this.mousewheelListener.bind(this);
|
||||
|
||||
this.changeTimer = lang.delayedCall(function() {
|
||||
this.updateCompletions(true);
|
||||
}.bind(this));
|
||||
|
||||
this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.$init = function() {
|
||||
this.popup = new AcePopup(document.body || document.documentElement);
|
||||
this.popup.on("click", function(e) {
|
||||
this.insertMatch();
|
||||
e.stop();
|
||||
}.bind(this));
|
||||
this.popup.focus = this.editor.focus.bind(this.editor);
|
||||
this.popup.on("show", this.tooltipTimer.bind(null, null));
|
||||
this.popup.on("select", this.tooltipTimer.bind(null, null));
|
||||
this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null));
|
||||
return this.popup;
|
||||
};
|
||||
|
||||
this.getPopup = function() {
|
||||
return this.popup || this.$init();
|
||||
};
|
||||
|
||||
this.openPopup = function(editor, prefix, keepPopupPosition) {
|
||||
if (!this.popup)
|
||||
this.$init();
|
||||
|
||||
this.popup.setData(this.completions.filtered);
|
||||
|
||||
editor.keyBinding.addKeyboardHandler(this.keyboardHandler);
|
||||
|
||||
var renderer = editor.renderer;
|
||||
this.popup.setRow(this.autoSelect ? 0 : -1);
|
||||
if (!keepPopupPosition) {
|
||||
this.popup.setTheme(editor.getTheme());
|
||||
this.popup.setFontSize(editor.getFontSize());
|
||||
|
||||
var lineHeight = renderer.layerConfig.lineHeight;
|
||||
|
||||
var pos = renderer.$cursorLayer.getPixelPosition(this.base, true);
|
||||
pos.left -= this.popup.getTextLeftOffset();
|
||||
|
||||
var rect = editor.container.getBoundingClientRect();
|
||||
pos.top += rect.top - renderer.layerConfig.offset;
|
||||
pos.left += rect.left - editor.renderer.scrollLeft;
|
||||
pos.left += renderer.$gutterLayer.gutterWidth;
|
||||
|
||||
this.popup.show(pos, lineHeight);
|
||||
} else if (keepPopupPosition && !prefix) {
|
||||
this.detach();
|
||||
}
|
||||
};
|
||||
|
||||
this.detach = function() {
|
||||
this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler);
|
||||
this.editor.off("changeSelection", this.changeListener);
|
||||
this.editor.off("blur", this.blurListener);
|
||||
this.editor.off("mousedown", this.mousedownListener);
|
||||
this.editor.off("mousewheel", this.mousewheelListener);
|
||||
this.changeTimer.cancel();
|
||||
this.hideDocTooltip();
|
||||
|
||||
this.gatherCompletionsId += 1;
|
||||
if (this.popup && this.popup.isOpen)
|
||||
this.popup.hide();
|
||||
|
||||
if (this.base)
|
||||
this.base.detach();
|
||||
this.activated = false;
|
||||
this.completions = this.base = null;
|
||||
};
|
||||
|
||||
this.changeListener = function(e) {
|
||||
var cursor = this.editor.selection.lead;
|
||||
if (cursor.row != this.base.row || cursor.column < this.base.column) {
|
||||
this.detach();
|
||||
}
|
||||
if (this.activated)
|
||||
this.changeTimer.schedule();
|
||||
else
|
||||
this.detach();
|
||||
};
|
||||
|
||||
this.blurListener = function(e) {
|
||||
// we have to check if activeElement is a child of popup because
|
||||
// on IE preventDefault doesn't stop scrollbar from being focussed
|
||||
var el = document.activeElement;
|
||||
var text = this.editor.textInput.getElement()
|
||||
if (el != text && el.parentNode != this.popup.container
|
||||
&& el != this.tooltipNode && e.relatedTarget != this.tooltipNode
|
||||
&& e.relatedTarget != text
|
||||
) {
|
||||
this.detach();
|
||||
}
|
||||
};
|
||||
|
||||
this.mousedownListener = function(e) {
|
||||
this.detach();
|
||||
};
|
||||
|
||||
this.mousewheelListener = function(e) {
|
||||
this.detach();
|
||||
};
|
||||
|
||||
this.goTo = function(where) {
|
||||
var row = this.popup.getRow();
|
||||
var max = this.popup.session.getLength() - 1;
|
||||
|
||||
switch(where) {
|
||||
case "up": row = row <= 0 ? max : row - 1; break;
|
||||
case "down": row = row >= max ? -1 : row + 1; break;
|
||||
case "start": row = 0; break;
|
||||
case "end": row = max; break;
|
||||
}
|
||||
|
||||
this.popup.setRow(row);
|
||||
};
|
||||
|
||||
this.insertMatch = function(data) {
|
||||
if (!data)
|
||||
data = this.popup.getData(this.popup.getRow());
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
if (data.completer && data.completer.insertMatch) {
|
||||
data.completer.insertMatch(this.editor, data);
|
||||
} else {
|
||||
if (this.completions.filterText) {
|
||||
var ranges = this.editor.selection.getAllRanges();
|
||||
for (var i = 0, range; range = ranges[i]; i++) {
|
||||
range.start.column -= this.completions.filterText.length;
|
||||
this.editor.session.remove(range);
|
||||
}
|
||||
}
|
||||
if (data.snippet)
|
||||
snippetManager.insertSnippet(this.editor, data.snippet);
|
||||
else
|
||||
this.editor.execCommand("insertstring", data.value || data);
|
||||
}
|
||||
this.detach();
|
||||
};
|
||||
|
||||
|
||||
this.commands = {
|
||||
"Up": function(editor) { editor.completer.goTo("up"); },
|
||||
"Down": function(editor) { editor.completer.goTo("down"); },
|
||||
"Ctrl-Up|Ctrl-Home": function(editor) { editor.completer.goTo("start"); },
|
||||
"Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); },
|
||||
|
||||
"Esc": function(editor) { editor.completer.detach(); },
|
||||
"Space": function(editor) { editor.completer.detach(); editor.insert(" ");},
|
||||
"Return": function(editor) { return editor.completer.insertMatch(); },
|
||||
"Shift-Return": function(editor) { editor.completer.insertMatch(true); },
|
||||
"Tab": function(editor) {
|
||||
var result = editor.completer.insertMatch();
|
||||
if (!result && !editor.tabstopManager)
|
||||
editor.completer.goTo("down");
|
||||
else
|
||||
return result;
|
||||
},
|
||||
|
||||
"PageUp": function(editor) { editor.completer.popup.gotoPageUp(); },
|
||||
"PageDown": function(editor) { editor.completer.popup.gotoPageDown(); }
|
||||
};
|
||||
|
||||
this.gatherCompletions = function(editor, callback) {
|
||||
var session = editor.getSession();
|
||||
var pos = editor.getCursorPosition();
|
||||
|
||||
var line = session.getLine(pos.row);
|
||||
var prefix = util.retrievePrecedingIdentifier(line, pos.column);
|
||||
|
||||
this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length);
|
||||
this.base.$insertRight = true;
|
||||
|
||||
var matches = [];
|
||||
var total = editor.completers.length;
|
||||
editor.completers.forEach(function(completer, i) {
|
||||
completer.getCompletions(editor, session, pos, prefix, function(err, results) {
|
||||
if (!err)
|
||||
matches = matches.concat(results);
|
||||
// Fetch prefix again, because they may have changed by now
|
||||
var pos = editor.getCursorPosition();
|
||||
var line = session.getLine(pos.row);
|
||||
callback(null, {
|
||||
prefix: util.retrievePrecedingIdentifier(line, pos.column, results[0] && results[0].identifierRegex),
|
||||
matches: matches,
|
||||
finished: (--total === 0)
|
||||
});
|
||||
});
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
this.showPopup = function(editor) {
|
||||
if (this.editor)
|
||||
this.detach();
|
||||
|
||||
this.activated = true;
|
||||
|
||||
this.editor = editor;
|
||||
if (editor.completer != this) {
|
||||
if (editor.completer)
|
||||
editor.completer.detach();
|
||||
editor.completer = this;
|
||||
}
|
||||
|
||||
editor.on("changeSelection", this.changeListener);
|
||||
editor.on("blur", this.blurListener);
|
||||
editor.on("mousedown", this.mousedownListener);
|
||||
editor.on("mousewheel", this.mousewheelListener);
|
||||
|
||||
this.updateCompletions();
|
||||
};
|
||||
|
||||
this.updateCompletions = function(keepPopupPosition) {
|
||||
if (keepPopupPosition && this.base && this.completions) {
|
||||
var pos = this.editor.getCursorPosition();
|
||||
var prefix = this.editor.session.getTextRange({start: this.base, end: pos});
|
||||
if (prefix == this.completions.filterText)
|
||||
return;
|
||||
this.completions.setFilter(prefix);
|
||||
if (!this.completions.filtered.length)
|
||||
return this.detach();
|
||||
if (this.completions.filtered.length == 1
|
||||
&& this.completions.filtered[0].value == prefix
|
||||
&& !this.completions.filtered[0].snippet)
|
||||
return this.detach();
|
||||
this.openPopup(this.editor, prefix, keepPopupPosition);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save current gatherCompletions session, session is close when a match is insert
|
||||
var _id = this.gatherCompletionsId;
|
||||
this.gatherCompletions(this.editor, function(err, results) {
|
||||
// Only detach if result gathering is finished
|
||||
var detachIfFinished = function() {
|
||||
if (!results.finished) return;
|
||||
return this.detach();
|
||||
}.bind(this);
|
||||
|
||||
var prefix = results.prefix;
|
||||
var matches = results && results.matches;
|
||||
|
||||
if (!matches || !matches.length)
|
||||
return detachIfFinished();
|
||||
|
||||
// Wrong prefix or wrong session -> ignore
|
||||
if (prefix.indexOf(results.prefix) !== 0 || _id != this.gatherCompletionsId)
|
||||
return;
|
||||
|
||||
this.completions = new FilteredList(matches);
|
||||
|
||||
if (this.exactMatch)
|
||||
this.completions.exactMatch = true;
|
||||
|
||||
this.completions.setFilter(prefix);
|
||||
var filtered = this.completions.filtered;
|
||||
|
||||
// No results
|
||||
if (!filtered.length)
|
||||
return detachIfFinished();
|
||||
|
||||
// One result equals to the prefix
|
||||
if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet)
|
||||
return detachIfFinished();
|
||||
|
||||
// Autoinsert if one result
|
||||
if (this.autoInsert && filtered.length == 1 && results.finished)
|
||||
return this.insertMatch(filtered[0]);
|
||||
|
||||
this.openPopup(this.editor, prefix, keepPopupPosition);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
this.cancelContextMenu = function() {
|
||||
this.editor.$mouseHandler.cancelContextMenu();
|
||||
};
|
||||
|
||||
this.updateDocTooltip = function() {
|
||||
var popup = this.popup;
|
||||
var all = popup.data;
|
||||
var selected = all && (all[popup.getHoveredRow()] || all[popup.getRow()]);
|
||||
var doc = null;
|
||||
if (!selected || !this.editor || !this.popup.isOpen)
|
||||
return this.hideDocTooltip();
|
||||
this.editor.completers.some(function(completer) {
|
||||
if (completer.getDocTooltip)
|
||||
doc = completer.getDocTooltip(selected);
|
||||
return doc;
|
||||
});
|
||||
if (!doc)
|
||||
doc = selected;
|
||||
|
||||
if (typeof doc == "string")
|
||||
doc = {docText: doc}
|
||||
if (!doc || !(doc.docHTML || doc.docText))
|
||||
return this.hideDocTooltip();
|
||||
this.showDocTooltip(doc);
|
||||
};
|
||||
|
||||
this.showDocTooltip = function(item) {
|
||||
if (!this.tooltipNode) {
|
||||
this.tooltipNode = dom.createElement("div");
|
||||
this.tooltipNode.className = "ace_tooltip ace_doc-tooltip";
|
||||
this.tooltipNode.style.margin = 0;
|
||||
this.tooltipNode.style.pointerEvents = "auto";
|
||||
this.tooltipNode.tabIndex = -1;
|
||||
this.tooltipNode.onblur = this.blurListener.bind(this);
|
||||
}
|
||||
|
||||
var tooltipNode = this.tooltipNode;
|
||||
if (item.docHTML) {
|
||||
tooltipNode.innerHTML = item.docHTML;
|
||||
} else if (item.docText) {
|
||||
tooltipNode.textContent = item.docText;
|
||||
}
|
||||
|
||||
if (!tooltipNode.parentNode)
|
||||
document.body.appendChild(tooltipNode);
|
||||
var popup = this.popup;
|
||||
var rect = popup.container.getBoundingClientRect();
|
||||
tooltipNode.style.top = popup.container.style.top;
|
||||
tooltipNode.style.bottom = popup.container.style.bottom;
|
||||
|
||||
if (window.innerWidth - rect.right < 320) {
|
||||
tooltipNode.style.right = window.innerWidth - rect.left + "px";
|
||||
tooltipNode.style.left = "";
|
||||
} else {
|
||||
tooltipNode.style.left = (rect.right + 1) + "px";
|
||||
tooltipNode.style.right = "";
|
||||
}
|
||||
tooltipNode.style.display = "block";
|
||||
};
|
||||
|
||||
this.hideDocTooltip = function() {
|
||||
this.tooltipTimer.cancel();
|
||||
if (!this.tooltipNode) return;
|
||||
var el = this.tooltipNode;
|
||||
if (!this.editor.isFocused() && document.activeElement == el)
|
||||
this.editor.focus();
|
||||
this.tooltipNode = null;
|
||||
if (el.parentNode)
|
||||
el.parentNode.removeChild(el);
|
||||
};
|
||||
|
||||
}).call(Autocomplete.prototype);
|
||||
|
||||
Autocomplete.startCommand = {
|
||||
name: "startAutocomplete",
|
||||
exec: function(editor) {
|
||||
if (!editor.completer)
|
||||
editor.completer = new Autocomplete();
|
||||
editor.completer.autoInsert = false;
|
||||
editor.completer.autoSelect = true;
|
||||
editor.completer.showPopup(editor);
|
||||
// prevent ctrl-space opening context menu on firefox on mac
|
||||
editor.completer.cancelContextMenu();
|
||||
},
|
||||
bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space"
|
||||
};
|
||||
|
||||
var FilteredList = function(array, filterText, mutateData) {
|
||||
this.all = array;
|
||||
this.filtered = array;
|
||||
this.filterText = filterText || "";
|
||||
this.exactMatch = false;
|
||||
};
|
||||
(function(){
|
||||
this.setFilter = function(str) {
|
||||
if (str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0)
|
||||
var matches = this.filtered;
|
||||
else
|
||||
var matches = this.all;
|
||||
|
||||
this.filterText = str;
|
||||
matches = this.filterCompletions(matches, this.filterText);
|
||||
matches = matches.sort(function(a, b) {
|
||||
return b.exactMatch - a.exactMatch || b.score - a.score;
|
||||
});
|
||||
|
||||
// make unique
|
||||
var prev = null;
|
||||
matches = matches.filter(function(item){
|
||||
var caption = item.snippet || item.caption || item.value;
|
||||
if (caption === prev) return false;
|
||||
prev = caption;
|
||||
return true;
|
||||
});
|
||||
|
||||
this.filtered = matches;
|
||||
};
|
||||
this.filterCompletions = function(items, needle) {
|
||||
var results = [];
|
||||
var upper = needle.toUpperCase();
|
||||
var lower = needle.toLowerCase();
|
||||
loop: for (var i = 0, item; item = items[i]; i++) {
|
||||
var caption = item.value || item.caption || item.snippet;
|
||||
if (!caption) continue;
|
||||
var lastIndex = -1;
|
||||
var matchMask = 0;
|
||||
var penalty = 0;
|
||||
var index, distance;
|
||||
|
||||
if (this.exactMatch) {
|
||||
if (needle !== caption.substr(0, needle.length))
|
||||
continue loop;
|
||||
}else{
|
||||
// caption char iteration is faster in Chrome but slower in Firefox, so lets use indexOf
|
||||
for (var j = 0; j < needle.length; j++) {
|
||||
// TODO add penalty on case mismatch
|
||||
var i1 = caption.indexOf(lower[j], lastIndex + 1);
|
||||
var i2 = caption.indexOf(upper[j], lastIndex + 1);
|
||||
index = (i1 >= 0) ? ((i2 < 0 || i1 < i2) ? i1 : i2) : i2;
|
||||
if (index < 0)
|
||||
continue loop;
|
||||
distance = index - lastIndex - 1;
|
||||
if (distance > 0) {
|
||||
// first char mismatch should be more sensitive
|
||||
if (lastIndex === -1)
|
||||
penalty += 10;
|
||||
penalty += distance;
|
||||
}
|
||||
matchMask = matchMask | (1 << index);
|
||||
lastIndex = index;
|
||||
}
|
||||
}
|
||||
item.matchMask = matchMask;
|
||||
item.exactMatch = penalty ? 0 : 1;
|
||||
item.score = (item.score || 0) - penalty;
|
||||
results.push(item);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
}).call(FilteredList.prototype);
|
||||
|
||||
exports.Autocomplete = Autocomplete;
|
||||
exports.FilteredList = FilteredList;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,341 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("../edit_session").EditSession;
|
||||
var Renderer = require("../virtual_renderer").VirtualRenderer;
|
||||
var Editor = require("../editor").Editor;
|
||||
var Range = require("../range").Range;
|
||||
var event = require("../lib/event");
|
||||
var lang = require("../lib/lang");
|
||||
var dom = require("../lib/dom");
|
||||
|
||||
var $singleLineEditor = function(el) {
|
||||
var renderer = new Renderer(el);
|
||||
|
||||
renderer.$maxLines = 4;
|
||||
|
||||
var editor = new Editor(renderer);
|
||||
|
||||
editor.setHighlightActiveLine(false);
|
||||
editor.setShowPrintMargin(false);
|
||||
editor.renderer.setShowGutter(false);
|
||||
editor.renderer.setHighlightGutterLine(false);
|
||||
|
||||
editor.$mouseHandler.$focusWaitTimout = 0;
|
||||
editor.$highlightTagPending = true;
|
||||
|
||||
return editor;
|
||||
};
|
||||
|
||||
var AcePopup = function(parentNode) {
|
||||
var el = dom.createElement("div");
|
||||
var popup = new $singleLineEditor(el);
|
||||
|
||||
if (parentNode)
|
||||
parentNode.appendChild(el);
|
||||
el.style.display = "none";
|
||||
popup.renderer.content.style.cursor = "default";
|
||||
popup.renderer.setStyle("ace_autocomplete");
|
||||
|
||||
popup.setOption("displayIndentGuides", false);
|
||||
popup.setOption("dragDelay", 150);
|
||||
|
||||
var noop = function(){};
|
||||
|
||||
popup.focus = noop;
|
||||
popup.$isFocused = true;
|
||||
|
||||
popup.renderer.$cursorLayer.restartTimer = noop;
|
||||
popup.renderer.$cursorLayer.element.style.opacity = 0;
|
||||
|
||||
popup.renderer.$maxLines = 8;
|
||||
popup.renderer.$keepTextAreaAtCursor = false;
|
||||
|
||||
popup.setHighlightActiveLine(false);
|
||||
// set default highlight color
|
||||
popup.session.highlight("");
|
||||
popup.session.$searchHighlight.clazz = "ace_highlight-marker";
|
||||
|
||||
popup.on("mousedown", function(e) {
|
||||
var pos = e.getDocumentPosition();
|
||||
popup.selection.moveToPosition(pos);
|
||||
selectionMarker.start.row = selectionMarker.end.row = pos.row;
|
||||
e.stop();
|
||||
});
|
||||
|
||||
var lastMouseEvent;
|
||||
var hoverMarker = new Range(-1,0,-1,Infinity);
|
||||
var selectionMarker = new Range(-1,0,-1,Infinity);
|
||||
selectionMarker.id = popup.session.addMarker(selectionMarker, "ace_active-line", "fullLine");
|
||||
popup.setSelectOnHover = function(val) {
|
||||
if (!val) {
|
||||
hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine");
|
||||
} else if (hoverMarker.id) {
|
||||
popup.session.removeMarker(hoverMarker.id);
|
||||
hoverMarker.id = null;
|
||||
}
|
||||
};
|
||||
popup.setSelectOnHover(false);
|
||||
popup.on("mousemove", function(e) {
|
||||
if (!lastMouseEvent) {
|
||||
lastMouseEvent = e;
|
||||
return;
|
||||
}
|
||||
if (lastMouseEvent.x == e.x && lastMouseEvent.y == e.y) {
|
||||
return;
|
||||
}
|
||||
lastMouseEvent = e;
|
||||
lastMouseEvent.scrollTop = popup.renderer.scrollTop;
|
||||
var row = lastMouseEvent.getDocumentPosition().row;
|
||||
if (hoverMarker.start.row != row) {
|
||||
if (!hoverMarker.id)
|
||||
popup.setRow(row);
|
||||
setHoverMarker(row);
|
||||
}
|
||||
});
|
||||
popup.renderer.on("beforeRender", function() {
|
||||
if (lastMouseEvent && hoverMarker.start.row != -1) {
|
||||
lastMouseEvent.$pos = null;
|
||||
var row = lastMouseEvent.getDocumentPosition().row;
|
||||
if (!hoverMarker.id)
|
||||
popup.setRow(row);
|
||||
setHoverMarker(row, true);
|
||||
}
|
||||
});
|
||||
popup.renderer.on("afterRender", function() {
|
||||
var row = popup.getRow();
|
||||
var t = popup.renderer.$textLayer;
|
||||
var selected = t.element.childNodes[row - t.config.firstRow];
|
||||
if (selected == t.selectedNode)
|
||||
return;
|
||||
if (t.selectedNode)
|
||||
dom.removeCssClass(t.selectedNode, "ace_selected");
|
||||
t.selectedNode = selected;
|
||||
if (selected)
|
||||
dom.addCssClass(selected, "ace_selected");
|
||||
});
|
||||
var hideHoverMarker = function() { setHoverMarker(-1) };
|
||||
var setHoverMarker = function(row, suppressRedraw) {
|
||||
if (row !== hoverMarker.start.row) {
|
||||
hoverMarker.start.row = hoverMarker.end.row = row;
|
||||
if (!suppressRedraw)
|
||||
popup.session._emit("changeBackMarker");
|
||||
popup._emit("changeHoverMarker");
|
||||
}
|
||||
};
|
||||
popup.getHoveredRow = function() {
|
||||
return hoverMarker.start.row;
|
||||
};
|
||||
|
||||
event.addListener(popup.container, "mouseout", hideHoverMarker);
|
||||
popup.on("hide", hideHoverMarker);
|
||||
popup.on("changeSelection", hideHoverMarker);
|
||||
|
||||
popup.session.doc.getLength = function() {
|
||||
return popup.data.length;
|
||||
};
|
||||
popup.session.doc.getLine = function(i) {
|
||||
var data = popup.data[i];
|
||||
if (typeof data == "string")
|
||||
return data;
|
||||
return (data && data.value) || "";
|
||||
};
|
||||
|
||||
var bgTokenizer = popup.session.bgTokenizer;
|
||||
bgTokenizer.$tokenizeRow = function(row) {
|
||||
var data = popup.data[row];
|
||||
var tokens = [];
|
||||
if (!data)
|
||||
return tokens;
|
||||
if (typeof data == "string")
|
||||
data = {value: data};
|
||||
if (!data.caption)
|
||||
data.caption = data.value || data.name;
|
||||
|
||||
var last = -1;
|
||||
var flag, c;
|
||||
for (var i = 0; i < data.caption.length; i++) {
|
||||
c = data.caption[i];
|
||||
flag = data.matchMask & (1 << i) ? 1 : 0;
|
||||
if (last !== flag) {
|
||||
tokens.push({type: data.className || "" + ( flag ? "completion-highlight" : ""), value: c});
|
||||
last = flag;
|
||||
} else {
|
||||
tokens[tokens.length - 1].value += c;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.meta) {
|
||||
var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth;
|
||||
if (data.meta.length + data.caption.length < maxW - 2)
|
||||
tokens.push({type: "rightAlignedText", value: data.meta});
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
bgTokenizer.$updateOnChange = noop;
|
||||
bgTokenizer.start = noop;
|
||||
|
||||
popup.session.$computeWidth = function() {
|
||||
return this.screenWidth = 0;
|
||||
};
|
||||
|
||||
popup.$blockScrolling = Infinity;
|
||||
|
||||
// public
|
||||
popup.isOpen = false;
|
||||
popup.isTopdown = false;
|
||||
|
||||
popup.data = [];
|
||||
popup.setData = function(list) {
|
||||
popup.data = list || [];
|
||||
popup.setValue(lang.stringRepeat("\n", list.length), -1);
|
||||
popup.setRow(0);
|
||||
};
|
||||
popup.getData = function(row) {
|
||||
return popup.data[row];
|
||||
};
|
||||
|
||||
popup.getRow = function() {
|
||||
return selectionMarker.start.row;
|
||||
};
|
||||
popup.setRow = function(line) {
|
||||
line = Math.max(-1, Math.min(this.data.length, line));
|
||||
if (selectionMarker.start.row != line) {
|
||||
popup.selection.clearSelection();
|
||||
selectionMarker.start.row = selectionMarker.end.row = line || 0;
|
||||
popup.session._emit("changeBackMarker");
|
||||
popup.moveCursorTo(line || 0, 0);
|
||||
if (popup.isOpen)
|
||||
popup._signal("select");
|
||||
}
|
||||
};
|
||||
|
||||
popup.on("changeSelection", function() {
|
||||
if (popup.isOpen)
|
||||
popup.setRow(popup.selection.lead.row);
|
||||
popup.renderer.scrollCursorIntoView();
|
||||
});
|
||||
|
||||
popup.hide = function() {
|
||||
this.container.style.display = "none";
|
||||
this._signal("hide");
|
||||
popup.isOpen = false;
|
||||
};
|
||||
popup.show = function(pos, lineHeight, topdownOnly) {
|
||||
var el = this.container;
|
||||
var screenHeight = window.innerHeight;
|
||||
var screenWidth = window.innerWidth;
|
||||
var renderer = this.renderer;
|
||||
// var maxLines = Math.min(renderer.$maxLines, this.session.getLength());
|
||||
var maxH = renderer.$maxLines * lineHeight * 1.4;
|
||||
var top = pos.top + this.$borderSize;
|
||||
if (top + maxH > screenHeight - lineHeight && !topdownOnly) {
|
||||
el.style.top = "";
|
||||
el.style.bottom = screenHeight - top + "px";
|
||||
popup.isTopdown = false;
|
||||
} else {
|
||||
top += lineHeight;
|
||||
el.style.top = top + "px";
|
||||
el.style.bottom = "";
|
||||
popup.isTopdown = true;
|
||||
}
|
||||
|
||||
el.style.display = "";
|
||||
this.renderer.$textLayer.checkForSizeChanges();
|
||||
|
||||
var left = pos.left;
|
||||
if (left + el.offsetWidth > screenWidth)
|
||||
left = screenWidth - el.offsetWidth;
|
||||
|
||||
el.style.left = left + "px";
|
||||
|
||||
this._signal("show");
|
||||
lastMouseEvent = null;
|
||||
popup.isOpen = true;
|
||||
};
|
||||
|
||||
popup.getTextLeftOffset = function() {
|
||||
return this.$borderSize + this.renderer.$padding + this.$imageSize;
|
||||
};
|
||||
|
||||
popup.$imageSize = 0;
|
||||
popup.$borderSize = 1;
|
||||
|
||||
return popup;
|
||||
};
|
||||
|
||||
dom.importCssString("\
|
||||
.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {\
|
||||
background-color: #CAD6FA;\
|
||||
z-index: 1;\
|
||||
}\
|
||||
.ace_editor.ace_autocomplete .ace_line-hover {\
|
||||
border: 1px solid #abbffe;\
|
||||
margin-top: -1px;\
|
||||
background: rgba(233,233,253,0.4);\
|
||||
}\
|
||||
.ace_editor.ace_autocomplete .ace_line-hover {\
|
||||
position: absolute;\
|
||||
z-index: 2;\
|
||||
}\
|
||||
.ace_editor.ace_autocomplete .ace_scroller {\
|
||||
background: none;\
|
||||
border: none;\
|
||||
box-shadow: none;\
|
||||
}\
|
||||
.ace_rightAlignedText {\
|
||||
color: gray;\
|
||||
display: inline-block;\
|
||||
position: absolute;\
|
||||
right: 4px;\
|
||||
text-align: right;\
|
||||
z-index: -1;\
|
||||
}\
|
||||
.ace_editor.ace_autocomplete .ace_completion-highlight{\
|
||||
color: #000;\
|
||||
text-shadow: 0 0 0.01em;\
|
||||
}\
|
||||
.ace_editor.ace_autocomplete {\
|
||||
width: 280px;\
|
||||
z-index: 200000;\
|
||||
background: #fbfbfb;\
|
||||
color: #444;\
|
||||
border: 1px lightgray solid;\
|
||||
position: fixed;\
|
||||
box-shadow: 2px 3px 5px rgba(0,0,0,.2);\
|
||||
line-height: 1.4;\
|
||||
}");
|
||||
|
||||
exports.AcePopup = AcePopup;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
var Range = require("../range").Range;
|
||||
|
||||
var splitRegex = /[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/;
|
||||
|
||||
function getWordIndex(doc, pos) {
|
||||
var textBefore = doc.getTextRange(Range.fromPoints({row: 0, column:0}, pos));
|
||||
return textBefore.split(splitRegex).length - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a distance analysis of the word `prefix` at position `pos` in `doc`.
|
||||
* @return Map
|
||||
*/
|
||||
function wordDistance(doc, pos) {
|
||||
var prefixPos = getWordIndex(doc, pos);
|
||||
var words = doc.getValue().split(splitRegex);
|
||||
var wordScores = Object.create(null);
|
||||
|
||||
var currentWord = words[prefixPos];
|
||||
|
||||
words.forEach(function(word, idx) {
|
||||
if (!word || word === currentWord) return;
|
||||
|
||||
var distance = Math.abs(prefixPos - idx);
|
||||
var score = words.length - distance;
|
||||
if (wordScores[word]) {
|
||||
wordScores[word] = Math.max(score, wordScores[word]);
|
||||
} else {
|
||||
wordScores[word] = score;
|
||||
}
|
||||
});
|
||||
return wordScores;
|
||||
}
|
||||
|
||||
exports.getCompletions = function(editor, session, pos, prefix, callback) {
|
||||
var wordScore = wordDistance(session, pos, prefix);
|
||||
var wordList = Object.keys(wordScore);
|
||||
callback(null, wordList.map(function(word) {
|
||||
return {
|
||||
caption: word,
|
||||
value: word,
|
||||
score: wordScore[word],
|
||||
meta: "local"
|
||||
};
|
||||
}));
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
exports.parForEach = function(array, fn, callback) {
|
||||
var completed = 0;
|
||||
var arLength = array.length;
|
||||
if (arLength === 0)
|
||||
callback();
|
||||
for (var i = 0; i < arLength; i++) {
|
||||
fn(array[i], function(result, err) {
|
||||
completed++;
|
||||
if (completed === arLength)
|
||||
callback(result, err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var ID_REGEX = /[a-zA-Z_0-9\$\-\u00A2-\uFFFF]/;
|
||||
|
||||
exports.retrievePrecedingIdentifier = function(text, pos, regex) {
|
||||
regex = regex || ID_REGEX;
|
||||
var buf = [];
|
||||
for (var i = pos-1; i >= 0; i--) {
|
||||
if (regex.test(text[i]))
|
||||
buf.push(text[i]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return buf.reverse().join("");
|
||||
};
|
||||
|
||||
exports.retrieveFollowingIdentifier = function(text, pos, regex) {
|
||||
regex = regex || ID_REGEX;
|
||||
var buf = [];
|
||||
for (var i = pos; i < text.length; i++) {
|
||||
if (regex.test(text[i]))
|
||||
buf.push(text[i]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
};
|
||||
|
||||
});
|
||||
@@ -34,12 +34,8 @@ define(function(require, exports, module) {
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
|
||||
// tokenizing lines longer than this makes editor very slow
|
||||
var MAX_LINE_LENGTH = 5000;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use.
|
||||
*
|
||||
* If a certain row is changed, everything below that row is re-tokenized.
|
||||
@@ -52,8 +48,6 @@ var MAX_LINE_LENGTH = 5000;
|
||||
* @param {Tokenizer} tokenizer The tokenizer to use
|
||||
* @param {Editor} editor The editor to associate with
|
||||
*
|
||||
*
|
||||
*
|
||||
* @constructor
|
||||
**/
|
||||
|
||||
@@ -70,29 +64,36 @@ var BackgroundTokenizer = function(tokenizer, editor) {
|
||||
if (!self.running) { return; }
|
||||
|
||||
var workerStart = new Date();
|
||||
var startLine = self.currentLine;
|
||||
var currentLine = self.currentLine;
|
||||
var endLine = -1;
|
||||
var doc = self.doc;
|
||||
|
||||
var processedLines = 0;
|
||||
while (self.lines[currentLine])
|
||||
currentLine++;
|
||||
|
||||
var startLine = currentLine;
|
||||
|
||||
var len = doc.getLength();
|
||||
while (self.currentLine < len) {
|
||||
self.$tokenizeRow(self.currentLine);
|
||||
while (self.lines[self.currentLine])
|
||||
self.currentLine++;
|
||||
var processedLines = 0;
|
||||
self.running = false;
|
||||
while (currentLine < len) {
|
||||
self.$tokenizeRow(currentLine);
|
||||
endLine = currentLine;
|
||||
do {
|
||||
currentLine++;
|
||||
} while (self.lines[currentLine]);
|
||||
|
||||
// only check every 5 lines
|
||||
processedLines ++;
|
||||
if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) {
|
||||
self.fireUpdateEvent(startLine, self.currentLine-1);
|
||||
if ((processedLines % 5 === 0) && (new Date() - workerStart) > 20) {
|
||||
self.running = setTimeout(self.$worker, 20);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.currentLine = currentLine;
|
||||
|
||||
self.running = false;
|
||||
|
||||
self.fireUpdateEvent(startLine, len - 1);
|
||||
if (startLine <= endLine)
|
||||
self.fireUpdateEvent(startLine, endLine);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -144,7 +145,7 @@ var BackgroundTokenizer = function(tokenizer, editor) {
|
||||
first: firstRow,
|
||||
last: lastRow
|
||||
};
|
||||
this._emit("update", {data: data});
|
||||
this._signal("update", {data: data});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -165,6 +166,11 @@ var BackgroundTokenizer = function(tokenizer, editor) {
|
||||
this.running = setTimeout(this.$worker, 700);
|
||||
};
|
||||
|
||||
this.scheduleStart = function() {
|
||||
if (!this.running)
|
||||
this.running = setTimeout(this.$worker, 700);
|
||||
}
|
||||
|
||||
this.$updateOnChange = function(delta) {
|
||||
var range = delta.range;
|
||||
var startRow = range.start.row;
|
||||
@@ -185,8 +191,6 @@ var BackgroundTokenizer = function(tokenizer, editor) {
|
||||
this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength());
|
||||
|
||||
this.stop();
|
||||
// pretty long delay to prevent the tokenizer from interfering with the user
|
||||
this.running = setTimeout(this.$worker, 700);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -226,17 +230,9 @@ var BackgroundTokenizer = function(tokenizer, editor) {
|
||||
var line = this.doc.getLine(row);
|
||||
var state = this.states[row - 1];
|
||||
|
||||
if (line.length > MAX_LINE_LENGTH) {
|
||||
var overflow = {value: line.substr(MAX_LINE_LENGTH), type: "text"};
|
||||
line = line.slice(0, MAX_LINE_LENGTH);
|
||||
}
|
||||
var data = this.tokenizer.getLineTokens(line, state);
|
||||
if (overflow) {
|
||||
data.tokens.push(overflow);
|
||||
data.state = "start";
|
||||
}
|
||||
var data = this.tokenizer.getLineTokens(line, state, row);
|
||||
|
||||
if (this.states[row] !== data.state) {
|
||||
if (this.states[row] + "" !== data.state + "") {
|
||||
this.states[row] = data.state;
|
||||
this.lines[row + 1] = null;
|
||||
if (this.currentLine > row + 1)
|
||||
|
||||
@@ -62,19 +62,19 @@ module.exports = {
|
||||
doc.setMode("./mode/javascript")
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "start", "start"])
|
||||
testStates(doc, ["comment_regex_allowed", "start", "no_regex"])
|
||||
|
||||
doc.remove(new Range(0,2,1,2))
|
||||
testStates(doc, [null, "start"])
|
||||
testStates(doc, [null, "no_regex"])
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "comment"])
|
||||
testStates(doc, ["comment_regex_allowed", "comment_regex_allowed"])
|
||||
|
||||
doc.insert({row:0, column:2}, "\n*/")
|
||||
testStates(doc, [undefined, undefined, "comment"])
|
||||
testStates(doc, [undefined, undefined, "comment_regex_allowed"])
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "start", "start"])
|
||||
testStates(doc, ["comment_regex_allowed", "start", "no_regex"])
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,45 +2,44 @@ define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
var MultiHashHandler = require("../keyboard/hash_handler").MultiHashHandler;
|
||||
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
||||
|
||||
/**
|
||||
* @class CommandManager
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new CommandManager(platform, commands)
|
||||
* @param {String} platform Identifier for the platform; must be either `'mac'` or `'win'`
|
||||
* @param {String} platform Identifier for the platform; must be either `"mac"` or `"win"`
|
||||
* @param {Array} commands A list of commands
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
var CommandManager = function(platform, commands) {
|
||||
this.platform = platform;
|
||||
this.commands = this.byName = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
this.addCommands(commands);
|
||||
|
||||
MultiHashHandler.call(this, commands, platform);
|
||||
this.byName = this.commands;
|
||||
this.setDefaultHandler("exec", function(e) {
|
||||
return e.command.exec(e.editor, e.args || {});
|
||||
});
|
||||
};
|
||||
|
||||
oop.inherits(CommandManager, HashHandler);
|
||||
oop.inherits(CommandManager, MultiHashHandler);
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.exec = function(command, editor, args) {
|
||||
if (typeof command === 'string')
|
||||
if (Array.isArray(command)) {
|
||||
for (var i = command.length; i--; ) {
|
||||
if (this.exec(command[i], editor, args)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof command === "string")
|
||||
command = this.commands[command];
|
||||
|
||||
if (!command)
|
||||
@@ -49,13 +48,11 @@ oop.inherits(CommandManager, HashHandler);
|
||||
if (editor && editor.$readOnly && !command.readOnly)
|
||||
return false;
|
||||
|
||||
var retvalue = this._emit("exec", {
|
||||
editor: editor,
|
||||
command: command,
|
||||
args: args
|
||||
});
|
||||
var e = {editor: editor, command: command, args: args};
|
||||
e.returnValue = this._emit("exec", e);
|
||||
this._signal("afterExec", e);
|
||||
|
||||
return retvalue === false ? false : true;
|
||||
return e.returnValue === false ? false : true;
|
||||
};
|
||||
|
||||
this.toggleRecording = function(editor) {
|
||||
|
||||
+1
-1
@@ -188,7 +188,7 @@ module.exports = {
|
||||
assert.equal(command, "cm2");
|
||||
|
||||
var command = this.cm.findKeyCommand(0, "return");
|
||||
assert.equal(command, "cm3");
|
||||
assert.equal(command + "", ["cm4", "cm3"] + "");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,15 +32,48 @@ define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var lang = require("../lib/lang");
|
||||
var config = require("../config");
|
||||
var Range = require("../range").Range;
|
||||
|
||||
function bindKey(win, mac) {
|
||||
return {
|
||||
win: win,
|
||||
mac: mac
|
||||
};
|
||||
return {win: win, mac: mac};
|
||||
}
|
||||
|
||||
/*
|
||||
multiSelectAction: "forEach"|"forEachLine"|function|undefined,
|
||||
scrollIntoView: true|"cursor"|"center"|"selectionPart"
|
||||
*/
|
||||
exports.commands = [{
|
||||
name: "showSettingsMenu",
|
||||
bindKey: bindKey("Ctrl-,", "Command-,"),
|
||||
exec: function(editor) {
|
||||
config.loadModule("ace/ext/settings_menu", function(module) {
|
||||
module.init(editor);
|
||||
editor.showSettingsMenu();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "goToNextError",
|
||||
bindKey: bindKey("Alt-E", "Ctrl-E"),
|
||||
exec: function(editor) {
|
||||
config.loadModule("ace/ext/error_marker", function(module) {
|
||||
module.showErrorMarker(editor, 1);
|
||||
});
|
||||
},
|
||||
scrollIntoView: "animate",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "goToPreviousError",
|
||||
bindKey: bindKey("Alt-Shift-E", "Ctrl-Shift-E"),
|
||||
exec: function(editor) {
|
||||
config.loadModule("ace/ext/error_marker", function(module) {
|
||||
module.showErrorMarker(editor, -1);
|
||||
});
|
||||
},
|
||||
scrollIntoView: "animate",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectall",
|
||||
bindKey: bindKey("Ctrl-A", "Command-A"),
|
||||
exec: function(editor) { editor.selectAll(); },
|
||||
@@ -64,38 +97,86 @@ exports.commands = [{
|
||||
name: "fold",
|
||||
bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"),
|
||||
exec: function(editor) { editor.session.toggleFold(false); },
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "unfold",
|
||||
bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"),
|
||||
exec: function(editor) { editor.session.toggleFold(true); },
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "toggleFoldWidget",
|
||||
bindKey: bindKey("F2", "F2"),
|
||||
exec: function(editor) { editor.session.toggleFoldWidget(); },
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "toggleParentFoldWidget",
|
||||
bindKey: bindKey("Alt-F2", "Alt-F2"),
|
||||
exec: function(editor) { editor.session.toggleFoldWidget(true); },
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "foldall",
|
||||
bindKey: bindKey("Alt-0", "Command-Option-0"),
|
||||
bindKey: bindKey("Ctrl-Alt-0", "Ctrl-Command-Option-0"),
|
||||
exec: function(editor) { editor.session.foldAll(); },
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "foldOther",
|
||||
bindKey: bindKey("Alt-0", "Command-Option-0"),
|
||||
exec: function(editor) {
|
||||
editor.session.foldAll();
|
||||
editor.session.unfold(editor.selection.getAllRanges());
|
||||
},
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "unfoldall",
|
||||
bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"),
|
||||
exec: function(editor) { editor.session.unfold(); },
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "findnext",
|
||||
bindKey: bindKey("Ctrl-K", "Command-G"),
|
||||
exec: function(editor) { editor.findNext(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "findprevious",
|
||||
bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"),
|
||||
exec: function(editor) { editor.findPrevious(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "center",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectOrFindNext",
|
||||
bindKey: bindKey("Alt-K", "Ctrl-G"),
|
||||
exec: function(editor) {
|
||||
if (editor.selection.isEmpty())
|
||||
editor.selection.selectWord();
|
||||
else
|
||||
editor.findNext();
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectOrFindPrevious",
|
||||
bindKey: bindKey("Alt-Shift-K", "Ctrl-Shift-G"),
|
||||
exec: function(editor) {
|
||||
if (editor.selection.isEmpty())
|
||||
editor.selection.selectWord();
|
||||
else
|
||||
editor.findPrevious();
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "find",
|
||||
bindKey: bindKey("Ctrl-F", "Command-F"),
|
||||
exec: function(editor) {
|
||||
var needle = prompt("Find:", editor.getCopyText());
|
||||
editor.find(needle);
|
||||
config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor)});
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
@@ -108,120 +189,144 @@ exports.commands = [{
|
||||
bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Up"),
|
||||
exec: function(editor) { editor.getSelection().selectFileStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
readOnly: true,
|
||||
scrollIntoView: "animate",
|
||||
aceCommandGroup: "fileJump"
|
||||
}, {
|
||||
name: "gotostart",
|
||||
bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"),
|
||||
exec: function(editor) { editor.navigateFileStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
readOnly: true,
|
||||
scrollIntoView: "animate",
|
||||
aceCommandGroup: "fileJump"
|
||||
}, {
|
||||
name: "selectup",
|
||||
bindKey: bindKey("Shift-Up", "Shift-Up"),
|
||||
exec: function(editor) { editor.getSelection().selectUp(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "golineup",
|
||||
bindKey: bindKey("Up", "Up|Ctrl-P"),
|
||||
exec: function(editor, args) { editor.navigateUp(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttoend",
|
||||
bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-Down"),
|
||||
exec: function(editor) { editor.getSelection().selectFileEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
readOnly: true,
|
||||
scrollIntoView: "animate",
|
||||
aceCommandGroup: "fileJump"
|
||||
}, {
|
||||
name: "gotoend",
|
||||
bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"),
|
||||
exec: function(editor) { editor.navigateFileEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
readOnly: true,
|
||||
scrollIntoView: "animate",
|
||||
aceCommandGroup: "fileJump"
|
||||
}, {
|
||||
name: "selectdown",
|
||||
bindKey: bindKey("Shift-Down", "Shift-Down"),
|
||||
exec: function(editor) { editor.getSelection().selectDown(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "golinedown",
|
||||
bindKey: bindKey("Down", "Down|Ctrl-N"),
|
||||
exec: function(editor, args) { editor.navigateDown(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectwordleft",
|
||||
bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectWordLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotowordleft",
|
||||
bindKey: bindKey("Ctrl-Left", "Option-Left"),
|
||||
exec: function(editor) { editor.navigateWordLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttolinestart",
|
||||
bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotolinestart",
|
||||
bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"),
|
||||
exec: function(editor) { editor.navigateLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectleft",
|
||||
bindKey: bindKey("Shift-Left", "Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoleft",
|
||||
bindKey: bindKey("Left", "Left|Ctrl-B"),
|
||||
exec: function(editor, args) { editor.navigateLeft(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectwordright",
|
||||
bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectWordRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotowordright",
|
||||
bindKey: bindKey("Ctrl-Right", "Option-Right"),
|
||||
exec: function(editor) { editor.navigateWordRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttolineend",
|
||||
bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotolineend",
|
||||
bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"),
|
||||
exec: function(editor) { editor.navigateLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectright",
|
||||
bindKey: bindKey("Shift-Right", "Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoright",
|
||||
bindKey: bindKey("Right", "Right|Ctrl-F"),
|
||||
exec: function(editor, args) { editor.navigateRight(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectpagedown",
|
||||
@@ -268,12 +373,14 @@ exports.commands = [{
|
||||
bindKey: "Shift-Home",
|
||||
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectlineend",
|
||||
bindKey: "Shift-End",
|
||||
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "togglerecording",
|
||||
@@ -287,14 +394,30 @@ exports.commands = [{
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "jumptomatching",
|
||||
bindKey: bindKey("Ctrl-P", "Ctrl-Shift-P"),
|
||||
bindKey: bindKey("Ctrl-P", "Ctrl-P"),
|
||||
exec: function(editor) { editor.jumpToMatching(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "animate",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttomatching",
|
||||
bindKey: bindKey("Ctrl-Shift-P", null),
|
||||
bindKey: bindKey("Ctrl-Shift-P", "Ctrl-Shift-P"),
|
||||
exec: function(editor) { editor.jumpToMatching(true); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "animate",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "expandToMatching",
|
||||
bindKey: bindKey("Ctrl-Shift-M", "Ctrl-Shift-M"),
|
||||
exec: function(editor) { editor.jumpToMatching(true, true); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "animate",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "passKeysToBrowser",
|
||||
bindKey: bindKey("null", "null"),
|
||||
exec: function() {},
|
||||
passEvent: true,
|
||||
readOnly: true
|
||||
},
|
||||
|
||||
@@ -310,60 +433,55 @@ exports.commands = [{
|
||||
editor.clearSelection();
|
||||
}
|
||||
},
|
||||
scrollIntoView: "cursor",
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removeline",
|
||||
bindKey: bindKey("Ctrl-D", "Command-D"),
|
||||
exec: function(editor) { editor.removeLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
scrollIntoView: "cursor",
|
||||
multiSelectAction: "forEachLine"
|
||||
}, {
|
||||
name: "duplicateSelection",
|
||||
bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"),
|
||||
exec: function(editor) { editor.duplicateSelection(); },
|
||||
scrollIntoView: "cursor",
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "sortlines",
|
||||
bindKey: bindKey("Ctrl-Alt-S", "Command-Alt-S"),
|
||||
exec: function(editor) { editor.sortLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
scrollIntoView: "selection",
|
||||
multiSelectAction: "forEachLine"
|
||||
}, {
|
||||
name: "togglecomment",
|
||||
bindKey: bindKey("Ctrl-/", "Command-/"),
|
||||
exec: function(editor) { editor.toggleCommentLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEachLine",
|
||||
scrollIntoView: "selectionPart"
|
||||
}, {
|
||||
name: "toggleBlockComment",
|
||||
bindKey: bindKey("Ctrl-Shift-/", "Command-Shift-/"),
|
||||
exec: function(editor) { editor.toggleBlockComment(); },
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "selectionPart"
|
||||
}, {
|
||||
name: "modifyNumberUp",
|
||||
bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"),
|
||||
exec: function(editor) { editor.modifyNumber(1); },
|
||||
scrollIntoView: "cursor",
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "modifyNumberDown",
|
||||
bindKey: bindKey("Ctrl-Shift-Down", "Alt-Shift-Down"),
|
||||
exec: function(editor) { editor.modifyNumber(-1); },
|
||||
scrollIntoView: "cursor",
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "replace",
|
||||
bindKey: bindKey("Ctrl-R", "Command-Option-F"),
|
||||
bindKey: bindKey("Ctrl-H", "Command-Option-F"),
|
||||
exec: function(editor) {
|
||||
var needle = prompt("Find:", editor.getCopyText());
|
||||
if (!needle)
|
||||
return;
|
||||
var replacement = prompt("Replacement:");
|
||||
if (!replacement)
|
||||
return;
|
||||
editor.replace(replacement, {needle: needle});
|
||||
}
|
||||
}, {
|
||||
name: "replaceall",
|
||||
bindKey: bindKey("Ctrl-Shift-R", "Command-Shift-Option-F"),
|
||||
exec: function(editor) {
|
||||
var needle = prompt("Find:");
|
||||
if (!needle)
|
||||
return;
|
||||
var replacement = prompt("Replacement:");
|
||||
if (!replacement)
|
||||
return;
|
||||
editor.replaceAll(replacement, {needle: needle});
|
||||
config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor, true)});
|
||||
}
|
||||
}, {
|
||||
name: "undo",
|
||||
@@ -376,92 +494,228 @@ exports.commands = [{
|
||||
}, {
|
||||
name: "copylinesup",
|
||||
bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"),
|
||||
exec: function(editor) { editor.copyLinesUp(); }
|
||||
exec: function(editor) { editor.copyLinesUp(); },
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "movelinesup",
|
||||
bindKey: bindKey("Alt-Up", "Option-Up"),
|
||||
exec: function(editor) { editor.moveLinesUp(); }
|
||||
exec: function(editor) { editor.moveLinesUp(); },
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "copylinesdown",
|
||||
bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"),
|
||||
exec: function(editor) { editor.copyLinesDown(); }
|
||||
exec: function(editor) { editor.copyLinesDown(); },
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "movelinesdown",
|
||||
bindKey: bindKey("Alt-Down", "Option-Down"),
|
||||
exec: function(editor) { editor.moveLinesDown(); }
|
||||
exec: function(editor) { editor.moveLinesDown(); },
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "del",
|
||||
bindKey: bindKey("Delete", "Delete|Ctrl-D"),
|
||||
bindKey: bindKey("Delete", "Delete|Ctrl-D|Shift-Delete"),
|
||||
exec: function(editor) { editor.remove("right"); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "backspace",
|
||||
bindKey: bindKey(
|
||||
"Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
|
||||
"Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H"
|
||||
"Shift-Backspace|Backspace",
|
||||
"Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H"
|
||||
),
|
||||
exec: function(editor) { editor.remove("left"); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "cut_or_delete",
|
||||
bindKey: bindKey("Shift-Delete", null),
|
||||
exec: function(editor) {
|
||||
if (editor.selection.isEmpty()) {
|
||||
editor.remove("left");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "removetolinestart",
|
||||
bindKey: bindKey("Alt-Backspace", "Command-Backspace"),
|
||||
exec: function(editor) { editor.removeToLineStart(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "removetolineend",
|
||||
bindKey: bindKey("Alt-Delete", "Ctrl-K"),
|
||||
exec: function(editor) { editor.removeToLineEnd(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "removewordleft",
|
||||
bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"),
|
||||
exec: function(editor) { editor.removeWordLeft(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "removewordright",
|
||||
bindKey: bindKey("Ctrl-Delete", "Alt-Delete"),
|
||||
exec: function(editor) { editor.removeWordRight(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "outdent",
|
||||
bindKey: bindKey("Shift-Tab", "Shift-Tab"),
|
||||
exec: function(editor) { editor.blockOutdent(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "selectionPart"
|
||||
}, {
|
||||
name: "indent",
|
||||
bindKey: bindKey("Tab", "Tab"),
|
||||
exec: function(editor) { editor.indent(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "selectionPart"
|
||||
}, {
|
||||
name: "blockoutdent",
|
||||
bindKey: bindKey("Ctrl-[", "Ctrl-["),
|
||||
exec: function(editor) { editor.blockOutdent(); },
|
||||
multiSelectAction: "forEachLine",
|
||||
scrollIntoView: "selectionPart"
|
||||
}, {
|
||||
name: "blockindent",
|
||||
bindKey: bindKey("Ctrl-]", "Ctrl-]"),
|
||||
exec: function(editor) { editor.blockIndent(); },
|
||||
multiSelectAction: "forEachLine",
|
||||
scrollIntoView: "selectionPart"
|
||||
}, {
|
||||
name: "insertstring",
|
||||
exec: function(editor, str) { editor.insert(str); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "inserttext",
|
||||
exec: function(editor, args) {
|
||||
editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
|
||||
},
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "splitline",
|
||||
bindKey: bindKey(null, "Ctrl-O"),
|
||||
exec: function(editor) { editor.splitLine(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "transposeletters",
|
||||
bindKey: bindKey("Ctrl-T", "Ctrl-T"),
|
||||
exec: function(editor) { editor.transposeLetters(); },
|
||||
multiSelectAction: function(editor) {editor.transposeSelections(1); }
|
||||
multiSelectAction: function(editor) {editor.transposeSelections(1); },
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "touppercase",
|
||||
bindKey: bindKey("Ctrl-U", "Ctrl-U"),
|
||||
exec: function(editor) { editor.toUpperCase(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "tolowercase",
|
||||
bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"),
|
||||
exec: function(editor) { editor.toLowerCase(); },
|
||||
multiSelectAction: "forEach"
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "expandtoline",
|
||||
bindKey: bindKey("Ctrl-Shift-L", "Command-Shift-L"),
|
||||
exec: function(editor) {
|
||||
var range = editor.selection.getRange();
|
||||
|
||||
range.start.column = range.end.column = 0;
|
||||
range.end.row++;
|
||||
editor.selection.setRange(range, false);
|
||||
},
|
||||
multiSelectAction: "forEach",
|
||||
scrollIntoView: "cursor",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "joinlines",
|
||||
bindKey: bindKey(null, null),
|
||||
exec: function(editor) {
|
||||
var isBackwards = editor.selection.isBackwards();
|
||||
var selectionStart = isBackwards ? editor.selection.getSelectionLead() : editor.selection.getSelectionAnchor();
|
||||
var selectionEnd = isBackwards ? editor.selection.getSelectionAnchor() : editor.selection.getSelectionLead();
|
||||
var firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length;
|
||||
var selectedText = editor.session.doc.getTextRange(editor.selection.getRange());
|
||||
var selectedCount = selectedText.replace(/\n\s*/, " ").length;
|
||||
var insertLine = editor.session.doc.getLine(selectionStart.row);
|
||||
|
||||
for (var i = selectionStart.row + 1; i <= selectionEnd.row + 1; i++) {
|
||||
var curLine = lang.stringTrimLeft(lang.stringTrimRight(editor.session.doc.getLine(i)));
|
||||
if (curLine.length !== 0) {
|
||||
curLine = " " + curLine;
|
||||
}
|
||||
insertLine += curLine;
|
||||
}
|
||||
|
||||
if (selectionEnd.row + 1 < (editor.session.doc.getLength() - 1)) {
|
||||
// Don't insert a newline at the end of the document
|
||||
insertLine += editor.session.doc.getNewLineCharacter();
|
||||
}
|
||||
|
||||
editor.clearSelection();
|
||||
editor.session.doc.replace(new Range(selectionStart.row, 0, selectionEnd.row + 2, 0), insertLine);
|
||||
|
||||
if (selectedCount > 0) {
|
||||
// Select the text that was previously selected
|
||||
editor.selection.moveCursorTo(selectionStart.row, selectionStart.column);
|
||||
editor.selection.selectTo(selectionStart.row, selectionStart.column + selectedCount);
|
||||
} else {
|
||||
// If the joined line had something in it, start the cursor at that something
|
||||
firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length > firstLineEndCol ? (firstLineEndCol + 1) : firstLineEndCol;
|
||||
editor.selection.moveCursorTo(selectionStart.row, firstLineEndCol);
|
||||
}
|
||||
},
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "invertSelection",
|
||||
bindKey: bindKey(null, null),
|
||||
exec: function(editor) {
|
||||
var endRow = editor.session.doc.getLength() - 1;
|
||||
var endCol = editor.session.doc.getLine(endRow).length;
|
||||
var ranges = editor.selection.rangeList.ranges;
|
||||
var newRanges = [];
|
||||
|
||||
// If multiple selections don't exist, rangeList will return 0 so replace with single range
|
||||
if (ranges.length < 1) {
|
||||
ranges = [editor.selection.getRange()];
|
||||
}
|
||||
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (i == (ranges.length - 1)) {
|
||||
// The last selection must connect to the end of the document, unless it already does
|
||||
if (!(ranges[i].end.row === endRow && ranges[i].end.column === endCol)) {
|
||||
newRanges.push(new Range(ranges[i].end.row, ranges[i].end.column, endRow, endCol));
|
||||
}
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
// The first selection must connect to the start of the document, unless it already does
|
||||
if (!(ranges[i].start.row === 0 && ranges[i].start.column === 0)) {
|
||||
newRanges.push(new Range(0, 0, ranges[i].start.row, ranges[i].start.column));
|
||||
}
|
||||
} else {
|
||||
newRanges.push(new Range(ranges[i-1].end.row, ranges[i-1].end.column, ranges[i].start.row, ranges[i].start.column));
|
||||
}
|
||||
}
|
||||
|
||||
editor.exitMultiSelectMode();
|
||||
editor.clearSelection();
|
||||
|
||||
for(var i = 0; i < newRanges.length; i++) {
|
||||
editor.selection.addRange(newRanges[i], false);
|
||||
}
|
||||
},
|
||||
readOnly: true,
|
||||
scrollIntoView: "none"
|
||||
}];
|
||||
|
||||
});
|
||||
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var config = require("../config");
|
||||
var oop = require("../lib/oop");
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
var occurStartCommand = require("./occur_commands").occurStartCommand;
|
||||
|
||||
// These commands can be installed in a normal key handler to start iSearch:
|
||||
exports.iSearchStartCommands = [{
|
||||
name: "iSearch",
|
||||
bindKey: {win: "Ctrl-F", mac: "Command-F"},
|
||||
exec: function(editor, options) {
|
||||
config.loadModule(["core", "ace/incremental_search"], function(e) {
|
||||
var iSearch = e.iSearch = e.iSearch || new e.IncrementalSearch();
|
||||
iSearch.activate(editor, options.backwards);
|
||||
if (options.jumpToFirstMatch) iSearch.next(options);
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "iSearchBackwards",
|
||||
exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {backwards: true}); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "iSearchAndGo",
|
||||
bindKey: {win: "Ctrl-K", mac: "Command-G"},
|
||||
exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {jumpToFirstMatch: true, useCurrentOrPrevSearch: true}); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "iSearchBackwardsAndGo",
|
||||
bindKey: {win: "Ctrl-Shift-K", mac: "Command-Shift-G"},
|
||||
exec: function(editor) { editor.execCommand('iSearch', {jumpToFirstMatch: true, backwards: true, useCurrentOrPrevSearch: true}); },
|
||||
readOnly: true
|
||||
}];
|
||||
|
||||
// These commands are only available when incremental search mode is active:
|
||||
exports.iSearchCommands = [{
|
||||
name: "restartSearch",
|
||||
bindKey: {win: "Ctrl-F", mac: "Command-F"},
|
||||
exec: function(iSearch) {
|
||||
iSearch.cancelSearch(true);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "searchForward",
|
||||
bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"},
|
||||
exec: function(iSearch, options) {
|
||||
options.useCurrentOrPrevSearch = true;
|
||||
iSearch.next(options);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "searchBackward",
|
||||
bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"},
|
||||
exec: function(iSearch, options) {
|
||||
options.useCurrentOrPrevSearch = true;
|
||||
options.backwards = true;
|
||||
iSearch.next(options);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "extendSearchTerm",
|
||||
exec: function(iSearch, string) {
|
||||
iSearch.addString(string);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "extendSearchTermSpace",
|
||||
bindKey: "space",
|
||||
exec: function(iSearch) { iSearch.addString(' '); },
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "shrinkSearchTerm",
|
||||
bindKey: "backspace",
|
||||
exec: function(iSearch) {
|
||||
iSearch.removeChar();
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: 'confirmSearch',
|
||||
bindKey: 'return',
|
||||
exec: function(iSearch) { iSearch.deactivate(); },
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: 'cancelSearch',
|
||||
bindKey: 'esc|Ctrl-G',
|
||||
exec: function(iSearch) { iSearch.deactivate(true); },
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: 'occurisearch',
|
||||
bindKey: 'Ctrl-O',
|
||||
exec: function(iSearch) {
|
||||
var options = oop.mixin({}, iSearch.$options);
|
||||
iSearch.deactivate();
|
||||
occurStartCommand.exec(iSearch.$editor, options);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "yankNextWord",
|
||||
bindKey: "Ctrl-w",
|
||||
exec: function(iSearch) {
|
||||
var ed = iSearch.$editor,
|
||||
range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorWordRight(); }),
|
||||
string = ed.session.getTextRange(range);
|
||||
iSearch.addString(string);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "yankNextChar",
|
||||
bindKey: "Ctrl-Alt-y",
|
||||
exec: function(iSearch) {
|
||||
var ed = iSearch.$editor,
|
||||
range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorRight(); }),
|
||||
string = ed.session.getTextRange(range);
|
||||
iSearch.addString(string);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: 'recenterTopBottom',
|
||||
bindKey: 'Ctrl-l',
|
||||
exec: function(iSearch) { iSearch.$editor.execCommand('recenterTopBottom'); },
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: 'selectAllMatches',
|
||||
bindKey: 'Ctrl-space',
|
||||
exec: function(iSearch) {
|
||||
var ed = iSearch.$editor,
|
||||
hl = ed.session.$isearchHighlight,
|
||||
ranges = hl && hl.cache ? hl.cache
|
||||
.reduce(function(ranges, ea) {
|
||||
return ranges.concat(ea ? ea : []); }, []) : [];
|
||||
iSearch.deactivate(false);
|
||||
ranges.forEach(ed.selection.addRange.bind(ed.selection));
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: 'searchAsRegExp',
|
||||
bindKey: 'Alt-r',
|
||||
exec: function(iSearch) {
|
||||
iSearch.convertNeedleToRegExp();
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}];
|
||||
|
||||
function IncrementalSearchKeyboardHandler(iSearch) {
|
||||
this.$iSearch = iSearch;
|
||||
}
|
||||
|
||||
oop.inherits(IncrementalSearchKeyboardHandler, HashHandler);
|
||||
|
||||
;(function() {
|
||||
|
||||
this.attach = function(editor) {
|
||||
var iSearch = this.$iSearch;
|
||||
HashHandler.call(this, exports.iSearchCommands, editor.commands.platform);
|
||||
this.$commandExecHandler = editor.commands.addEventListener('exec', function(e) {
|
||||
if (!e.command.isIncrementalSearchCommand) return undefined;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return e.command.exec(iSearch, e.args || {});
|
||||
});
|
||||
}
|
||||
|
||||
this.detach = function(editor) {
|
||||
if (!this.$commandExecHandler) return;
|
||||
editor.commands.removeEventListener('exec', this.$commandExecHandler);
|
||||
delete this.$commandExecHandler;
|
||||
}
|
||||
|
||||
var handleKeyboard$super = this.handleKeyboard;
|
||||
this.handleKeyboard = function(data, hashId, key, keyCode) {
|
||||
if (((hashId === 1/*ctrl*/ || hashId === 8/*command*/) && key === 'v')
|
||||
|| (hashId === 1/*ctrl*/ && key === 'y')) return null;
|
||||
var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);
|
||||
if (cmd.command) { return cmd; }
|
||||
if (hashId == -1) {
|
||||
var extendCmd = this.commands.extendSearchTerm;
|
||||
if (extendCmd) { return {command: extendCmd, args: key}; }
|
||||
}
|
||||
return {command: "null", passEvent: hashId == 0 || hashId == 4};
|
||||
}
|
||||
|
||||
}).call(IncrementalSearchKeyboardHandler.prototype);
|
||||
|
||||
|
||||
exports.IncrementalSearchKeyboardHandler = IncrementalSearchKeyboardHandler;
|
||||
|
||||
});
|
||||
+17
-1
@@ -35,41 +35,49 @@ exports.defaultCommands = [{
|
||||
name: "addCursorAbove",
|
||||
exec: function(editor) { editor.selectMoreLines(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelow",
|
||||
exec: function(editor) { editor.selectMoreLines(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorAboveSkipCurrent",
|
||||
exec: function(editor) { editor.selectMoreLines(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelowSkipCurrent",
|
||||
exec: function(editor) { editor.selectMoreLines(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreBefore",
|
||||
exec: function(editor) { editor.selectMore(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreAfter",
|
||||
exec: function(editor) { editor.selectMore(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextBefore",
|
||||
exec: function(editor) { editor.selectMore(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextAfter",
|
||||
exec: function(editor) { editor.selectMore(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}, {
|
||||
name: "splitIntoLines",
|
||||
@@ -79,7 +87,14 @@ exports.defaultCommands = [{
|
||||
}, {
|
||||
name: "alignCursors",
|
||||
exec: function(editor) { editor.alignCursors(); },
|
||||
bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"}
|
||||
bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"},
|
||||
scrollIntoView: "cursor"
|
||||
}, {
|
||||
name: "findAll",
|
||||
exec: function(editor) { editor.findAll(); },
|
||||
bindKey: {win: "Ctrl-Alt-K", mac: "Ctrl-Alt-G"},
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true
|
||||
}];
|
||||
|
||||
// commands active only in multiselect mode
|
||||
@@ -87,6 +102,7 @@ exports.multiSelectCommands = [{
|
||||
name: "singleSelection",
|
||||
bindKey: "esc",
|
||||
exec: function(editor) { editor.exitMultiSelectMode(); },
|
||||
scrollIntoView: "cursor",
|
||||
readonly: true,
|
||||
isAvailable: function(editor) {return editor && editor.inMultiSelectMode}
|
||||
}];
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var config = require("../config"),
|
||||
Occur = require("../occur").Occur;
|
||||
|
||||
// These commands can be installed in a normal command handler to start occur:
|
||||
var occurStartCommand = {
|
||||
name: "occur",
|
||||
exec: function(editor, options) {
|
||||
var alreadyInOccur = !!editor.session.$occur;
|
||||
var occurSessionActive = new Occur().enter(editor, options);
|
||||
if (occurSessionActive && !alreadyInOccur)
|
||||
OccurKeyboardHandler.installIn(editor);
|
||||
},
|
||||
readOnly: true
|
||||
};
|
||||
|
||||
var occurCommands = [{
|
||||
name: "occurexit",
|
||||
bindKey: 'esc|Ctrl-G',
|
||||
exec: function(editor) {
|
||||
var occur = editor.session.$occur;
|
||||
if (!occur) return;
|
||||
occur.exit(editor, {});
|
||||
if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor);
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "occuraccept",
|
||||
bindKey: 'enter',
|
||||
exec: function(editor) {
|
||||
var occur = editor.session.$occur;
|
||||
if (!occur) return;
|
||||
occur.exit(editor, {translatePosition: true});
|
||||
if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor);
|
||||
},
|
||||
readOnly: true
|
||||
}];
|
||||
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
var oop = require("../lib/oop");
|
||||
|
||||
|
||||
function OccurKeyboardHandler() {}
|
||||
|
||||
oop.inherits(OccurKeyboardHandler, HashHandler);
|
||||
|
||||
;(function() {
|
||||
|
||||
this.isOccurHandler = true;
|
||||
|
||||
this.attach = function(editor) {
|
||||
HashHandler.call(this, occurCommands, editor.commands.platform);
|
||||
this.$editor = editor;
|
||||
}
|
||||
|
||||
var handleKeyboard$super = this.handleKeyboard;
|
||||
this.handleKeyboard = function(data, hashId, key, keyCode) {
|
||||
var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);
|
||||
return (cmd && cmd.command) ? cmd : undefined;
|
||||
}
|
||||
|
||||
}).call(OccurKeyboardHandler.prototype);
|
||||
|
||||
OccurKeyboardHandler.installIn = function(editor) {
|
||||
var handler = new this();
|
||||
editor.keyBinding.addKeyboardHandler(handler);
|
||||
editor.commands.addCommands(occurCommands);
|
||||
}
|
||||
|
||||
OccurKeyboardHandler.uninstallFrom = function(editor) {
|
||||
editor.commands.removeCommands(occurCommands);
|
||||
var handler = editor.getKeyboardHandler();
|
||||
if (handler.isOccurHandler)
|
||||
editor.keyBinding.removeKeyboardHandler(handler);
|
||||
}
|
||||
|
||||
exports.occurStartCommand = occurStartCommand;
|
||||
|
||||
});
|
||||
@@ -32,6 +32,11 @@ define(function(require, exports, module) {
|
||||
"no use strict";
|
||||
|
||||
var lang = require("./lib/lang");
|
||||
var oop = require("./lib/oop");
|
||||
var net = require("./lib/net");
|
||||
var AppConfig = require("./lib/app_config").AppConfig;
|
||||
|
||||
module.exports = exports = new AppConfig();
|
||||
|
||||
var global = (function() {
|
||||
return this;
|
||||
@@ -65,30 +70,81 @@ exports.all = function() {
|
||||
return lang.copyObject(options);
|
||||
};
|
||||
|
||||
// module loading
|
||||
exports.moduleUrl = function(name, component) {
|
||||
if (options.$moduleUrls[name])
|
||||
return options.$moduleUrls[name];
|
||||
|
||||
var parts = name.split("/");
|
||||
component = component || parts[parts.length - 2] || "";
|
||||
var base = parts[parts.length - 1].replace(component, "").replace(/(^[\-_])|([\-_]$)/, "");
|
||||
|
||||
if (!base && parts.length > 1)
|
||||
// todo make this configurable or get rid of '-'
|
||||
var sep = component == "snippets" ? "/" : "-";
|
||||
var base = parts[parts.length - 1];
|
||||
if (component == "worker" && sep == "-") {
|
||||
var re = new RegExp("^" + component + "[\\-_]|[\\-_]" + component + "$", "g");
|
||||
base = base.replace(re, "");
|
||||
}
|
||||
|
||||
if ((!base || base == component) && parts.length > 1)
|
||||
base = parts[parts.length - 2];
|
||||
var path = options[component + "Path"];
|
||||
if (path == null)
|
||||
if (path == null) {
|
||||
path = options.basePath;
|
||||
} else if (sep == "/") {
|
||||
component = sep = "";
|
||||
}
|
||||
if (path && path.slice(-1) != "/")
|
||||
path += "/";
|
||||
return path + component + "-" + base + this.get("suffix");
|
||||
return path + component + sep + base + this.get("suffix");
|
||||
};
|
||||
|
||||
exports.setModuleUrl = function(name, subst) {
|
||||
return options.$moduleUrls[name] = subst;
|
||||
};
|
||||
|
||||
exports.init = function() {
|
||||
options.packaged = require.packaged || module.packaged || (global.define && define.packaged);
|
||||
exports.$loading = {};
|
||||
exports.loadModule = function(moduleName, onLoad) {
|
||||
var module, moduleType;
|
||||
if (Array.isArray(moduleName)) {
|
||||
moduleType = moduleName[0];
|
||||
moduleName = moduleName[1];
|
||||
}
|
||||
|
||||
try {
|
||||
module = require(moduleName);
|
||||
} catch (e) {}
|
||||
// require(moduleName) can return empty object if called after require([moduleName], callback)
|
||||
if (module && !exports.$loading[moduleName])
|
||||
return onLoad && onLoad(module);
|
||||
|
||||
if (!exports.$loading[moduleName])
|
||||
exports.$loading[moduleName] = [];
|
||||
|
||||
exports.$loading[moduleName].push(onLoad);
|
||||
|
||||
if (exports.$loading[moduleName].length > 1)
|
||||
return;
|
||||
|
||||
var afterLoad = function() {
|
||||
require([moduleName], function(module) {
|
||||
exports._emit("load.module", {name: moduleName, module: module});
|
||||
var listeners = exports.$loading[moduleName];
|
||||
exports.$loading[moduleName] = null;
|
||||
listeners.forEach(function(onLoad) {
|
||||
onLoad && onLoad(module);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (!exports.get("packaged"))
|
||||
return afterLoad();
|
||||
net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad);
|
||||
};
|
||||
|
||||
// initialization
|
||||
function init(packaged) {
|
||||
options.packaged = packaged || require.packaged || module.packaged || (global.define && define.packaged);
|
||||
|
||||
if (!global.document)
|
||||
return "";
|
||||
@@ -96,7 +152,11 @@ exports.init = function() {
|
||||
var scriptOptions = {};
|
||||
var scriptUrl = "";
|
||||
|
||||
var scripts = document.getElementsByTagName("script");
|
||||
// Use currentScript.ownerDocument in case this file was loaded from imported document. (HTML Imports)
|
||||
var currentScript = (document.currentScript || document._currentScript ); // native or polyfill
|
||||
var currentDocument = currentScript && currentScript.ownerDocument || document;
|
||||
|
||||
var scripts = currentDocument.getElementsByTagName("script");
|
||||
for (var i=0; i<scripts.length; i++) {
|
||||
var script = scripts[i];
|
||||
|
||||
@@ -122,6 +182,7 @@ exports.init = function() {
|
||||
scriptOptions.packaged = true;
|
||||
}
|
||||
|
||||
scriptOptions.basePath = scriptOptions.base;
|
||||
scriptOptions.workerPath = scriptOptions.workerPath || scriptOptions.base;
|
||||
scriptOptions.modePath = scriptOptions.modePath || scriptOptions.base;
|
||||
scriptOptions.themePath = scriptOptions.themePath || scriptOptions.base;
|
||||
@@ -132,6 +193,8 @@ exports.init = function() {
|
||||
exports.set(key, scriptOptions[key]);
|
||||
};
|
||||
|
||||
exports.init = init;
|
||||
|
||||
function deHyphenate(str) {
|
||||
return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); });
|
||||
}
|
||||
|
||||
@@ -40,10 +40,10 @@ var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test path resolution" : function() {
|
||||
"test: path resolution" : function() {
|
||||
config.set("packaged", "true");
|
||||
var url = config.moduleUrl("kr_theme", "theme");
|
||||
assert.equal(url, "theme-kr.js");
|
||||
assert.equal(url, "theme-kr_theme.js");
|
||||
|
||||
config.set("basePath", "a/b");
|
||||
url = config.moduleUrl("m/theme", "theme");
|
||||
@@ -60,12 +60,76 @@ module.exports = {
|
||||
url = config.moduleUrl("foo/1", "theme");
|
||||
assert.equal(url, "a/b1.js");
|
||||
|
||||
url = config.moduleUrl("snippets/js");
|
||||
assert.equal(url, "a/b/snippets/js.js");
|
||||
|
||||
config.setModuleUrl("snippets/js", "_.js");
|
||||
url = config.moduleUrl("snippets/js");
|
||||
assert.equal(url, "_.js");
|
||||
|
||||
url = config.moduleUrl("ace/ext/textarea");
|
||||
assert.equal(url, "a/b/ext-textarea.js");
|
||||
|
||||
assert.equal();
|
||||
},
|
||||
"test: define options" : function() {
|
||||
var o = {};
|
||||
config.defineOptions(o, "test_object", {
|
||||
opt1: {
|
||||
set: function(val) {
|
||||
this.x = val;
|
||||
},
|
||||
value: 7,
|
||||
},
|
||||
initialValue: {
|
||||
set: function(val) {
|
||||
this.x = val;
|
||||
},
|
||||
initialValue: 8,
|
||||
},
|
||||
opt2: {
|
||||
get: function(val) {
|
||||
return this.x;
|
||||
}
|
||||
},
|
||||
forwarded: "model"
|
||||
});
|
||||
o.model = {};
|
||||
config.defineOptions(o.model, "model", {
|
||||
forwarded: {value: 1}
|
||||
});
|
||||
|
||||
config.resetOptions(o);
|
||||
config.resetOptions(o.model);
|
||||
assert.equal(o.getOption("opt1"), 7);
|
||||
assert.equal(o.getOption("opt2"), 7);
|
||||
o.setOption("opt1", 8);
|
||||
assert.equal(o.getOption("opt1"), 8);
|
||||
assert.equal(o.getOption("opt2"), 8);
|
||||
|
||||
assert.equal(o.getOption("forwarded"), 1);
|
||||
|
||||
assert.equal(o.getOption("new"), undefined);
|
||||
o.setOption("new", 0);
|
||||
assert.equal(o.getOption("new"), undefined);
|
||||
|
||||
|
||||
assert.equal(o.getOption("initialValue"), 8);
|
||||
o.setOption("initialValue", 7);
|
||||
assert.equal(o.getOption("opt2"), 7);
|
||||
|
||||
config.setDefaultValues("test_object", {
|
||||
opt1: 1,
|
||||
forwarded: 2
|
||||
});
|
||||
config.resetOptions(o);
|
||||
assert.equal(o.getOption("opt1"), 1);
|
||||
assert.equal(o.getOption("forwarded"), 2);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
.ace_editor {
|
||||
position: absolute;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
font-size: 12px;
|
||||
font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.ace_scroller {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: inherit;
|
||||
-ms-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.ace_content {
|
||||
@@ -15,16 +23,40 @@
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
cursor: text;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.ace_dragging .ace_scroller:before{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
content: '';
|
||||
background: rgba(250, 250, 250, 0.01);
|
||||
z-index: 1000;
|
||||
}
|
||||
.ace_dragging.ace_dark .ace_scroller:before{
|
||||
background: rgba(0, 0, 0, 0.01);
|
||||
}
|
||||
|
||||
.ace_selecting, .ace_selecting * {
|
||||
cursor: text !important;
|
||||
}
|
||||
|
||||
.ace_gutter {
|
||||
position: absolute;
|
||||
overflow : hidden;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
-ms-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.ace_gutter-active-line {
|
||||
@@ -44,34 +76,47 @@
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_error {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUM2OEZDQTQ4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUM2OEZDQTU4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQzY4RkNBMjhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQzY4RkNBMzhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkgXxbAAAAJbSURBVHjapFNNaBNBFH4zs5vdZLP5sQmNpT82QY209heh1ioWisaDRcSKF0WKJ0GQnrzrxasHsR6EnlrwD0TagxJabaVEpFYxLWlLSS822tr87m66ccfd2GKyVhA6MMybgfe97/vmPUQphd0sZjto9XIn9OOsvlu2nkqRzVU+6vvlzPf8W6bk8dxQ0NPbxAALgCgg2JkaQuhzQau/El0zbmUA7U0Es8v2CiYmKQJHGO1QICCLoqilMhkmurDAyapKgqItezi/USRdJqEYY4D5jCy03ht2yMkkvL91jTTX10qzyyu2hruPRN7jgbH+EOsXcMLgYiThEgAMhABW85oqy1DXdRIdvP1AHJ2acQXvDIrVHcdQNrEKNYSVMSZGMjEzIIAwDXIo+6G/FxcGnzkC3T2oMhLjre49sBB+RRcHLqdafK6sYdE/GGBwU1VpFNj0aN8pJbe+BkZyevUrvLl6Xmm0W9IuTc0DxrDNAJd5oEvI/KRsNC3bQyNjPO9yQ1YHcfj2QvfQc/5TUhJTBc2iM0U7AWDQtc1nJHvD/cfO2s7jaGkiTEfa/Ep8coLu7zmNmh8+dc5lZDuUeFAGUNA/OY6JVaypQ0vjr7XYjUvJM37vt+j1vuTK5DgVfVUoTjVe+y3/LxMxY2GgU+CSLy4cpfsYorRXuXIOi0Vt40h67uZFTdIo6nLaZcwUJWAzwNS0tBnqqKzQDnjdG/iPyZxo46HaKUpbvYkj8qYRTZsBhge+JHhZyh0x9b95JqjVJkT084kZIPwu/mPWqPgfQ5jXh2+92Ay7HedfAgwA6KDWafb4w3cAAAAASUVORK5CYII=");
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUM2OEZDQTg4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUM2OEZDQTk4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQzY4RkNBNjhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQzY4RkNBNzhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pgd7PfIAAAGmSURBVHjaYvr//z8DJZiJgUIANoCRkREb9gLiSVAaQx4OQM7AAkwd7XU2/v++/rOttdYGEB9dASEvOMydGKfH8Gv/p4XTkvRBfLxeQAP+1cUhXopyvzhP7P/IoSj7g7Mw09cNKO6J1QQ0L4gICPIv/veg/8W+JdFvQNLHVsW9/nmn9zk7B+cCkDwhL7gt6knSZnx9/LuCEOcvkIAMP+cvto9nfqyZmmUAksfnBUtbM60gX/3/kgyv3/xSFOL5DZT+L8vP+Yfh5cvfPvp/xUHyQHXGyAYwgpwBjZYFT3Y1OEl/OfCH4ffv3wzc4iwMvNIsDJ+f/mH4+vIPAxsb631WW0Yln6ZpQLXdMK/DXGDflh+sIv37EivD5x//Gb7+YWT4y86sl7BCCkSD+Z++/1dkvsFRl+HnD1Rvje4F8whjMXmGj58YGf5zsDMwcnAwfPvKcml62DsQDeaDxN+/Y0qwlpEHqrdB94IRNIDUgfgfKJChGK4OikEW3gTiXUB950ASLFAF54AC94A0G9QAfOnmF9DCDzABFqS08IHYDIScdijOjQABBgC+/9awBH96jwAAAABJRU5ErkJggg==");
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==");
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_info {
|
||||
background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQAAAAAAEFBQVJSUl5eXmRkZGtra39/f4WFhYmJiZGRkaampry8vMPDw8zMzNXV1dzc3OTk5Orq6vDw8P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABQALAAAAAAQABAAAAUuICWOZGmeaBml5XGwFCQSBGyXRSAwtqQIiRuiwIM5BoYVbEFIyGCQoeJGrVptIQA7");
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=");
|
||||
background-position: 2px center;
|
||||
}
|
||||
.ace_dark .ace_gutter-cell.ace_info {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRTk5MTVGREIxNDkxMUUxOTc5Q0FFREQyMTNGMjBFQyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRTk5MTVGRUIxNDkxMUUxOTc5Q0FFREQyMTNGMjBFQyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZFOTkxNUZCQjE0OTExRTE5NzlDQUVERDIxM0YyMEVDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkZFOTkxNUZDQjE0OTExRTE5NzlDQUVERDIxM0YyMEVDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+SIDkjAAAAJ1JREFUeNpi/P//PwMlgImBQkB7A6qrq/+DMC55FkIGKCoq4pVnpFkgTp069f/+/fv/r1u37r+tre1/kg0A+ptn9uzZYLaRkRHpLvjw4cNXWVlZhufPnzOcO3eOdAO0tbVPAjHDmzdvGA4fPsxIsgGSkpJmv379Ynj37h2DjIyMCMkG3LhxQ/T27dsMampqDHZ2dq/pH41DxwCAAAMAFdc68dUsFZgAAAAASUVORK5CYII=");
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");
|
||||
}
|
||||
|
||||
.ace_scrollbar {
|
||||
position: absolute;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
.ace_scrollbar-inner {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
cursor: text;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.ace_scrollbar-v{
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.ace_scrollbar-h {
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@@ -93,22 +138,29 @@
|
||||
resize: none;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
font: inherit;
|
||||
padding: 0 1px;
|
||||
margin: 0 -1px;
|
||||
text-indent: -1em;
|
||||
-ms-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.ace_text-input.ace_composition {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
z-index: 1000;
|
||||
opacity: 1;
|
||||
border: solid lightgray 1px;
|
||||
margin: -1px
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
.ace_layer {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
white-space: pre;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
-moz-box-sizing: border-box;
|
||||
@@ -127,7 +179,6 @@
|
||||
}
|
||||
|
||||
.ace_text-layer {
|
||||
color: black;
|
||||
font: inherit !important;
|
||||
}
|
||||
|
||||
@@ -146,6 +197,16 @@
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
border-left: 2px solid
|
||||
}
|
||||
|
||||
.ace_slim-cursors .ace_cursor {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.ace_overwrite-cursors .ace_cursor {
|
||||
border-left-width: 0;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.ace_hidden-cursors .ace_cursor {
|
||||
@@ -153,26 +214,15 @@
|
||||
}
|
||||
|
||||
.ace_smooth-blinking .ace_cursor {
|
||||
-moz-transition: opacity 0.18s;
|
||||
-webkit-transition: opacity 0.18s;
|
||||
-o-transition: opacity 0.18s;
|
||||
-ms-transition: opacity 0.18s;
|
||||
transition: opacity 0.18s;
|
||||
}
|
||||
|
||||
.ace_cursor[style*="opacity: 0"]{
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
||||
}
|
||||
|
||||
.ace_editor.ace_multiselect .ace_cursor {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.ace_line {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_step {
|
||||
.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
}
|
||||
@@ -211,15 +261,13 @@
|
||||
vertical-align: middle;
|
||||
|
||||
background-image:
|
||||
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82"),
|
||||
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%3AIDAT8%11c%FC%FF%FF%7F%18%03%1A%60%01%F2%3F%A0%891%80%04%FF%11-%F8%17%9BJ%E2%05%B1ZD%81v%26t%E7%80%F8%A3%82h%A12%1A%20%A3%01%02%0F%01%BA%25%06%00%19%C0%0D%AEF%D5%3ES%00%00%00%00IEND%AEB%60%82");
|
||||
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),
|
||||
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=");
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
background-position: center center, top left;
|
||||
color: transparent;
|
||||
|
||||
border: 1px solid black;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
|
||||
cursor: pointer;
|
||||
@@ -231,31 +279,33 @@
|
||||
|
||||
.ace_fold:hover{
|
||||
background-image:
|
||||
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82"),
|
||||
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%003IDAT8%11c%FC%FF%FF%7F%3E%03%1A%60%01%F2%3F%A3%891%80%04%FFQ%26%F8w%C0%B43%A1%DB%0C%E2%8F%0A%A2%85%CAh%80%8C%06%08%3C%04%E8%96%18%00%A3S%0D%CD%CF%D8%C1%9D%00%00%00%00IEND%AEB%60%82");
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
background-position: center center, top left;
|
||||
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),
|
||||
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC");
|
||||
}
|
||||
|
||||
.ace_editor.ace_dragging .ace_content {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.ace_gutter-tooltip {
|
||||
background-color: #FFFFD5;
|
||||
.ace_tooltip {
|
||||
background-color: #FFF;
|
||||
background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1));
|
||||
background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));
|
||||
border: 1px solid gray;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);
|
||||
border-radius: 1px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
color: black;
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
position: absolute;
|
||||
z-index: 300;
|
||||
max-width: 100%;
|
||||
padding: 3px 4px;
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
white-space: pre-line;
|
||||
white-space: pre;
|
||||
word-wrap: break-word;
|
||||
line-height: normal;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
letter-spacing: normal;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ace_folding-enabled > .ace_gutter-cell {
|
||||
@@ -268,40 +318,41 @@
|
||||
box-sizing: border-box;
|
||||
|
||||
margin: 0 -12px 0 1px;
|
||||
display: inline-block;
|
||||
display: none;
|
||||
width: 11px;
|
||||
vertical-align: top;
|
||||
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAe%8A%B1%0D%000%0C%C2%F2%2CK%96%BC%D0%8F9%81%88H%E9%D0%0E%96%C0%10%92%3E%02%80%5E%82%E4%A9*-%EEsw%C8%CC%11%EE%96w%D8%DC%E9*Eh%0C%151(%00%00%00%00IEND%AEB%60%82");
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ace_folding-enabled .ace_fold-widget {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ace_fold-widget.ace_end {
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAm%C7%C1%09%000%08C%D1%8C%ECE%C8E(%8E%EC%02)%1EZJ%F1%C1'%04%07I%E1%E5%EE%CAL%F5%A2%99%99%22%E2%D6%1FU%B5%FE0%D9x%A7%26Wz5%0E%D5%00%00%00%00IEND%AEB%60%82");
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==");
|
||||
}
|
||||
|
||||
.ace_fold-widget.ace_closed {
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%03%00%00%00%06%08%06%00%00%00%06%E5%24%0C%00%00%009IDATx%DA5%CA%C1%09%000%08%03%C0%AC*(%3E%04%C1%0D%BA%B1%23%A4Uh%E0%20%81%C0%CC%F8%82%81%AA%A2%AArGfr%88%08%11%11%1C%DD%7D%E0%EE%5B%F6%F6%CB%B8%05Q%2F%E9tai%D9%00%00%00%00IEND%AEB%60%82");
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==");
|
||||
}
|
||||
|
||||
.ace_fold-widget:hover {
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.ace_fold-widget:active {
|
||||
border: 1px solid rgba(0, 0, 0, 0.4);
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
/**
|
||||
@@ -321,32 +372,22 @@
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.ace_dark .ace_fold-widget:active {
|
||||
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ace_fold-widget.ace_invalid {
|
||||
background-color: #FFB4B4;
|
||||
border-color: #DE5555;
|
||||
}
|
||||
|
||||
.ace_fade-fold-widgets .ace_fold-widget {
|
||||
-moz-transition: opacity 0.4s ease 0.05s;
|
||||
-webkit-transition: opacity 0.4s ease 0.05s;
|
||||
-o-transition: opacity 0.4s ease 0.05s;
|
||||
-ms-transition: opacity 0.4s ease 0.05s;
|
||||
transition: opacity 0.4s ease 0.05s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.ace_fade-fold-widgets:hover .ace_fold-widget {
|
||||
-moz-transition: opacity 0.05s ease 0.05s;
|
||||
-webkit-transition: opacity 0.05s ease 0.05s;
|
||||
-o-transition: opacity 0.05s ease 0.05s;
|
||||
-ms-transition: opacity 0.05s ease 0.05s;
|
||||
transition: opacity 0.05s ease 0.05s;
|
||||
opacity:1;
|
||||
}
|
||||
@@ -366,3 +407,16 @@
|
||||
.ace_italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
.ace_error-marker {
|
||||
background-color: rgba(255, 0, 0,0.2);
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.ace_highlight-marker {
|
||||
background-color: rgba(255, 255, 0,0.2);
|
||||
position: absolute;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
@@ -56,10 +56,10 @@ var Document = function(text) {
|
||||
|
||||
// There has to be one line at least in the document. If you pass an empty
|
||||
// string to the insert function, nothing will happen. Workaround.
|
||||
if (text.length == 0) {
|
||||
if (text.length === 0) {
|
||||
this.$lines = [""];
|
||||
} else if (Array.isArray(text)) {
|
||||
this.insertLines(0, text);
|
||||
this._insertLines(0, text);
|
||||
} else {
|
||||
this.insert({row: 0, column:0}, text);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ var Document = function(text) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all the lines in the document as a single string, split by the new line character.
|
||||
* Returns all the lines in the document as a single string, joined by the new line character.
|
||||
**/
|
||||
this.getValue = function() {
|
||||
return this.getAllLines().join(this.getNewLineCharacter());
|
||||
@@ -92,7 +92,6 @@ var Document = function(text) {
|
||||
* @param {Number} row The row number to use
|
||||
* @param {Number} column The column number to use
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.createAnchor = function(row, column) {
|
||||
return new Anchor(this, row, column);
|
||||
@@ -105,28 +104,23 @@ var Document = function(text) {
|
||||
* @param {String} text The text to work with
|
||||
* @returns {String} A String array, with each index containing a piece of the original `text` string.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
// check for IE split bug
|
||||
if ("aaa".split(/a/).length == 0)
|
||||
if ("aaa".split(/a/).length === 0)
|
||||
this.$split = function(text) {
|
||||
return text.replace(/\r\n|\r/g, "\n").split("\n");
|
||||
}
|
||||
};
|
||||
else
|
||||
this.$split = function(text) {
|
||||
return text.split(/\r\n|\r|\n/);
|
||||
};
|
||||
|
||||
|
||||
|
||||
this.$detectNewLine = function(text) {
|
||||
var match = text.match(/^.*?(\r\n|\r|\n)/m);
|
||||
if (match) {
|
||||
this.$autoNewLine = match[1];
|
||||
} else {
|
||||
this.$autoNewLine = "\n";
|
||||
}
|
||||
this.$autoNewLine = match ? match[1] : "\n";
|
||||
this._signal("changeNewLineMode");
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -135,41 +129,36 @@ var Document = function(text) {
|
||||
* If `newLineMode == unix`, `\n` is returned.
|
||||
* If `newLineMode == auto`, the value of `autoNewLine` is returned.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getNewLineCharacter = function() {
|
||||
switch (this.$newLineMode) {
|
||||
case "windows":
|
||||
return "\r\n";
|
||||
|
||||
case "unix":
|
||||
return "\n";
|
||||
|
||||
case "auto":
|
||||
return this.$autoNewLine;
|
||||
default:
|
||||
return this.$autoNewLine || "\n";
|
||||
}
|
||||
};
|
||||
|
||||
this.$autoNewLine = "\n";
|
||||
this.$autoNewLine = "";
|
||||
this.$newLineMode = "auto";
|
||||
/**
|
||||
* [Sets the new line mode.]{: #Document.setNewLineMode.desc}
|
||||
* @param {String} newLineMode [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param}
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.setNewLineMode = function(newLineMode) {
|
||||
if (this.$newLineMode === newLineMode)
|
||||
return;
|
||||
|
||||
this.$newLineMode = newLineMode;
|
||||
this._signal("changeNewLineMode");
|
||||
};
|
||||
|
||||
/**
|
||||
* [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode}
|
||||
* @returns String
|
||||
* @returns {String}
|
||||
**/
|
||||
this.getNewLineMode = function() {
|
||||
return this.$newLineMode;
|
||||
@@ -179,8 +168,6 @@ var Document = function(text) {
|
||||
* Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`).
|
||||
* @param {String} text The text to check
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.isNewLine = function(text) {
|
||||
return (text == "\r\n" || text == "\r" || text == "\n");
|
||||
@@ -190,8 +177,6 @@ var Document = function(text) {
|
||||
* Returns a verbatim copy of the given line as it is in the document
|
||||
* @param {Number} row The row index to retrieve
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getLine = function(row) {
|
||||
return this.$lines[row] || "";
|
||||
@@ -202,15 +187,13 @@ var Document = function(text) {
|
||||
* @param {Number} firstRow The first row index to retrieve
|
||||
* @param {Number} lastRow The final row index to retrieve
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getLines = function(firstRow, lastRow) {
|
||||
return this.$lines.slice(firstRow, lastRow + 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all lines in the document as string array. Warning: The caller should not modify this array!
|
||||
* Returns all lines in the document as string array.
|
||||
**/
|
||||
this.getAllLines = function() {
|
||||
return this.getLines(0, this.getLength());
|
||||
@@ -227,19 +210,19 @@ var Document = function(text) {
|
||||
* [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc}
|
||||
* @param {Range} range The range to work with
|
||||
*
|
||||
*
|
||||
* @returns {String}
|
||||
**/
|
||||
this.getTextRange = function(range) {
|
||||
if (range.start.row == range.end.row) {
|
||||
return this.$lines[range.start.row].substring(range.start.column,
|
||||
range.end.column);
|
||||
return this.getLine(range.start.row)
|
||||
.substring(range.start.column, range.end.column);
|
||||
}
|
||||
else {
|
||||
var lines = this.getLines(range.start.row+1, range.end.row-1);
|
||||
lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column));
|
||||
lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column));
|
||||
var lines = this.getLines(range.start.row, range.end.row);
|
||||
lines[0] = (lines[0] || "").substring(range.start.column);
|
||||
var l = lines.length - 1;
|
||||
if (range.end.row - range.start.row == l)
|
||||
lines[l] = lines[l].substring(0, range.end.column);
|
||||
return lines.join(this.getNewLineCharacter());
|
||||
}
|
||||
};
|
||||
|
||||
this.$clipPosition = function(position) {
|
||||
@@ -247,13 +230,14 @@ var Document = function(text) {
|
||||
if (position.row >= length) {
|
||||
position.row = Math.max(0, length - 1);
|
||||
position.column = this.getLine(length-1).length;
|
||||
}
|
||||
} else if (position.row < 0)
|
||||
position.row = 0;
|
||||
return position;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts a block of `text` and the indicated `position`.
|
||||
* @param {Object} position The position to start inserting at
|
||||
* Inserts a block of `text` at the indicated `position`.
|
||||
* @param {Object} position The position to start inserting at; it's an object that looks like `{ row: row, column: column}`
|
||||
* @param {String} text A chunk of text to insert
|
||||
* @returns {Object} The position ({row, column}) of the last line of `text`. If the length of `text` is 0, this function simply returns `position`.
|
||||
*
|
||||
@@ -275,7 +259,7 @@ var Document = function(text) {
|
||||
position = this.insertInLine(position, firstLine);
|
||||
if (lastLine !== null) {
|
||||
position = this.insertNewLine(position); // terminate first line
|
||||
position = this.insertLines(position.row, lines);
|
||||
position = this._insertLines(position.row, lines);
|
||||
position = this.insertInLine(position, lastLine || "");
|
||||
}
|
||||
return position;
|
||||
@@ -317,19 +301,22 @@ var Document = function(text) {
|
||||
* {row: row, column: 0}
|
||||
* ```
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.insertLines = function(row, lines) {
|
||||
if (row >= this.getLength())
|
||||
return this.insert({row: row, column: 0}, "\n" + lines.join("\n"));
|
||||
return this._insertLines(Math.max(row, 0), lines);
|
||||
};
|
||||
this._insertLines = function(row, lines) {
|
||||
if (lines.length == 0)
|
||||
return {row: row, column: 0};
|
||||
|
||||
// apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF)
|
||||
// to circumvent that we have to break huge inserts into smaller chunks here
|
||||
if (lines.length > 0xFFFF) {
|
||||
var end = this.insertLines(row, lines.slice(0xFFFF));
|
||||
lines = lines.slice(0, 0xFFFF);
|
||||
while (lines.length > 0xF000) {
|
||||
var end = this._insertLines(row, lines.slice(0, 0xF000));
|
||||
lines = lines.slice(0xF000);
|
||||
row = end.row;
|
||||
}
|
||||
|
||||
var args = [row, 0];
|
||||
@@ -342,8 +329,8 @@ var Document = function(text) {
|
||||
range: range,
|
||||
lines: lines
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
return end || range.end;
|
||||
this._signal("change", { data: delta });
|
||||
return range.end;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -372,14 +359,14 @@ var Document = function(text) {
|
||||
range: Range.fromPoints(position, end),
|
||||
text: this.getNewLineCharacter()
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
this._signal("change", { data: delta });
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event.
|
||||
* @param {Object} position The position to insert at
|
||||
* @param {Object} position The position to insert at; it's an object that looks like `{ row: row, column: column}`
|
||||
* @param {String} text A chunk of text
|
||||
* @returns {Object} Returns an object containing the final row and column, like this:
|
||||
* ```
|
||||
@@ -406,7 +393,7 @@ var Document = function(text) {
|
||||
range: Range.fromPoints(position, end),
|
||||
text: text
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
this._signal("change", { data: delta });
|
||||
|
||||
return end;
|
||||
};
|
||||
@@ -416,9 +403,10 @@ var Document = function(text) {
|
||||
* @param {Range} range A specified Range to remove
|
||||
* @returns {Object} Returns the new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.remove = function(range) {
|
||||
if (!(range instanceof Range))
|
||||
range = Range.fromPoints(range.start, range.end);
|
||||
// clip to document
|
||||
range.start = this.$clipPosition(range.start);
|
||||
range.end = this.$clipPosition(range.end);
|
||||
@@ -437,7 +425,7 @@ var Document = function(text) {
|
||||
this.removeInLine(lastRow, 0, range.end.column);
|
||||
|
||||
if (lastFullRow >= firstFullRow)
|
||||
this.removeLines(firstFullRow, lastFullRow);
|
||||
this._removeLines(firstFullRow, lastFullRow);
|
||||
|
||||
if (firstFullRow != firstRow) {
|
||||
this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
|
||||
@@ -457,7 +445,6 @@ var Document = function(text) {
|
||||
* @param {Number} endColumn The column to stop removing at
|
||||
* @returns {Object} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.<br/>If `startColumn` is equal to `endColumn`, this function returns nothing.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.removeInLine = function(row, startColumn, endColumn) {
|
||||
if (startColumn == endColumn)
|
||||
@@ -474,7 +461,7 @@ var Document = function(text) {
|
||||
range: range,
|
||||
text: removed
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
this._signal("change", { data: delta });
|
||||
return range.start;
|
||||
};
|
||||
|
||||
@@ -484,9 +471,14 @@ var Document = function(text) {
|
||||
* @param {Number} lastRow The last row to be removed
|
||||
* @returns {[String]} Returns all the removed lines.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.removeLines = function(firstRow, lastRow) {
|
||||
if (firstRow < 0 || lastRow >= this.getLength())
|
||||
return this.remove(new Range(firstRow, 0, lastRow + 1, 0));
|
||||
return this._removeLines(firstRow, lastRow);
|
||||
};
|
||||
|
||||
this._removeLines = function(firstRow, lastRow) {
|
||||
var range = new Range(firstRow, 0, lastRow + 1, 0);
|
||||
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
|
||||
|
||||
@@ -496,7 +488,7 @@ var Document = function(text) {
|
||||
nl: this.getNewLineCharacter(),
|
||||
lines: removed
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
this._signal("change", { data: delta });
|
||||
return removed;
|
||||
};
|
||||
|
||||
@@ -519,7 +511,7 @@ var Document = function(text) {
|
||||
range: range,
|
||||
text: this.getNewLineCharacter()
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
this._signal("change", { data: delta });
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -531,9 +523,10 @@ var Document = function(text) {
|
||||
* If the text and range are empty, this function returns an object containing the current `range.start` value.
|
||||
* If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.replace = function(range, text) {
|
||||
if (!(range instanceof Range))
|
||||
range = Range.fromPoints(range.start, range.end);
|
||||
if (text.length == 0 && range.isEmpty())
|
||||
return range.start;
|
||||
|
||||
@@ -554,7 +547,7 @@ var Document = function(text) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
* Applies all the changes previously accumulated. These can be either `'insertText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
**/
|
||||
this.applyDeltas = function(deltas) {
|
||||
for (var i=0; i<deltas.length; i++) {
|
||||
@@ -566,14 +559,14 @@ var Document = function(text) {
|
||||
else if (delta.action == "insertText")
|
||||
this.insert(range.start, delta.text);
|
||||
else if (delta.action == "removeLines")
|
||||
this.removeLines(range.start.row, range.end.row - 1);
|
||||
this._removeLines(range.start.row, range.end.row - 1);
|
||||
else if (delta.action == "removeText")
|
||||
this.remove(range);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverts any changes previously applied. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
* Reverts any changes previously applied. These can be either `'insertText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
**/
|
||||
this.revertDeltas = function(deltas) {
|
||||
for (var i=deltas.length-1; i>=0; i--) {
|
||||
@@ -582,16 +575,70 @@ var Document = function(text) {
|
||||
var range = Range.fromPoints(delta.range.start, delta.range.end);
|
||||
|
||||
if (delta.action == "insertLines")
|
||||
this.removeLines(range.start.row, range.end.row - 1);
|
||||
this._removeLines(range.start.row, range.end.row - 1);
|
||||
else if (delta.action == "insertText")
|
||||
this.remove(range);
|
||||
else if (delta.action == "removeLines")
|
||||
this.insertLines(range.start.row, delta.lines);
|
||||
this._insertLines(range.start.row, delta.lines);
|
||||
else if (delta.action == "removeText")
|
||||
this.insert(range.start, delta.text);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts an index position in a document to a `{row, column}` object.
|
||||
*
|
||||
* Index refers to the "absolute position" of a character in the document. For example:
|
||||
*
|
||||
* ```javascript
|
||||
* var x = 0; // 10 characters, plus one for newline
|
||||
* var y = -1;
|
||||
* ```
|
||||
*
|
||||
* Here, `y` is an index 15: 11 characters for the first row, and 5 characters until `y` in the second.
|
||||
*
|
||||
* @param {Number} index An index to convert
|
||||
* @param {Number} startRow=0 The row from which to start the conversion
|
||||
* @returns {Object} A `{row, column}` object of the `index` position
|
||||
*/
|
||||
this.indexToPosition = function(index, startRow) {
|
||||
var lines = this.$lines || this.getAllLines();
|
||||
var newlineLength = this.getNewLineCharacter().length;
|
||||
for (var i = startRow || 0, l = lines.length; i < l; i++) {
|
||||
index -= lines[i].length + newlineLength;
|
||||
if (index < 0)
|
||||
return {row: i, column: index + lines[i].length + newlineLength};
|
||||
}
|
||||
return {row: l-1, column: lines[l-1].length};
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the `{row, column}` position in a document to the character's index.
|
||||
*
|
||||
* Index refers to the "absolute position" of a character in the document. For example:
|
||||
*
|
||||
* ```javascript
|
||||
* var x = 0; // 10 characters, plus one for newline
|
||||
* var y = -1;
|
||||
* ```
|
||||
*
|
||||
* Here, `y` is an index 15: 11 characters for the first row, and 5 characters until `y` in the second.
|
||||
*
|
||||
* @param {Object} pos The `{row, column}` to convert
|
||||
* @param {Number} startRow=0 The row from which to start the conversion
|
||||
* @returns {Number} The index position in the document
|
||||
*/
|
||||
this.positionToIndex = function(pos, startRow) {
|
||||
var lines = this.$lines || this.getAllLines();
|
||||
var newlineLength = this.getNewLineCharacter().length;
|
||||
var index = 0;
|
||||
var row = Math.min(pos.row, lines.length);
|
||||
for (var i = startRow || 0; i < row; ++i)
|
||||
index += lines[i].length + newlineLength;
|
||||
|
||||
return index + pos.column;
|
||||
};
|
||||
|
||||
}).call(Document.prototype);
|
||||
|
||||
exports.Document = Document;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,10 +37,10 @@ var Range = require("../range").Range;
|
||||
|
||||
function BracketMatch() {
|
||||
|
||||
this.findMatchingBracket = function(position, char) {
|
||||
this.findMatchingBracket = function(position, chr) {
|
||||
if (position.column == 0) return null;
|
||||
|
||||
var charBeforeCursor = char || this.getLine(position.row).charAt(position.column-1);
|
||||
var charBeforeCursor = chr || this.getLine(position.row).charAt(position.column-1);
|
||||
if (charBeforeCursor == "") return null;
|
||||
|
||||
var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/);
|
||||
@@ -117,6 +117,7 @@ function BracketMatch() {
|
||||
typeRe = new RegExp(
|
||||
"(\\.?" +
|
||||
token.type.replace(".", "\\.").replace("rparen", ".paren")
|
||||
.replace(/\b(?:end|start|begin)\b/, "")
|
||||
+ ")+"
|
||||
);
|
||||
}
|
||||
@@ -173,6 +174,7 @@ function BracketMatch() {
|
||||
typeRe = new RegExp(
|
||||
"(\\.?" +
|
||||
token.type.replace(".", "\\.").replace("lparen", ".paren")
|
||||
.replace(/\b(?:end|start|begin)\b/, "")
|
||||
+ ")+"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Range = require("../range").Range;
|
||||
var RangeList = require("../range_list").RangeList;
|
||||
var oop = require("../lib/oop")
|
||||
/*
|
||||
* Simple fold-data struct.
|
||||
**/
|
||||
@@ -42,9 +45,11 @@ var Fold = exports.Fold = function(range, placeholder) {
|
||||
this.end = range.end;
|
||||
|
||||
this.sameRow = range.start.row == range.end.row;
|
||||
this.subFolds = [];
|
||||
this.subFolds = this.ranges = [];
|
||||
};
|
||||
|
||||
oop.inherits(Fold, RangeList);
|
||||
|
||||
(function() {
|
||||
|
||||
this.toString = function() {
|
||||
@@ -64,17 +69,21 @@ var Fold = exports.Fold = function(range, placeholder) {
|
||||
this.subFolds.forEach(function(subFold) {
|
||||
fold.subFolds.push(subFold.clone());
|
||||
});
|
||||
fold.collapseChildren = this.collapseChildren;
|
||||
return fold;
|
||||
};
|
||||
|
||||
this.addSubFold = function(fold) {
|
||||
if (this.range.isEqual(fold))
|
||||
return this;
|
||||
return;
|
||||
|
||||
if (!this.range.containsRange(fold))
|
||||
throw "A fold can't intersect already existing fold" + fold.range + this.range;
|
||||
throw new Error("A fold can't intersect already existing fold" + fold.range + this.range);
|
||||
|
||||
var row = fold.range.start.row, column = fold.range.start.column;
|
||||
// transform fold to local coordinates
|
||||
consumeRange(fold, this.start);
|
||||
|
||||
var row = fold.start.row, column = fold.start.column;
|
||||
for (var i = 0, cmp = -1; i < this.subFolds.length; i++) {
|
||||
cmp = this.subFolds[i].range.compare(row, column);
|
||||
if (cmp != 1)
|
||||
@@ -95,7 +104,7 @@ var Fold = exports.Fold = function(range, placeholder) {
|
||||
var afterEnd = this.subFolds[j];
|
||||
|
||||
if (cmp == 0)
|
||||
throw "A fold can't intersect already existing fold" + fold.range + this.range;
|
||||
throw new Error("A fold can't intersect already existing fold" + fold.range + this.range);
|
||||
|
||||
var consumedFolds = this.subFolds.splice(i, j - i, fold);
|
||||
fold.setFoldLine(this.foldLine);
|
||||
@@ -103,6 +112,29 @@ var Fold = exports.Fold = function(range, placeholder) {
|
||||
return fold;
|
||||
};
|
||||
|
||||
this.restoreRange = function(range) {
|
||||
return restoreRange(range, this.start);
|
||||
};
|
||||
|
||||
}).call(Fold.prototype);
|
||||
|
||||
function consumePoint(point, anchor) {
|
||||
point.row -= anchor.row;
|
||||
if (point.row == 0)
|
||||
point.column -= anchor.column;
|
||||
}
|
||||
function consumeRange(range, anchor) {
|
||||
consumePoint(range.start, anchor);
|
||||
consumePoint(range.end, anchor);
|
||||
}
|
||||
function restorePoint(point, anchor) {
|
||||
if (point.row == 0)
|
||||
point.column += anchor.column;
|
||||
point.row += anchor.row;
|
||||
}
|
||||
function restoreRange(range, anchor) {
|
||||
restorePoint(range.start, anchor);
|
||||
restorePoint(range.end, anchor);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -44,7 +44,7 @@ function FoldLine(foldData, folds) {
|
||||
folds = this.folds = [ folds ];
|
||||
}
|
||||
|
||||
var last = folds[folds.length - 1]
|
||||
var last = folds[folds.length - 1];
|
||||
this.range = new Range(folds[0].start.row, folds[0].start.column,
|
||||
last.end.row, last.end.column);
|
||||
this.start = this.range.start;
|
||||
@@ -66,12 +66,12 @@ function FoldLine(foldData, folds) {
|
||||
fold.start.row += shift;
|
||||
fold.end.row += shift;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.addFold = function(fold) {
|
||||
if (fold.sameRow) {
|
||||
if (fold.start.row < this.startRow || fold.endRow > this.endRow) {
|
||||
throw "Can't add a fold to this FoldLine as it has no connection";
|
||||
throw new Error("Can't add a fold to this FoldLine as it has no connection");
|
||||
}
|
||||
this.folds.push(fold);
|
||||
this.folds.sort(function(a, b) {
|
||||
@@ -93,20 +93,20 @@ function FoldLine(foldData, folds) {
|
||||
this.start.row = fold.start.row;
|
||||
this.start.column = fold.start.column;
|
||||
} else {
|
||||
throw "Trying to add fold to FoldRow that doesn't have a matching row";
|
||||
throw new Error("Trying to add fold to FoldRow that doesn't have a matching row");
|
||||
}
|
||||
fold.foldLine = this;
|
||||
}
|
||||
};
|
||||
|
||||
this.containsRow = function(row) {
|
||||
return row >= this.start.row && row <= this.end.row;
|
||||
}
|
||||
};
|
||||
|
||||
this.walk = function(callback, endRow, endColumn) {
|
||||
var lastEnd = 0,
|
||||
folds = this.folds,
|
||||
fold,
|
||||
comp, stop, isNewRow = true;
|
||||
cmp, stop, isNewRow = true;
|
||||
|
||||
if (endRow == null) {
|
||||
endRow = this.end.row;
|
||||
@@ -116,9 +116,9 @@ function FoldLine(foldData, folds) {
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
fold = folds[i];
|
||||
|
||||
comp = fold.range.compareStart(endRow, endColumn);
|
||||
cmp = fold.range.compareStart(endRow, endColumn);
|
||||
// This fold is after the endRow/Column.
|
||||
if (comp == -1) {
|
||||
if (cmp == -1) {
|
||||
callback(null, endRow, endColumn, lastEnd, isNewRow);
|
||||
return;
|
||||
}
|
||||
@@ -127,8 +127,8 @@ function FoldLine(foldData, folds) {
|
||||
stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd);
|
||||
|
||||
// If the user requested to stop the walk or endRow/endColumn is
|
||||
// inside of this fold (comp == 0), then end here.
|
||||
if (stop || comp == 0) {
|
||||
// inside of this fold (cmp == 0), then end here.
|
||||
if (stop || cmp === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ function FoldLine(foldData, folds) {
|
||||
lastEnd = fold.end.column;
|
||||
}
|
||||
callback(null, endRow, endColumn, lastEnd, isNewRow);
|
||||
}
|
||||
};
|
||||
|
||||
this.getNextFoldTo = function(row, column) {
|
||||
var fold, cmp;
|
||||
@@ -150,15 +150,15 @@ function FoldLine(foldData, folds) {
|
||||
fold: fold,
|
||||
kind: "after"
|
||||
};
|
||||
} else if (cmp == 0) {
|
||||
} else if (cmp === 0) {
|
||||
return {
|
||||
fold: fold,
|
||||
kind: "inside"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
this.addRemoveChars = function(row, column, len) {
|
||||
var ret = this.getNextFoldTo(row, column),
|
||||
@@ -175,7 +175,7 @@ function FoldLine(foldData, folds) {
|
||||
} else if (fold.start.row == row) {
|
||||
folds = this.folds;
|
||||
var i = folds.indexOf(fold);
|
||||
if (i == 0) {
|
||||
if (i === 0) {
|
||||
this.start.column += len;
|
||||
}
|
||||
for (i; i < folds.length; i++) {
|
||||
@@ -189,16 +189,18 @@ function FoldLine(foldData, folds) {
|
||||
this.end.column += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.split = function(row, column) {
|
||||
var fold = this.getNextFoldTo(row, column).fold,
|
||||
folds = this.folds;
|
||||
var pos = this.getNextFoldTo(row, column);
|
||||
|
||||
if (!pos || pos.kind == "inside")
|
||||
return null;
|
||||
|
||||
var fold = pos.fold;
|
||||
var folds = this.folds;
|
||||
var foldData = this.foldData;
|
||||
|
||||
if (!fold) {
|
||||
return null;
|
||||
}
|
||||
var i = folds.indexOf(fold);
|
||||
var foldBefore = folds[i - 1];
|
||||
this.end.row = foldBefore.end.row;
|
||||
@@ -211,7 +213,7 @@ function FoldLine(foldData, folds) {
|
||||
var newFoldLine = new FoldLine(foldData, folds);
|
||||
foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine);
|
||||
return newFoldLine;
|
||||
}
|
||||
};
|
||||
|
||||
this.merge = function(foldLineNext) {
|
||||
var folds = foldLineNext.folds;
|
||||
@@ -222,7 +224,7 @@ function FoldLine(foldData, folds) {
|
||||
// it's merged now with foldLineNext.
|
||||
var foldData = this.foldData;
|
||||
foldData.splice(foldData.indexOf(foldLineNext), 1);
|
||||
}
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
var ret = [this.range.toString() + ": [" ];
|
||||
@@ -230,13 +232,12 @@ function FoldLine(foldData, folds) {
|
||||
this.folds.forEach(function(fold) {
|
||||
ret.push(" " + fold.toString());
|
||||
});
|
||||
ret.push("]")
|
||||
ret.push("]");
|
||||
return ret.join("\n");
|
||||
}
|
||||
};
|
||||
|
||||
this.idxToPosition = function(idx) {
|
||||
var lastFoldEndColumn = 0;
|
||||
var fold;
|
||||
|
||||
for (var i = 0; i < this.folds.length; i++) {
|
||||
var fold = this.folds[i];
|
||||
@@ -261,7 +262,7 @@ function FoldLine(foldData, folds) {
|
||||
row: this.end.row,
|
||||
column: this.end.column + idx
|
||||
};
|
||||
}
|
||||
};
|
||||
}).call(FoldLine.prototype);
|
||||
|
||||
exports.FoldLine = FoldLine;
|
||||
|
||||
@@ -66,7 +66,6 @@ function Folding() {
|
||||
*
|
||||
*/
|
||||
this.getFoldsInRange = function(range) {
|
||||
range = range.clone();
|
||||
var start = range.start;
|
||||
var end = range.end;
|
||||
var foldLines = this.$foldData;
|
||||
@@ -104,9 +103,24 @@ function Folding() {
|
||||
foundFolds.push(fold);
|
||||
}
|
||||
}
|
||||
start.column -= 1;
|
||||
end.column += 1;
|
||||
|
||||
return foundFolds;
|
||||
};
|
||||
|
||||
this.getFoldsInRangeList = function(ranges) {
|
||||
if (Array.isArray(ranges)) {
|
||||
var folds = [];
|
||||
ranges.forEach(function(range) {
|
||||
folds = folds.concat(this.getFoldsInRange(range));
|
||||
}, this);
|
||||
} else {
|
||||
var folds = this.getFoldsInRange(ranges);
|
||||
}
|
||||
return folds;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns all folds in the document
|
||||
*/
|
||||
@@ -114,18 +128,9 @@ function Folding() {
|
||||
var folds = [];
|
||||
var foldLines = this.$foldData;
|
||||
|
||||
function addFold(fold) {
|
||||
folds.push(fold);
|
||||
if (!fold.subFolds)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < fold.subFolds.length; i++)
|
||||
addFold(fold.subFolds[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < foldLines.length; i++)
|
||||
for (var j = 0; j < foldLines[i].folds.length; j++)
|
||||
addFold(foldLines[i].folds[j]);
|
||||
folds.push(foldLines[i].folds[j]);
|
||||
|
||||
return folds;
|
||||
};
|
||||
@@ -249,7 +254,7 @@ function Folding() {
|
||||
return foldLine;
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* Adds a new fold.
|
||||
*
|
||||
* @returns
|
||||
@@ -263,9 +268,10 @@ function Folding() {
|
||||
|
||||
if (placeholder instanceof Fold)
|
||||
fold = placeholder;
|
||||
else
|
||||
else {
|
||||
fold = new Fold(range, placeholder);
|
||||
|
||||
fold.collapseChildren = range.collapseChildren;
|
||||
}
|
||||
this.$clipRangeToDocument(fold.range);
|
||||
|
||||
var startRow = fold.start.row;
|
||||
@@ -274,20 +280,20 @@ function Folding() {
|
||||
var endColumn = fold.end.column;
|
||||
|
||||
// --- Some checking ---
|
||||
if (startRow == endRow && endColumn - startColumn < 2)
|
||||
throw "The range has to be at least 2 characters width";
|
||||
if (!(startRow < endRow ||
|
||||
startRow == endRow && startColumn <= endColumn - 2))
|
||||
throw new Error("The range has to be at least 2 characters width");
|
||||
|
||||
var startFold = this.getFoldAt(startRow, startColumn, 1);
|
||||
var endFold = this.getFoldAt(endRow, endColumn, -1);
|
||||
if (startFold && endFold == startFold)
|
||||
return startFold.addSubFold(fold);
|
||||
|
||||
if (
|
||||
(startFold && !startFold.range.isStart(startRow, startColumn))
|
||||
|| (endFold && !endFold.range.isEnd(endRow, endColumn))
|
||||
) {
|
||||
throw "A fold can't intersect already existing fold" + fold.range + startFold.range;
|
||||
}
|
||||
if (startFold && !startFold.range.isStart(startRow, startColumn))
|
||||
this.removeFold(startFold);
|
||||
|
||||
if (endFold && !endFold.range.isEnd(endRow, endColumn))
|
||||
this.removeFold(endFold);
|
||||
|
||||
// Check if there are folds in the range we create the new fold for.
|
||||
var folds = this.getFoldsInRange(fold.range);
|
||||
@@ -295,7 +301,9 @@ function Folding() {
|
||||
// Remove the folds from fold data.
|
||||
this.removeFolds(folds);
|
||||
// Add the removed folds as subfolds on the new fold.
|
||||
fold.subFolds = folds;
|
||||
folds.forEach(function(subFold) {
|
||||
fold.addSubFold(subFold);
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = 0; i < foldData.length; i++) {
|
||||
@@ -304,8 +312,7 @@ function Folding() {
|
||||
foldLine.addFold(fold);
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
else if (startRow == foldLine.end.row) {
|
||||
} else if (startRow == foldLine.end.row) {
|
||||
foldLine.addFold(fold);
|
||||
added = true;
|
||||
if (!fold.sameRow) {
|
||||
@@ -318,8 +325,7 @@ function Folding() {
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (endRow <= foldLine.start.row) {
|
||||
} else if (endRow <= foldLine.start.row) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -334,7 +340,7 @@ function Folding() {
|
||||
|
||||
// Notify that fold data has changed.
|
||||
this.$modified = true;
|
||||
this._emit("changeFold", { data: fold });
|
||||
this._emit("changeFold", { data: fold, action: "add" });
|
||||
|
||||
return fold;
|
||||
};
|
||||
@@ -386,14 +392,16 @@ function Folding() {
|
||||
newFoldLine.start.column = folds[0].start.column;
|
||||
}
|
||||
|
||||
if (!this.$updating) {
|
||||
if (this.$useWrapMode)
|
||||
this.$updateWrapData(startRow, endRow);
|
||||
else
|
||||
this.$updateRowLengthCache(startRow, endRow);
|
||||
}
|
||||
|
||||
// Notify that fold data has changed.
|
||||
this.$modified = true;
|
||||
this._emit("changeFold", { data: fold });
|
||||
this._emit("changeFold", { data: fold, action: "remove" });
|
||||
};
|
||||
|
||||
this.removeFolds = function(folds) {
|
||||
@@ -413,9 +421,13 @@ function Folding() {
|
||||
|
||||
this.expandFold = function(fold) {
|
||||
this.removeFold(fold);
|
||||
fold.subFolds.forEach(function(fold) {
|
||||
this.addFold(fold);
|
||||
fold.subFolds.forEach(function(subFold) {
|
||||
fold.restoreRange(subFold);
|
||||
this.addFold(subFold);
|
||||
}, this);
|
||||
if (fold.collapseChildren > 0) {
|
||||
this.foldAll(fold.start.row+1, fold.end.row, fold.collapseChildren-1);
|
||||
}
|
||||
fold.subFolds = [];
|
||||
};
|
||||
|
||||
@@ -427,26 +439,30 @@ function Folding() {
|
||||
|
||||
this.unfold = function(location, expandInner) {
|
||||
var range, folds;
|
||||
if (location == null)
|
||||
if (location == null) {
|
||||
range = new Range(0, 0, this.getLength(), 0);
|
||||
else if (typeof location == "number")
|
||||
expandInner = true;
|
||||
} else if (typeof location == "number")
|
||||
range = new Range(location, 0, location, this.getLine(location).length);
|
||||
else if ("row" in location)
|
||||
range = Range.fromPoints(location, location);
|
||||
else
|
||||
range = location;
|
||||
|
||||
folds = this.getFoldsInRange(range);
|
||||
folds = this.getFoldsInRangeList(range);
|
||||
if (expandInner) {
|
||||
this.removeFolds(folds);
|
||||
} else {
|
||||
// TODO: might need to remove and add folds in one go instead of using
|
||||
var subFolds = folds;
|
||||
// TODO: might be better to remove and add folds in one go instead of using
|
||||
// expandFolds several times.
|
||||
while (folds.length) {
|
||||
this.expandFolds(folds);
|
||||
folds = this.getFoldsInRange(range);
|
||||
while (subFolds.length) {
|
||||
this.expandFolds(subFolds);
|
||||
subFolds = this.getFoldsInRangeList(range);
|
||||
}
|
||||
}
|
||||
if (folds.length)
|
||||
return folds;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -462,36 +478,41 @@ function Folding() {
|
||||
return foldLine ? foldLine.end.row : docRow;
|
||||
};
|
||||
|
||||
this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) {
|
||||
if (startRow == null) {
|
||||
startRow = foldLine.start.row;
|
||||
startColumn = 0;
|
||||
}
|
||||
this.getRowFoldStart = function(docRow, startFoldRow) {
|
||||
var foldLine = this.getFoldLine(docRow, startFoldRow);
|
||||
return foldLine ? foldLine.start.row : docRow;
|
||||
};
|
||||
|
||||
if (endRow == null) {
|
||||
this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) {
|
||||
if (startRow == null)
|
||||
startRow = foldLine.start.row;
|
||||
if (startColumn == null)
|
||||
startColumn = 0;
|
||||
if (endRow == null)
|
||||
endRow = foldLine.end.row;
|
||||
if (endColumn == null)
|
||||
endColumn = this.getLine(endRow).length;
|
||||
}
|
||||
|
||||
|
||||
// Build the textline using the FoldLine walker.
|
||||
var doc = this.doc;
|
||||
var textLine = "";
|
||||
|
||||
foldLine.walk(function(placeholder, row, column, lastColumn) {
|
||||
if (row < startRow) {
|
||||
if (row < startRow)
|
||||
return;
|
||||
} else if (row == startRow) {
|
||||
if (column < startColumn) {
|
||||
if (row == startRow) {
|
||||
if (column < startColumn)
|
||||
return;
|
||||
}
|
||||
lastColumn = Math.max(startColumn, lastColumn);
|
||||
}
|
||||
|
||||
if (placeholder != null) {
|
||||
textLine += placeholder;
|
||||
} else {
|
||||
textLine += doc.getLine(row).substring(lastColumn, column);
|
||||
}
|
||||
}.bind(this), endRow, endColumn);
|
||||
}, endRow, endColumn);
|
||||
return textLine;
|
||||
};
|
||||
|
||||
@@ -533,26 +554,22 @@ function Folding() {
|
||||
if (fold) {
|
||||
this.expandFold(fold);
|
||||
return;
|
||||
}
|
||||
else if (bracketPos = this.findMatchingBracket(cursor)) {
|
||||
} else if (bracketPos = this.findMatchingBracket(cursor)) {
|
||||
if (range.comparePoint(bracketPos) == 1) {
|
||||
range.end = bracketPos;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
range.start = bracketPos;
|
||||
range.start.column++;
|
||||
range.end.column--;
|
||||
}
|
||||
}
|
||||
else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) {
|
||||
} else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) {
|
||||
if (range.comparePoint(bracketPos) == 1)
|
||||
range.end = bracketPos;
|
||||
else
|
||||
range.start = bracketPos;
|
||||
|
||||
range.start.column++;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
range = this.getCommentFoldRange(cursor.row, cursor.column) || range;
|
||||
}
|
||||
} else {
|
||||
@@ -560,8 +577,7 @@ function Folding() {
|
||||
if (tryToUnfold && folds.length) {
|
||||
this.expandFolds(folds);
|
||||
return;
|
||||
}
|
||||
else if (folds.length == 1 ) {
|
||||
} else if (folds.length == 1 ) {
|
||||
fold = folds[0];
|
||||
}
|
||||
}
|
||||
@@ -617,10 +633,15 @@ function Folding() {
|
||||
}
|
||||
};
|
||||
|
||||
this.foldAll = function(startRow, endRow) {
|
||||
this.foldAll = function(startRow, endRow, depth) {
|
||||
if (depth == undefined)
|
||||
depth = 100000; // JSON.stringify doesn't hanle Infinity
|
||||
var foldWidgets = this.foldWidgets;
|
||||
if (!foldWidgets)
|
||||
return; // mode doesn't support folding
|
||||
endRow = endRow || this.getLength();
|
||||
for (var row = startRow || 0; row < endRow; row++) {
|
||||
startRow = startRow || 0;
|
||||
for (var row = startRow; row < endRow; row++) {
|
||||
if (foldWidgets[row] == null)
|
||||
foldWidgets[row] = this.getFoldWidget(row);
|
||||
if (foldWidgets[row] != "start")
|
||||
@@ -628,13 +649,23 @@ function Folding() {
|
||||
|
||||
var range = this.getFoldWidgetRange(row);
|
||||
// sometimes range can be incompatible with existing fold
|
||||
// wouldn't it be better for addFold to return null istead of throwing?
|
||||
if (range && range.end.row <= endRow) try {
|
||||
this.addFold("...", range);
|
||||
// TODO change addFold to return null istead of throwing
|
||||
if (range && range.isMultiLine()
|
||||
&& range.end.row <= endRow
|
||||
&& range.start.row >= startRow
|
||||
) {
|
||||
row = range.end.row;
|
||||
try {
|
||||
// addFold can change the range
|
||||
var fold = this.addFold("...", range);
|
||||
if (fold)
|
||||
fold.collapseChildren = depth;
|
||||
} catch(e) {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// structured folding
|
||||
this.$foldStyles = {
|
||||
"manual": 1,
|
||||
"markbegin": 1,
|
||||
@@ -659,14 +690,14 @@ function Folding() {
|
||||
this.$setFolding(mode);
|
||||
};
|
||||
|
||||
// structured folding
|
||||
this.$setFolding = function(foldMode) {
|
||||
if (this.$foldMode == foldMode)
|
||||
return;
|
||||
|
||||
this.$foldMode = foldMode;
|
||||
|
||||
this.removeListener('change', this.$updateFoldWidgets);
|
||||
this.off('change', this.$updateFoldWidgets);
|
||||
this.off('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets);
|
||||
this._emit("changeAnnotation");
|
||||
|
||||
if (!foldMode || this.$foldStyle == "manual") {
|
||||
@@ -679,35 +710,74 @@ function Folding() {
|
||||
this.getFoldWidgetRange = foldMode.getFoldWidgetRange.bind(foldMode, this, this.$foldStyle);
|
||||
|
||||
this.$updateFoldWidgets = this.updateFoldWidgets.bind(this);
|
||||
this.$tokenizerUpdateFoldWidgets = this.tokenizerUpdateFoldWidgets.bind(this);
|
||||
this.on('change', this.$updateFoldWidgets);
|
||||
|
||||
this.on('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets);
|
||||
};
|
||||
|
||||
this.getParentFoldRangeData = function (row, ignoreCurrent) {
|
||||
var fw = this.foldWidgets;
|
||||
if (!fw || (ignoreCurrent && fw[row]))
|
||||
return {};
|
||||
|
||||
var i = row - 1, firstRange;
|
||||
while (i >= 0) {
|
||||
var c = fw[i];
|
||||
if (c == null)
|
||||
c = fw[i] = this.getFoldWidget(i);
|
||||
|
||||
if (c == "start") {
|
||||
var range = this.getFoldWidgetRange(i);
|
||||
if (!firstRange)
|
||||
firstRange = range;
|
||||
if (range && range.end.row >= row)
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
return {
|
||||
range: i !== -1 && range,
|
||||
firstRange: firstRange
|
||||
};
|
||||
}
|
||||
|
||||
this.onFoldWidgetClick = function(row, e) {
|
||||
e = e.domEvent;
|
||||
var options = {
|
||||
children: e.shiftKey,
|
||||
all: e.ctrlKey || e.metaKey,
|
||||
siblings: e.altKey
|
||||
};
|
||||
|
||||
var range = this.$toggleFoldWidget(row, options);
|
||||
if (!range) {
|
||||
var el = (e.target || e.srcElement)
|
||||
if (el && /ace_fold-widget/.test(el.className))
|
||||
el.className += " ace_invalid";
|
||||
}
|
||||
};
|
||||
|
||||
this.$toggleFoldWidget = function(row, options) {
|
||||
if (!this.getFoldWidget)
|
||||
return;
|
||||
var type = this.getFoldWidget(row);
|
||||
var line = this.getLine(row);
|
||||
var onlySubfolds = e.shiftKey;
|
||||
var addSubfolds = onlySubfolds || e.ctrlKey || e.altKey || e.metaKey;
|
||||
var fold;
|
||||
|
||||
if (type == "end")
|
||||
fold = this.getFoldAt(row, 0, -1);
|
||||
else
|
||||
fold = this.getFoldAt(row, line.length, 1);
|
||||
var dir = type === "end" ? -1 : 1;
|
||||
var fold = this.getFoldAt(row, dir === -1 ? 0 : line.length, dir);
|
||||
|
||||
if (fold) {
|
||||
if (addSubfolds)
|
||||
if (options.children || options.all)
|
||||
this.removeFold(fold);
|
||||
else
|
||||
this.expandFold(fold);
|
||||
return;
|
||||
}
|
||||
|
||||
var range = this.getFoldWidgetRange(row);
|
||||
if (range) {
|
||||
var range = this.getFoldWidgetRange(row, true);
|
||||
// sometimes singleline folds can be missed by the code above
|
||||
if (!range.isMultiLine()) {
|
||||
if (range && !range.isMultiLine()) {
|
||||
fold = this.getFoldAt(range.start.row, range.start.column, 1);
|
||||
if (fold && range.isEqual(fold.range)) {
|
||||
this.removeFold(fold);
|
||||
@@ -715,15 +785,47 @@ function Folding() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlySubfolds)
|
||||
if (options.siblings) {
|
||||
var data = this.getParentFoldRangeData(row);
|
||||
if (data.range) {
|
||||
var startRow = data.range.start.row + 1;
|
||||
var endRow = data.range.end.row;
|
||||
}
|
||||
this.foldAll(startRow, endRow, options.all ? 10000 : 0);
|
||||
} else if (options.children) {
|
||||
endRow = range ? range.end.row : this.getLength();
|
||||
this.foldAll(row + 1, range.end.row, options.all ? 10000 : 0);
|
||||
} else if (range) {
|
||||
if (options.all)
|
||||
range.collapseChildren = 10000;
|
||||
this.addFold("...", range);
|
||||
}
|
||||
|
||||
if (addSubfolds)
|
||||
this.foldAll(range.start.row + 1, range.end.row);
|
||||
return range;
|
||||
};
|
||||
|
||||
|
||||
|
||||
this.toggleFoldWidget = function(toggleParent) {
|
||||
var row = this.selection.getCursor().row;
|
||||
row = this.getRowFoldStart(row);
|
||||
var range = this.$toggleFoldWidget(row, {});
|
||||
|
||||
if (range)
|
||||
return;
|
||||
// handle toggleParent
|
||||
var data = this.getParentFoldRangeData(row, true);
|
||||
range = data.range || data.firstRange;
|
||||
|
||||
if (range) {
|
||||
row = range.start.row;
|
||||
var fold = this.getFoldAt(row, this.getLine(row).length, 1);
|
||||
|
||||
if (fold) {
|
||||
this.removeFold(fold);
|
||||
} else {
|
||||
if (addSubfolds)
|
||||
this.foldAll(row + 1, this.getLength());
|
||||
(e.target || e.srcElement).className += " ace_invalid"
|
||||
this.addFold("...", range);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -743,7 +845,13 @@ function Folding() {
|
||||
this.foldWidgets.splice.apply(this.foldWidgets, args);
|
||||
}
|
||||
};
|
||||
|
||||
this.tokenizerUpdateFoldWidgets = function(e) {
|
||||
var rows = e.data;
|
||||
if (rows.first != rows.last) {
|
||||
if (this.foldWidgets.length > rows.first)
|
||||
this.foldWidgets.splice(rows.first, this.foldWidgets.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.Folding = Folding;
|
||||
|
||||
@@ -62,6 +62,7 @@ function createFoldTestSession() {
|
||||
}
|
||||
|
||||
function assertArray(a, b) {
|
||||
assert.equal(a+"", b+"");
|
||||
assert.ok(a.length == b.length);
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
assert.equal(a[i], b[i]);
|
||||
@@ -386,10 +387,11 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
|
||||
EditSession.prototype.$wrapAsCode = true;
|
||||
// Basic splitting.
|
||||
computeAndAssert("foo bar foo bar", [ 12 ]);
|
||||
computeAndAssert("foo bar f bar", [ 12 ]);
|
||||
computeAndAssert("foo bar f r", [ 14 ]);
|
||||
computeAndAssert("foo bar f r", [ 12 ]); // 14 if we enable
|
||||
computeAndAssert("foo bar foo bar foo bara foo", [12, 25]);
|
||||
|
||||
// Don't split if there is only whitespaces/tabs at the end of the line.
|
||||
@@ -405,7 +407,7 @@ module.exports = {
|
||||
computeAndAssert("foo \t \tbar", [ 7 ]);
|
||||
|
||||
// Ignore spaces/tabs at beginning of split.
|
||||
computeAndAssert("foo \t \t \t \t bar", [ 14 ]);
|
||||
computeAndAssert("foo \t \t \t \t bar", [ 7 ]); // 14
|
||||
|
||||
// Test wrapping for asian characters.
|
||||
computeAndAssert("ぁぁ", [1], 2);
|
||||
@@ -417,6 +419,10 @@ module.exports = {
|
||||
computeAndAssert(" ab.c;ef++", [1, 3, 5, 7, 8], 2);
|
||||
computeAndAssert(" a.b", [1, 2, 3], 1);
|
||||
computeAndAssert("#>>", [1, 2], 1);
|
||||
|
||||
// Test wrapping for punctuation in
|
||||
EditSession.prototype.$wrapAsCode = false;
|
||||
computeAndAssert("ab cde, Juhu kinners", [3, 8, 13, 19], 6);
|
||||
},
|
||||
|
||||
"test get longest line" : function() {
|
||||
@@ -899,6 +905,26 @@ module.exports = {
|
||||
return session;
|
||||
},
|
||||
|
||||
"test delete fold with wrap enabled": function() {
|
||||
var session = new EditSession("");
|
||||
session.setValue([
|
||||
"This is some placeholder text that will be folded inline.",
|
||||
"This is some placeholder text that will be folded inline.",
|
||||
"More text.",
|
||||
"<p>The cursor in this paragraph text will be offset by 1 row.<p>",
|
||||
"<p>Everything after this will be offset as well due to the folds in the row before too.</p>"
|
||||
].join("\n"));
|
||||
session.addFold('...', new Range(0, 8, 0, 42));
|
||||
session.addFold('...', new Range(1, 8, 1, 42));
|
||||
session.addFold('...', new Range(3, 7, 3, 51));
|
||||
session.setOption("wrap", 40);
|
||||
session.remove(new Range(0,0, 2, 5));
|
||||
// needed because adjustWrapLimit is called async from renderer
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.equal(session.$wrapData + "", [[], [], [40, 76]] + "");
|
||||
},
|
||||
|
||||
"test add fold": function() {
|
||||
var session = createFoldTestSession();
|
||||
var fold;
|
||||
@@ -911,7 +937,7 @@ module.exports = {
|
||||
fail = true;
|
||||
}
|
||||
if (fail != shouldFail) {
|
||||
throw "Expected to get an exception";
|
||||
throw new Error("Expected to get an exception");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -980,7 +1006,8 @@ module.exports = {
|
||||
assertArray(session.$docRowCache, [1,3,4]);
|
||||
assertArray(session.$screenRowCache, [1,2,3]);
|
||||
|
||||
session.screenToDocumentPosition(0,0);
|
||||
var pos = session.screenToDocumentPosition(0,0);
|
||||
assert.equal(pos.row, 0);
|
||||
assertArray(session.$docRowCache, [1,3,4]);
|
||||
assertArray(session.$screenRowCache, [1,2,3]);
|
||||
|
||||
@@ -991,11 +1018,58 @@ module.exports = {
|
||||
session.$resetRowCache();
|
||||
assertArray(session.$docRowCache, []);
|
||||
assertArray(session.$screenRowCache, []);
|
||||
|
||||
session.screenToDocumentPosition(1,3);
|
||||
assertArray(session.$docRowCache, [1]);
|
||||
assertArray(session.$screenRowCache, [1]);
|
||||
|
||||
session.screenToDocumentPosition(5,3);
|
||||
assertArray(session.$docRowCache, [1,3,4]);
|
||||
assertArray(session.$screenRowCache, [1,2,3]);
|
||||
|
||||
session = new EditSession(new Array(30).join("\n"));
|
||||
session.documentToScreenPosition(2,0);
|
||||
session.documentToScreenPosition(2,0);
|
||||
assertArray(session.$docRowCache, [1,2]);
|
||||
assertArray(session.$screenRowCache, [1,2]);
|
||||
},
|
||||
|
||||
"test annotations": function() {
|
||||
var session = new EditSession([]),
|
||||
annotation = {row: 0, type: 'info', text: "This is a test."};
|
||||
|
||||
session.clearAnnotations();
|
||||
assertArray(session.getAnnotations(), []);
|
||||
session.setAnnotations([annotation]);
|
||||
assertArray(session.getAnnotations(), [annotation]);
|
||||
},
|
||||
|
||||
"test: mode loading" : function(next) {
|
||||
if (!require.undef) {
|
||||
console.log("Skipping test: This test only runs in the browser");
|
||||
next();
|
||||
return;
|
||||
}
|
||||
var session = new EditSession([]);
|
||||
session.setMode("ace/mode/javascript");
|
||||
assert.equal(session.$modeid, "ace/mode/javascript");
|
||||
session.on("changeMode", function() {
|
||||
assert.equal(session.$modeid, "ace/mode/javascript");
|
||||
});
|
||||
session.setMode("ace/mode/sh", function(mode) {
|
||||
assert.ok(!mode);
|
||||
});
|
||||
setTimeout(function() {
|
||||
session.setMode("ace/mode/javascript", function(mode) {
|
||||
session.setMode("ace/mode/javascript");
|
||||
assert.equal(session.$modeid, "ace/mode/javascript");
|
||||
next();
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,7 @@ var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
var UndoManager = require("./undomanager").UndoManager;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
var whitespace = require("./ext/whitespace");
|
||||
|
||||
module.exports = {
|
||||
"test: delete line from the middle" : function() {
|
||||
@@ -184,21 +185,23 @@ module.exports = {
|
||||
"test: comment lines should perserve selection" : function() {
|
||||
var session = new EditSession([" abc", "cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
whitespace.detectIndentation(session);
|
||||
|
||||
editor.moveCursorTo(0, 2);
|
||||
editor.getSelection().selectDown();
|
||||
editor.toggleCommentLines();
|
||||
|
||||
assert.equal(["// abc", "//cde"].join("\n"), session.toString());
|
||||
assert.equal(["// abc", "// cde"].join("\n"), session.toString());
|
||||
|
||||
var selection = editor.getSelectionRange();
|
||||
assert.position(selection.start, 0, 4);
|
||||
assert.position(selection.end, 1, 4);
|
||||
assert.position(selection.start, 0, 5);
|
||||
assert.position(selection.end, 1, 5);
|
||||
},
|
||||
|
||||
"test: uncomment lines should perserve selection" : function() {
|
||||
var session = new EditSession(["// abc", "//cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
session.setTabSize(2);
|
||||
|
||||
editor.moveCursorTo(0, 1);
|
||||
editor.getSelection().selectDown();
|
||||
@@ -235,7 +238,7 @@ module.exports = {
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
assert.range(editor.getSelectionRange(), 0, 2, 1, 0);
|
||||
assert.range(editor.getSelectionRange(), 0, 3, 1, 0);
|
||||
|
||||
// select up
|
||||
var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode());
|
||||
@@ -245,10 +248,10 @@ module.exports = {
|
||||
editor.getSelection().selectUp();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
assert.range(editor.getSelectionRange(), 0, 2, 1, 0);
|
||||
assert.range(editor.getSelectionRange(), 0, 3, 1, 0);
|
||||
},
|
||||
|
||||
"test: move lines down should select moved lines" : function() {
|
||||
"test: move lines down should keep selection on moved lines" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
@@ -257,25 +260,25 @@ module.exports = {
|
||||
|
||||
editor.moveLinesDown();
|
||||
assert.equal(["33", "11", "22", "44"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 1, 1);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 2, 1);
|
||||
|
||||
editor.moveLinesDown();
|
||||
assert.equal(["33", "44", "11", "22"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 2, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 2);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 2, 0);
|
||||
assert.position(editor.getCursorPosition(), 3, 1);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 2, 1);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 3, 1);
|
||||
|
||||
// moving again should have no effect
|
||||
editor.moveLinesDown();
|
||||
assert.equal(["33", "44", "11", "22"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 2, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 2);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 2, 0);
|
||||
assert.position(editor.getCursorPosition(), 3, 1);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 2, 1);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 3, 1);
|
||||
},
|
||||
|
||||
"test: move lines up should select moved lines" : function() {
|
||||
"test: move lines up should keep selection on moved lines" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
@@ -284,19 +287,18 @@ module.exports = {
|
||||
|
||||
editor.moveLinesUp();
|
||||
assert.equal(session.toString(), ["11", "33", "44", "22"].join("\n"));
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 1, 1);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 2, 1);
|
||||
|
||||
editor.moveLinesUp();
|
||||
assert.equal(session.toString(), ["33", "44", "11", "22"].join("\n"));
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 2, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 0, 0);
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 0, 1);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 1, 1);
|
||||
},
|
||||
|
||||
"test: move line without active selection should not move cursor relative to the moved line" : function()
|
||||
{
|
||||
"test: move line without active selection should not move cursor relative to the moved line" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
@@ -314,7 +316,7 @@ module.exports = {
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
},
|
||||
|
||||
"test: copy lines down should select lines and place cursor at the selection start" : function() {
|
||||
"test: copy lines down should keep selection" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
@@ -324,12 +326,12 @@ module.exports = {
|
||||
editor.copyLinesDown();
|
||||
assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString());
|
||||
|
||||
assert.position(editor.getCursorPosition(), 3, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 5, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 3, 0);
|
||||
assert.position(editor.getCursorPosition(), 4, 1);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 1);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 4, 1);
|
||||
},
|
||||
|
||||
"test: copy lines up should select lines and place cursor at the selection start" : function() {
|
||||
"test: copy lines up should keep selection" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
@@ -339,9 +341,9 @@ module.exports = {
|
||||
editor.copyLinesUp();
|
||||
assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString());
|
||||
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 1, 1);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 2, 1);
|
||||
},
|
||||
|
||||
"test: input a tab with soft tab should convert it to spaces" : function() {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// [WIP]
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var TokenIterator = require("ace/token_iterator").TokenIterator;
|
||||
|
||||
var phpTransform = require("./beautify/php_rules").transform;
|
||||
|
||||
exports.beautify = function(session) {
|
||||
var iterator = new TokenIterator(session, 0, 0);
|
||||
var token = iterator.getCurrentToken();
|
||||
|
||||
var context = session.$modeId.split("/").pop();
|
||||
|
||||
var code = phpTransform(iterator, context);
|
||||
session.doc.setValue(code);
|
||||
};
|
||||
|
||||
exports.commands = [{
|
||||
name: "beautify",
|
||||
exec: function(editor) {
|
||||
exports.beautify(editor.session);
|
||||
},
|
||||
bindKey: "Ctrl-Shift-B"
|
||||
}]
|
||||
|
||||
});
|
||||
@@ -0,0 +1,366 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var TokenIterator = require("ace/token_iterator").TokenIterator;
|
||||
exports.newLines = [{
|
||||
type: 'support.php_tag',
|
||||
value: '<?php'
|
||||
}, {
|
||||
type: 'support.php_tag',
|
||||
value: '<?'
|
||||
}, {
|
||||
type: 'support.php_tag',
|
||||
value: '?>'
|
||||
}, {
|
||||
type: 'paren.lparen',
|
||||
value: '{',
|
||||
indent: true
|
||||
}, {
|
||||
type: 'paren.rparen',
|
||||
breakBefore: true,
|
||||
value: '}',
|
||||
indent: false
|
||||
}, {
|
||||
type: 'paren.rparen',
|
||||
breakBefore: true,
|
||||
value: '})',
|
||||
indent: false,
|
||||
dontBreak: true
|
||||
}, {
|
||||
type: 'comment'
|
||||
}, {
|
||||
type: 'text',
|
||||
value: ';'
|
||||
}, {
|
||||
type: 'text',
|
||||
value: ':',
|
||||
context: 'php'
|
||||
}, {
|
||||
type: 'keyword',
|
||||
value: 'case',
|
||||
indent: true,
|
||||
dontBreak: true
|
||||
}, {
|
||||
type: 'keyword',
|
||||
value: 'default',
|
||||
indent: true,
|
||||
dontBreak: true
|
||||
}, {
|
||||
type: 'keyword',
|
||||
value: 'break',
|
||||
indent: false,
|
||||
dontBreak: true
|
||||
}, {
|
||||
type: 'punctuation.doctype.end',
|
||||
value: '>'
|
||||
}, {
|
||||
type: 'meta.tag.punctuation.end',
|
||||
value: '>'
|
||||
}, {
|
||||
type: 'meta.tag.punctuation.begin',
|
||||
value: '<',
|
||||
blockTag: true,
|
||||
indent: true,
|
||||
dontBreak: true
|
||||
}, {
|
||||
type: 'meta.tag.punctuation.begin',
|
||||
value: '</',
|
||||
indent: false,
|
||||
breakBefore: true,
|
||||
dontBreak: true
|
||||
}, {
|
||||
type: 'punctuation.operator',
|
||||
value: ';'
|
||||
}];
|
||||
|
||||
exports.spaces = [{
|
||||
type: 'xml-pe',
|
||||
prepend: true
|
||||
},{
|
||||
type: 'entity.other.attribute-name',
|
||||
prepend: true
|
||||
}, {
|
||||
type: 'storage.type',
|
||||
value: 'var',
|
||||
append: true
|
||||
}, {
|
||||
type: 'storage.type',
|
||||
value: 'function',
|
||||
append: true
|
||||
}, {
|
||||
type: 'keyword.operator',
|
||||
value: '='
|
||||
}, {
|
||||
type: 'keyword',
|
||||
value: 'as',
|
||||
prepend: true,
|
||||
append: true
|
||||
}, {
|
||||
type: 'keyword',
|
||||
value: 'function',
|
||||
append: true
|
||||
}, {
|
||||
type: 'support.function',
|
||||
next: /[^\(]/,
|
||||
append: true
|
||||
}, {
|
||||
type: 'keyword',
|
||||
value: 'or',
|
||||
append: true,
|
||||
prepend: true
|
||||
}, {
|
||||
type: 'keyword',
|
||||
value: 'and',
|
||||
append: true,
|
||||
prepend: true
|
||||
}, {
|
||||
type: 'keyword',
|
||||
value: 'case',
|
||||
append: true
|
||||
}, {
|
||||
type: 'keyword.operator',
|
||||
value: '||',
|
||||
append: true,
|
||||
prepend: true
|
||||
}, {
|
||||
type: 'keyword.operator',
|
||||
value: '&&',
|
||||
append: true,
|
||||
prepend: true
|
||||
}];
|
||||
exports.singleTags = ['!doctype','area','base','br','hr','input','img','link','meta'];
|
||||
|
||||
exports.transform = function(iterator, maxPos, context) {
|
||||
var token = iterator.getCurrentToken();
|
||||
|
||||
var newLines = exports.newLines;
|
||||
var spaces = exports.spaces;
|
||||
var singleTags = exports.singleTags;
|
||||
|
||||
var code = '';
|
||||
|
||||
var indentation = 0;
|
||||
var dontBreak = false;
|
||||
var tag;
|
||||
var lastTag;
|
||||
var lastToken = {};
|
||||
var nextTag;
|
||||
var nextToken = {};
|
||||
var breakAdded = false;
|
||||
var value = '';
|
||||
|
||||
while (token!==null) {
|
||||
console.log(token);
|
||||
|
||||
if( !token ){
|
||||
token = iterator.stepForward();
|
||||
continue;
|
||||
}
|
||||
|
||||
//change syntax
|
||||
//php
|
||||
if( token.type == 'support.php_tag' && token.value != '?>' ){
|
||||
context = 'php';
|
||||
}
|
||||
else if( token.type == 'support.php_tag' && token.value == '?>' ){
|
||||
context = 'html';
|
||||
}
|
||||
//css
|
||||
else if( token.type == 'meta.tag.name.style' && context != 'css' ){
|
||||
context = 'css';
|
||||
}
|
||||
else if( token.type == 'meta.tag.name.style' && context == 'css' ){
|
||||
context = 'html';
|
||||
}
|
||||
//js
|
||||
else if( token.type == 'meta.tag.name.script' && context != 'js' ){
|
||||
context = 'js';
|
||||
}
|
||||
else if( token.type == 'meta.tag.name.script' && context == 'js' ){
|
||||
context = 'html';
|
||||
}
|
||||
|
||||
nextToken = iterator.stepForward();
|
||||
|
||||
//tag name
|
||||
if (nextToken && nextToken.type.indexOf('meta.tag.name') == 0) {
|
||||
nextTag = nextToken.value;
|
||||
}
|
||||
|
||||
//don't linebreak
|
||||
if ( lastToken.type == 'support.php_tag' && lastToken.value == '<?=') {
|
||||
dontBreak = true;
|
||||
}
|
||||
|
||||
//lowercase
|
||||
if (token.type == 'meta.tag.name') {
|
||||
token.value = token.value.toLowerCase();
|
||||
}
|
||||
|
||||
//trim spaces
|
||||
if (token.type == 'text') {
|
||||
token.value = token.value.trim();
|
||||
}
|
||||
|
||||
//skip empty tokens
|
||||
if (!token.value) {
|
||||
token = nextToken;
|
||||
continue;
|
||||
}
|
||||
|
||||
//put spaces back in
|
||||
value = token.value;
|
||||
for (var i in spaces) {
|
||||
if (
|
||||
token.type == spaces[i].type &&
|
||||
(!spaces[i].value || token.value == spaces[i].value) &&
|
||||
(
|
||||
nextToken &&
|
||||
(!spaces[i].next || spaces[i].next.test(nextToken.value))
|
||||
)
|
||||
) {
|
||||
if (spaces[i].prepend) {
|
||||
value = ' ' + token.value;
|
||||
}
|
||||
|
||||
if (spaces[i].append) {
|
||||
value += ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//tag name
|
||||
if (token.type.indexOf('meta.tag.name') == 0) {
|
||||
tag = token.value;
|
||||
//console.log(tag);
|
||||
}
|
||||
|
||||
//new line before
|
||||
breakAdded = false;
|
||||
|
||||
//outdent
|
||||
for (i in newLines) {
|
||||
if (
|
||||
token.type == newLines[i].type &&
|
||||
(
|
||||
!newLines[i].value ||
|
||||
token.value == newLines[i].value
|
||||
) &&
|
||||
(
|
||||
!newLines[i].blockTag ||
|
||||
singleTags.indexOf(nextTag) === -1
|
||||
) &&
|
||||
(
|
||||
!newLines[i].context ||
|
||||
newLines[i].context === context
|
||||
)
|
||||
) {
|
||||
if (newLines[i].indent === false) {
|
||||
indentation--;
|
||||
}
|
||||
|
||||
if (
|
||||
newLines[i].breakBefore &&
|
||||
( !newLines[i].prev || newLines[i].prev.test(lastToken.value) )
|
||||
) {
|
||||
code += "\n";
|
||||
breakAdded = true;
|
||||
|
||||
//indent
|
||||
for (i = 0; i < indentation; i++) {
|
||||
code += "\t";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dontBreak===false) {
|
||||
for (i in newLines) {
|
||||
if (
|
||||
lastToken.type == newLines[i].type &&
|
||||
(
|
||||
!newLines[i].value || lastToken.value == newLines[i].value
|
||||
) &&
|
||||
(
|
||||
!newLines[i].blockTag ||
|
||||
singleTags.indexOf(tag) === -1
|
||||
) &&
|
||||
(
|
||||
!newLines[i].context ||
|
||||
newLines[i].context === context
|
||||
)
|
||||
) {
|
||||
if (newLines[i].indent === true) {
|
||||
indentation++;
|
||||
}
|
||||
|
||||
if (!newLines[i].dontBreak && !breakAdded) {
|
||||
code += "\n";
|
||||
|
||||
//indent
|
||||
for (i = 0; i < indentation; i++) {
|
||||
code += "\t";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code += value;
|
||||
|
||||
//linebreaks back on after end short php tag
|
||||
if ( lastToken.type == 'support.php_tag' && lastToken.value == '?>' ) {
|
||||
dontBreak = false;
|
||||
}
|
||||
|
||||
//next token
|
||||
lastTag = tag;
|
||||
|
||||
lastToken = token;
|
||||
|
||||
token = nextToken;
|
||||
|
||||
if (token===null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
};
|
||||
|
||||
|
||||
|
||||
});
|
||||
@@ -0,0 +1,980 @@
|
||||
define(function(require, exports, module) {
|
||||
|
||||
/* ChromeVox Ace namespace. */
|
||||
var cvoxAce = {};
|
||||
|
||||
/* Typedefs for Closure compiler. */
|
||||
/**
|
||||
* @typedef {{
|
||||
rate: number,
|
||||
pitch: number,
|
||||
volume: number,
|
||||
relativePitch: number,
|
||||
punctuationEcho: string
|
||||
}}
|
||||
*/
|
||||
/* TODO(peterxiao): Export this typedef through cvox.Api. */
|
||||
cvoxAce.SpeechProperty;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* row: number,
|
||||
* column: number
|
||||
* }}
|
||||
*/
|
||||
cvoxAce.Cursor;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
type: string,
|
||||
value: string
|
||||
}}
|
||||
}
|
||||
*/
|
||||
cvoxAce.Token;
|
||||
|
||||
/**
|
||||
* These are errors and information that Ace will display in the gutter.
|
||||
* @typedef {{
|
||||
row: number,
|
||||
column: number,
|
||||
value: string
|
||||
}}
|
||||
}
|
||||
*/
|
||||
cvoxAce.Annotation;
|
||||
|
||||
/* Speech Properties. */
|
||||
/**
|
||||
* Speech property for speaking constant tokens.
|
||||
* @type {cvoxAce.SpeechProperty}
|
||||
*/
|
||||
var CONSTANT_PROP = {
|
||||
'rate': 0.8,
|
||||
'pitch': 0.4,
|
||||
'volume': 0.9
|
||||
};
|
||||
|
||||
/**
|
||||
* Default speech property for speaking tokens.
|
||||
* @type {cvoxAce.SpeechProperty}
|
||||
*/
|
||||
var DEFAULT_PROP = {
|
||||
'rate': 1,
|
||||
'pitch': 0.5,
|
||||
'volume': 0.9
|
||||
};
|
||||
|
||||
/**
|
||||
* Speech property for speaking entity tokens.
|
||||
* @type {cvoxAce.SpeechProperty}
|
||||
*/
|
||||
var ENTITY_PROP = {
|
||||
'rate': 0.8,
|
||||
'pitch': 0.8,
|
||||
'volume': 0.9
|
||||
};
|
||||
|
||||
/**
|
||||
* Speech property for speaking keywords.
|
||||
* @type {cvoxAce.SpeechProperty}
|
||||
*/
|
||||
var KEYWORD_PROP = {
|
||||
'rate': 0.8,
|
||||
'pitch': 0.3,
|
||||
'volume': 0.9
|
||||
};
|
||||
|
||||
/**
|
||||
* Speech property for speaking storage tokens.
|
||||
* @type {cvoxAce.SpeechProperty}
|
||||
*/
|
||||
var STORAGE_PROP = {
|
||||
'rate': 0.8,
|
||||
'pitch': 0.7,
|
||||
'volume': 0.9
|
||||
};
|
||||
|
||||
/**
|
||||
* Speech property for speaking variable tokens.
|
||||
* @type {cvoxAce.SpeechProperty}
|
||||
*/
|
||||
var VARIABLE_PROP = {
|
||||
'rate': 0.8,
|
||||
'pitch': 0.8,
|
||||
'volume': 0.9
|
||||
};
|
||||
|
||||
/**
|
||||
* Speech property for speaking deleted text.
|
||||
* @type {cvoxAce.SpeechProperty}
|
||||
*/
|
||||
var DELETED_PROP = {
|
||||
'punctuationEcho': 'none',
|
||||
'relativePitch': -0.6
|
||||
};
|
||||
|
||||
/* Constants for Earcons. */
|
||||
var ERROR_EARCON = 'ALERT_NONMODAL';
|
||||
var MODE_SWITCH_EARCON = 'ALERT_MODAL';
|
||||
var NO_MATCH_EARCON = 'INVALID_KEYPRESS';
|
||||
|
||||
/* Constants for vim state. */
|
||||
var INSERT_MODE_STATE = 'insertMode';
|
||||
var COMMAND_MODE_STATE = 'start';
|
||||
|
||||
var REPLACE_LIST = [
|
||||
{
|
||||
substr: ';',
|
||||
newSubstr: ' semicolon '
|
||||
},
|
||||
{
|
||||
substr: ':',
|
||||
newSubstr: ' colon '
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Context menu commands.
|
||||
*/
|
||||
var Command = {
|
||||
SPEAK_ANNOT: 'annots',
|
||||
SPEAK_ALL_ANNOTS: 'all_annots',
|
||||
TOGGLE_LOCATION: 'toggle_location',
|
||||
SPEAK_MODE: 'mode',
|
||||
SPEAK_ROW_COL: 'row_col',
|
||||
TOGGLE_DISPLACEMENT: 'toggle_displacement',
|
||||
FOCUS_TEXT: 'focus_text'
|
||||
};
|
||||
|
||||
/**
|
||||
* Key prefix for each shortcut.
|
||||
*/
|
||||
var KEY_PREFIX = 'CONTROL + SHIFT ';
|
||||
|
||||
/* Globals. */
|
||||
cvoxAce.editor = null;
|
||||
/**
|
||||
* Last cursor position.
|
||||
* @type {cvoxAce.Cursor}
|
||||
*/
|
||||
var lastCursor = null;
|
||||
|
||||
/**
|
||||
* Table of annotations.
|
||||
* @typedef {!Object.<number, Object<number, cvoxAce.Annotation>>}
|
||||
*/
|
||||
var annotTable = {};
|
||||
|
||||
/**
|
||||
* Whether to speak character, word, and then line. This allows blind users
|
||||
* to know the location of the cursor when they change lines.
|
||||
* @typedef {boolean}
|
||||
*/
|
||||
var shouldSpeakRowLocation = false;
|
||||
|
||||
/**
|
||||
* Whether to speak displacement.
|
||||
* @typedef {boolean}
|
||||
*/
|
||||
var shouldSpeakDisplacement = false;
|
||||
|
||||
/**
|
||||
* Whether text was changed to cause a cursor change event.
|
||||
* @typedef {boolean}
|
||||
*/
|
||||
var changed = false;
|
||||
|
||||
/**
|
||||
* Current state vim is in.
|
||||
*/
|
||||
var vimState = null;
|
||||
|
||||
/**
|
||||
* Mapping from key code to shortcut.
|
||||
*/
|
||||
var keyCodeToShortcutMap = {};
|
||||
|
||||
/**
|
||||
* Mapping from command to shortcut.
|
||||
*/
|
||||
var cmdToShortcutMap = {};
|
||||
|
||||
/**
|
||||
* Get shortcut string from keyCode.
|
||||
* @param {number} keyCode Key code of shortcut.
|
||||
* @return {string} String representation of shortcut.
|
||||
*/
|
||||
var getKeyShortcutString = function(keyCode) {
|
||||
return KEY_PREFIX + String.fromCharCode(keyCode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return if in vim mode.
|
||||
* @return {boolean} True if in Vim mode.
|
||||
*/
|
||||
var isVimMode = function() {
|
||||
var keyboardHandler = cvoxAce.editor.keyBinding.getKeyboardHandler();
|
||||
return keyboardHandler.$id === 'ace/keyboard/vim';
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the current token.
|
||||
* @param {!cvoxAce.Cursor} cursor Current position of the cursor.
|
||||
* @return {!cvoxAce.Token} Token at the current position.
|
||||
*/
|
||||
var getCurrentToken = function(cursor) {
|
||||
return cvoxAce.editor.getSession().getTokenAt(cursor.row, cursor.column + 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the current line the cursor is under.
|
||||
* @param {!cvoxAce.Cursor} cursor Current cursor position.
|
||||
*/
|
||||
var getCurrentLine = function(cursor) {
|
||||
return cvoxAce.editor.getSession().getLine(cursor.row);
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for row changes. When the user changes rows we want to speak
|
||||
* the line so the user can work on this line. If shouldSpeakRowLocation is on
|
||||
* then we speak the character, then the row, then the line so the user knows
|
||||
* where the cursor is.
|
||||
* @param {!cvoxAce.Cursor} currCursor Current cursor position.
|
||||
*/
|
||||
var onRowChange = function(currCursor) {
|
||||
/* Notify that this line has an annotation. */
|
||||
if (annotTable[currCursor.row]) {
|
||||
cvox.Api.playEarcon(ERROR_EARCON);
|
||||
}
|
||||
if (shouldSpeakRowLocation) {
|
||||
cvox.Api.stop();
|
||||
speakChar(currCursor);
|
||||
speakTokenQueue(getCurrentToken(currCursor));
|
||||
speakLine(currCursor.row, 1);
|
||||
} else {
|
||||
speakLine(currCursor.row, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether the cursor is at the beginning of a word. A word is
|
||||
* a grouping of alphanumeric characters including underscores.
|
||||
* @param {!cvoxAce.Cursor} cursor Current cursor position.
|
||||
* @return {boolean} Whether there is word.
|
||||
*/
|
||||
var isWord = function(cursor) {
|
||||
var line = getCurrentLine(cursor);
|
||||
var lineSuffix = line.substr(cursor.column - 1);
|
||||
if (cursor.column === 0) {
|
||||
lineSuffix = ' ' + line;
|
||||
}
|
||||
/* Use regex to tell if the suffix is at the start of a new word. */
|
||||
var firstWordRegExp = /^\W(\w+)/;
|
||||
var words = firstWordRegExp.exec(lineSuffix);
|
||||
return words !== null;
|
||||
};
|
||||
|
||||
/**
|
||||
* A mapping of syntax type to speech properties / expanding rules.
|
||||
*/
|
||||
var rules = {
|
||||
'constant': {
|
||||
prop: CONSTANT_PROP
|
||||
},
|
||||
'entity': {
|
||||
prop: ENTITY_PROP
|
||||
},
|
||||
'keyword': {
|
||||
prop: KEYWORD_PROP
|
||||
},
|
||||
'storage': {
|
||||
prop: STORAGE_PROP
|
||||
},
|
||||
'variable': {
|
||||
prop: VARIABLE_PROP
|
||||
},
|
||||
'meta': {
|
||||
prop: DEFAULT_PROP,
|
||||
replace: [
|
||||
{
|
||||
substr: '</',
|
||||
newSubstr: ' closing tag '
|
||||
},
|
||||
{
|
||||
substr: '/>',
|
||||
newSubstr: ' close tag '
|
||||
},
|
||||
{
|
||||
substr: '<',
|
||||
newSubstr: ' tag start '
|
||||
},
|
||||
{
|
||||
substr: '>',
|
||||
newSubstr: ' tag end '
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Default rule to be used.
|
||||
*/
|
||||
var DEFAULT_RULE = {
|
||||
prop: DEFAULT_RULE
|
||||
};
|
||||
|
||||
/**
|
||||
* Expands substrings to how they are read based on the given rules.
|
||||
* @param {string} value Text to be expanded.
|
||||
* @param {Array.<Object>} replaceRules Rules to determine expansion.
|
||||
* @return {string} New expanded value.
|
||||
*/
|
||||
var expand = function(value, replaceRules) {
|
||||
var newValue = value;
|
||||
for (var i = 0; i < replaceRules.length; i++) {
|
||||
var replaceRule = replaceRules[i];
|
||||
var regexp = new RegExp(replaceRule.substr, 'g');
|
||||
newValue = newValue.replace(regexp, replaceRule.newSubstr);
|
||||
}
|
||||
return newValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Merges tokens from start inclusive to end exclusive.
|
||||
* @param {Array.<cvoxAce.Token>} Tokens to be merged.
|
||||
* @param {number} start Start index inclusive.
|
||||
* @param {number} end End index exclusive.
|
||||
* @return {cvoxAce.Token} Merged token.
|
||||
*/
|
||||
var mergeTokens = function(tokens, start, end) {
|
||||
/* Different type of token found! Merge all previous like tokens. */
|
||||
var newToken = {};
|
||||
newToken.value = '';
|
||||
newToken.type = tokens[start].type;
|
||||
for (var j = start; j < end; j++) {
|
||||
newToken.value += tokens[j].value;
|
||||
}
|
||||
return newToken;
|
||||
};
|
||||
|
||||
/**
|
||||
* Merges tokens that use the same speech properties.
|
||||
* @param {Array.<cvoxAce.Token>} tokens Tokens to be merged.
|
||||
* @return {Array.<cvoxAce.Token>} Merged tokens.
|
||||
*/
|
||||
var mergeLikeTokens = function(tokens) {
|
||||
if (tokens.length <= 1) {
|
||||
return tokens;
|
||||
}
|
||||
var newTokens = [];
|
||||
var lastLikeIndex = 0;
|
||||
for (var i = 1; i < tokens.length; i++) {
|
||||
var lastLikeToken = tokens[lastLikeIndex];
|
||||
var currToken = tokens[i];
|
||||
if (getTokenRule(lastLikeToken) !== getTokenRule(currToken)) {
|
||||
newTokens.push(mergeTokens(tokens, lastLikeIndex, i));
|
||||
lastLikeIndex = i;
|
||||
}
|
||||
}
|
||||
newTokens.push(mergeTokens(tokens, lastLikeIndex, tokens.length));
|
||||
return newTokens;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns if given row is a whitespace row.
|
||||
* @param {number} row Row.
|
||||
* @return {boolean} True if row is whitespaces.
|
||||
*/
|
||||
var isRowWhiteSpace = function(row) {
|
||||
var line = cvoxAce.editor.getSession().getLine(row);
|
||||
var whiteSpaceRegexp = /^\s*$/;
|
||||
return whiteSpaceRegexp.exec(line) !== null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Speak the line with syntax properties.
|
||||
* @param {number} row Row to speak.
|
||||
* @param {number} queue Queue mode to speak.
|
||||
*/
|
||||
var speakLine = function(row, queue) {
|
||||
var tokens = cvoxAce.editor.getSession().getTokens(row);
|
||||
if (tokens.length === 0 || isRowWhiteSpace(row)) {
|
||||
cvox.Api.playEarcon('EDITABLE_TEXT');
|
||||
return;
|
||||
}
|
||||
tokens = mergeLikeTokens(tokens);
|
||||
var firstToken = tokens[0];
|
||||
/* Filter out first token. */
|
||||
tokens = tokens.filter(function(token) {
|
||||
return token !== firstToken;
|
||||
});
|
||||
/* Speak first token separately to flush if queue. */
|
||||
speakToken_(firstToken, queue);
|
||||
/* Speak rest of tokens. */
|
||||
tokens.forEach(speakTokenQueue);
|
||||
};
|
||||
|
||||
/**
|
||||
* Speak the token based on the syntax of the token, flushing.
|
||||
* @param {!cvoxAce.Token} token Token to speak.
|
||||
* @param {number} queue Queue mode.
|
||||
*/
|
||||
var speakTokenFlush = function(token) {
|
||||
speakToken_(token, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Speak the token based on the syntax of the token, queueing.
|
||||
* @param {!cvoxAce.Token} token Token to speak.
|
||||
* @param {number} queue Queue mode.
|
||||
*/
|
||||
var speakTokenQueue = function(token) {
|
||||
speakToken_(token, 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!cvoxAce.Token} token Token to speak.
|
||||
* Get the token speech property.
|
||||
*/
|
||||
var getTokenRule = function(token) {
|
||||
/* Types are period delimited. In this case, we only syntax speak the outer
|
||||
* most type of token. */
|
||||
if (!token || !token.type) {
|
||||
return;
|
||||
}
|
||||
var split = token.type.split('.');
|
||||
if (split.length === 0) {
|
||||
return;
|
||||
}
|
||||
var type = split[0];
|
||||
var rule = rules[type];
|
||||
if (!rule) {
|
||||
return DEFAULT_RULE;
|
||||
}
|
||||
return rule;
|
||||
};
|
||||
|
||||
/**
|
||||
* Speak the token based on the syntax of the token.
|
||||
* @private
|
||||
* @param {!cvoxAce.Token} token Token to speak.
|
||||
* @param {number} queue Queue mode.
|
||||
*/
|
||||
var speakToken_ = function(token, queue) {
|
||||
var rule = getTokenRule(token);
|
||||
var value = expand(token.value, REPLACE_LIST);
|
||||
if (rule.replace) {
|
||||
value = expand(value, rule.replace);
|
||||
}
|
||||
cvox.Api.speak(value, queue, rule.prop);
|
||||
};
|
||||
|
||||
/**
|
||||
* Speaks the character under the cursor. This is queued.
|
||||
* @param {!cvoxAce.Cursor} cursor Current cursor position.
|
||||
* @return {string} Character.
|
||||
*/
|
||||
var speakChar = function(cursor) {
|
||||
var line = getCurrentLine(cursor);
|
||||
cvox.Api.speak(line[cursor.column], 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Speaks the jump from lastCursor to currCursor. This function assumes the
|
||||
* jump takes place on the current line.
|
||||
* @param {!cvoxAce.Cursor} lastCursor Previous cursor position.
|
||||
* @param {!cvoxAce.Cursor} currCursor Current cursor position.
|
||||
*/
|
||||
var speakDisplacement = function(lastCursor, currCursor) {
|
||||
var line = getCurrentLine(currCursor);
|
||||
|
||||
/* Get the text that we jumped past. */
|
||||
var displace = line.substring(lastCursor.column, currCursor.column);
|
||||
|
||||
/* Speak out loud spaces. */
|
||||
displace = displace.replace(/ /g, ' space ');
|
||||
cvox.Api.speak(displace);
|
||||
};
|
||||
|
||||
/**
|
||||
* Speaks the word if the cursor jumped to a new word or to the beginning
|
||||
* of the line. Otherwise speak the charactor.
|
||||
* @param {!cvoxAce.Cursor} lastCursor Previous cursor position.
|
||||
* @param {!cvoxAce.Cursor} currCursor Current cursor position.
|
||||
*/
|
||||
var speakCharOrWordOrLine = function(lastCursor, currCursor) {
|
||||
/* Say word only if jump. */
|
||||
if (Math.abs(lastCursor.column - currCursor.column) !== 1) {
|
||||
var currLineLength = getCurrentLine(currCursor).length;
|
||||
/* Speak line if jumping to beginning or end of line. */
|
||||
if (currCursor.column === 0 || currCursor.column === currLineLength) {
|
||||
speakLine(currCursor.row, 0);
|
||||
return;
|
||||
}
|
||||
if (isWord(currCursor)) {
|
||||
cvox.Api.stop();
|
||||
speakTokenQueue(getCurrentToken(currCursor));
|
||||
return;
|
||||
}
|
||||
}
|
||||
speakChar(currCursor);
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for column changes. If shouldSpeakDisplacement is on, then
|
||||
* we just speak displacements in row changes. Otherwise, we either speak
|
||||
* the character for single character movements, the word when jumping to the
|
||||
* next word, or the entire line if jumping to beginning or end of the line.
|
||||
* @param {!cvoxAce.Cursor} lastCursor Previous cursor position.
|
||||
* @param {!cvoxAce.Cursor} currCursor Current cursor position.
|
||||
*/
|
||||
var onColumnChange = function(lastCursor, currCursor) {
|
||||
if (!cvoxAce.editor.selection.isEmpty()) {
|
||||
speakDisplacement(lastCursor, currCursor);
|
||||
cvox.Api.speak('selected', 1);
|
||||
}
|
||||
else if (shouldSpeakDisplacement) {
|
||||
speakDisplacement(lastCursor, currCursor);
|
||||
} else {
|
||||
speakCharOrWordOrLine(lastCursor, currCursor);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for cursor changes. Classify cursor changes as either row or
|
||||
* column changes, then delegate accordingly.
|
||||
* @param {!Event} evt The event.
|
||||
*/
|
||||
var onCursorChange = function(evt) {
|
||||
/* Do not speak if cursor change was a result of text insertion. We want to
|
||||
* speak the text that was inserted and not where the cursor lands. */
|
||||
if (changed) {
|
||||
changed = false;
|
||||
return;
|
||||
}
|
||||
var currCursor = cvoxAce.editor.selection.getCursor();
|
||||
if (currCursor.row !== lastCursor.row) {
|
||||
onRowChange(currCursor);
|
||||
} else {
|
||||
onColumnChange(lastCursor, currCursor);
|
||||
}
|
||||
lastCursor = currCursor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for selection changes.
|
||||
* @param {!Event} evt The event.
|
||||
*/
|
||||
var onSelectionChange = function(evt) {
|
||||
/* Assumes that when selection changes to empty, the user has unselected. */
|
||||
if (cvoxAce.editor.selection.isEmpty()) {
|
||||
cvox.Api.speak('unselected');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for source changes. We want auditory feedback for inserting
|
||||
* and deleting text.
|
||||
* @param {!Event} evt The event.
|
||||
*/
|
||||
var onChange = function(evt) {
|
||||
var data = evt.data;
|
||||
switch (data.action) {
|
||||
case 'removeText':
|
||||
cvox.Api.speak(data.text, 0, DELETED_PROP);
|
||||
/* Let the future cursor change event know it's from text change. */
|
||||
changed = true;
|
||||
break;
|
||||
case 'insertText':
|
||||
cvox.Api.speak(data.text, 0);
|
||||
/* Let the future cursor change event know it's from text change. */
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether or not the annotation is new.
|
||||
* @param {!cvoxAce.Annotation} annot Annotation in question.
|
||||
* @return {boolean} Whether annot is new.
|
||||
*/
|
||||
var isNewAnnotation = function(annot) {
|
||||
var row = annot.row;
|
||||
var col = annot.column;
|
||||
return !annotTable[row] || !annotTable[row][col];
|
||||
};
|
||||
|
||||
/**
|
||||
* Populates the annotation table.
|
||||
* @param {!Array.<cvoxAce.Annotation>} annotations Array of annotations.
|
||||
*/
|
||||
var populateAnnotations = function(annotations) {
|
||||
annotTable = {};
|
||||
for (var i = 0; i < annotations.length; i++) {
|
||||
var annotation = annotations[i];
|
||||
var row = annotation.row;
|
||||
var col = annotation.column;
|
||||
if (!annotTable[row]) {
|
||||
annotTable[row] = {};
|
||||
}
|
||||
annotTable[row][col] = annotation;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for annotation changes. We want to notify the user when an
|
||||
* a new annotation appears.
|
||||
* @param {!Event} evt Event.
|
||||
*/
|
||||
var onAnnotationChange = function(evt) {
|
||||
var annotations = cvoxAce.editor.getSession().getAnnotations();
|
||||
var newAnnotations = annotations.filter(isNewAnnotation);
|
||||
if (newAnnotations.length > 0) {
|
||||
cvox.Api.playEarcon(ERROR_EARCON);
|
||||
}
|
||||
populateAnnotations(annotations);
|
||||
};
|
||||
|
||||
/**
|
||||
* Speak annotation.
|
||||
* @param {!cvoxAce.Annotation} annot Annotation to speak.
|
||||
*/
|
||||
var speakAnnot = function(annot) {
|
||||
var annotText = annot.type + ' ' + annot.text + ' on ' +
|
||||
rowColToString(annot.row, annot.column);
|
||||
annotText = annotText.replace(';', 'semicolon');
|
||||
cvox.Api.speak(annotText, 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Speak annotations in a row.
|
||||
* @param {number} row Row of annotations to speak.
|
||||
*/
|
||||
var speakAnnotsByRow = function(row) {
|
||||
var annots = annotTable[row];
|
||||
for (var col in annots) {
|
||||
speakAnnot(annots[col]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a string representation of a row and column.
|
||||
* @param {boolean} row Zero indexed row.
|
||||
* @param {boolean} col Zero indexed column.
|
||||
* @return {string} Row and column to be spoken.
|
||||
*/
|
||||
var rowColToString = function(row, col) {
|
||||
return 'row ' + (row + 1) + ' column ' + (col + 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Speaks the row and column.
|
||||
*/
|
||||
var speakCurrRowAndCol = function() {
|
||||
cvox.Api.speak(rowColToString(lastCursor.row, lastCursor.column));
|
||||
};
|
||||
|
||||
/**
|
||||
* Speaks all annotations.
|
||||
*/
|
||||
var speakAllAnnots = function() {
|
||||
for (var row in annotTable) {
|
||||
speakAnnotsByRow(row);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Speak the vim mode. If no vim mode, this function does nothing.
|
||||
*/
|
||||
var speakMode = function() {
|
||||
if (!isVimMode()) {
|
||||
return;
|
||||
}
|
||||
switch (cvoxAce.editor.keyBinding.$data.state) {
|
||||
case INSERT_MODE_STATE:
|
||||
cvox.Api.speak('Insert mode');
|
||||
break;
|
||||
case COMMAND_MODE_STATE:
|
||||
cvox.Api.speak('Command mode');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle speak location.
|
||||
*/
|
||||
var toggleSpeakRowLocation = function() {
|
||||
shouldSpeakRowLocation = !shouldSpeakRowLocation;
|
||||
/* Auditory feedback of the change. */
|
||||
if (shouldSpeakRowLocation) {
|
||||
cvox.Api.speak('Speak location on row change enabled.');
|
||||
} else {
|
||||
cvox.Api.speak('Speak location on row change disabled.');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle speak displacement.
|
||||
*/
|
||||
var toggleSpeakDisplacement = function() {
|
||||
shouldSpeakDisplacement = !shouldSpeakDisplacement;
|
||||
/* Auditory feedback of the change. */
|
||||
if (shouldSpeakDisplacement) {
|
||||
cvox.Api.speak('Speak displacement on column changes.');
|
||||
} else {
|
||||
cvox.Api.speak('Speak current character or word on column changes.');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for key down events. Gets the right shortcut from the map,
|
||||
* and calls the associated function.
|
||||
* @param {!Event} evt Keyboard event.
|
||||
*/
|
||||
var onKeyDown = function(evt) {
|
||||
if (evt.ctrlKey && evt.shiftKey) {
|
||||
var shortcut = keyCodeToShortcutMap[evt.keyCode];
|
||||
if (shortcut) {
|
||||
shortcut.func();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for status change events. Auditory feedback of changing
|
||||
* between vim states.
|
||||
* @param {!Event} evt Change status event.
|
||||
* @param {!Object} editor Editor state.
|
||||
*/
|
||||
var onChangeStatus = function(evt, editor) {
|
||||
if (!isVimMode()) {
|
||||
return;
|
||||
}
|
||||
var state = editor.keyBinding.$data.state;
|
||||
if (state === vimState) {
|
||||
/* State hasn't changed, do nothing. */
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case INSERT_MODE_STATE:
|
||||
cvox.Api.playEarcon(MODE_SWITCH_EARCON);
|
||||
/* When in insert mode, we want to speak out keys as feedback. */
|
||||
cvox.Api.setKeyEcho(true);
|
||||
break;
|
||||
case COMMAND_MODE_STATE:
|
||||
cvox.Api.playEarcon(MODE_SWITCH_EARCON);
|
||||
/* When in command mode, we want don't speak out keys because those keys
|
||||
* are not being inserted in the document. */
|
||||
cvox.Api.setKeyEcho(false);
|
||||
break;
|
||||
}
|
||||
vimState = state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles context menu events. This is a ChromeVox feature where hitting
|
||||
* the shortcut ChromeVox + comma will open up a search bar where you can
|
||||
* type in various commands. All keyboard shortcuts are also commands that
|
||||
* can be invoked. This handles the event that ChromeVox sends to the page.
|
||||
* @param {Event} evt Event received.
|
||||
*/
|
||||
var contextMenuHandler = function(evt) {
|
||||
var cmd = evt.detail['customCommand'];
|
||||
var shortcut = cmdToShortcutMap[cmd];
|
||||
if (shortcut) {
|
||||
shortcut.func();
|
||||
/* ChromeVox will bring focus to an element near the cursor instead of the
|
||||
* text input. */
|
||||
cvoxAce.editor.focus();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the ChromeVox context menu.
|
||||
*/
|
||||
var initContextMenu = function() {
|
||||
var ACTIONS = SHORTCUTS.map(function(shortcut) {
|
||||
return {
|
||||
desc: shortcut.desc + getKeyShortcutString(shortcut.keyCode),
|
||||
cmd: shortcut.cmd
|
||||
};
|
||||
});
|
||||
|
||||
/* Attach ContextMenuActions. */
|
||||
var body = document.querySelector('body');
|
||||
body.setAttribute('contextMenuActions', JSON.stringify(ACTIONS));
|
||||
|
||||
/* Listen for ContextMenu events. */
|
||||
body.addEventListener('ATCustomEvent', contextMenuHandler, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for find events. When there is a match, we want to speak the
|
||||
* line we are now at. Otherwise, we want to notify the user there was no
|
||||
* match
|
||||
* @param {!Event} evt The event.
|
||||
*/
|
||||
var onFindSearchbox = function(evt) {
|
||||
if (evt.match) {
|
||||
/* There is still a match! Speak the line. */
|
||||
speakLine(lastCursor.row, 0);
|
||||
} else {
|
||||
/* No match, give auditory feedback! */
|
||||
cvox.Api.playEarcon(NO_MATCH_EARCON);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Focus to text input.
|
||||
*/
|
||||
var focus = function() {
|
||||
cvoxAce.editor.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut definitions.
|
||||
*/
|
||||
var SHORTCUTS = [
|
||||
{
|
||||
/* 1 key. */
|
||||
keyCode: 49,
|
||||
func: function() {
|
||||
speakAnnotsByRow(lastCursor.row);
|
||||
},
|
||||
cmd: Command.SPEAK_ANNOT,
|
||||
desc: 'Speak annotations on line'
|
||||
},
|
||||
{
|
||||
/* 2 key. */
|
||||
keyCode: 50,
|
||||
func: speakAllAnnots,
|
||||
cmd: Command.SPEAK_ALL_ANNOTS,
|
||||
desc: 'Speak all annotations'
|
||||
},
|
||||
{
|
||||
/* 3 key. */
|
||||
keyCode: 51,
|
||||
func: speakMode,
|
||||
cmd: Command.SPEAK_MODE,
|
||||
desc: 'Speak Vim mode'
|
||||
},
|
||||
{
|
||||
/* 4 key. */
|
||||
keyCode: 52,
|
||||
func: toggleSpeakRowLocation,
|
||||
cmd: Command.TOGGLE_LOCATION,
|
||||
desc: 'Toggle speak row location'
|
||||
},
|
||||
{
|
||||
/* 5 key. */
|
||||
keyCode: 53,
|
||||
func: speakCurrRowAndCol,
|
||||
cmd: Command.SPEAK_ROW_COL,
|
||||
desc: 'Speak row and column'
|
||||
},
|
||||
{
|
||||
/* 6 key. */
|
||||
keyCode: 54,
|
||||
func: toggleSpeakDisplacement,
|
||||
cmd: Command.TOGGLE_DISPLACEMENT,
|
||||
desc: 'Toggle speak displacement'
|
||||
},
|
||||
{
|
||||
/* 7 key. */
|
||||
keyCode: 55,
|
||||
func: focus,
|
||||
cmd: Command.FOCUS_TEXT,
|
||||
desc: 'Focus text'
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Event handler for focus events.
|
||||
*/
|
||||
var onFocus = function() {
|
||||
cvoxAce.editor = editor;
|
||||
|
||||
/* Set up listeners. */
|
||||
editor.getSession().selection.on('changeCursor', onCursorChange);
|
||||
editor.getSession().selection.on('changeSelection', onSelectionChange);
|
||||
editor.getSession().on('change', onChange);
|
||||
editor.getSession().on('changeAnnotation', onAnnotationChange);
|
||||
editor.on('changeStatus', onChangeStatus);
|
||||
editor.on('findSearchBox', onFindSearchbox);
|
||||
editor.container.addEventListener('keydown', onKeyDown);
|
||||
|
||||
lastCursor = editor.selection.getCursor();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the theme.
|
||||
* @param {Object} editor Editor to use.
|
||||
*/
|
||||
var init = function(editor) {
|
||||
onFocus();
|
||||
|
||||
/* Construct maps. */
|
||||
SHORTCUTS.forEach(function(shortcut) {
|
||||
keyCodeToShortcutMap[shortcut.keyCode] = shortcut;
|
||||
cmdToShortcutMap[shortcut.cmd] = shortcut;
|
||||
});
|
||||
|
||||
editor.on('focus', onFocus);
|
||||
|
||||
/* Assume we start in command mode if vim. */
|
||||
if (isVimMode()) {
|
||||
cvox.Api.setKeyEcho(false);
|
||||
}
|
||||
initContextMenu();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns if cvox exists, and the api exists.
|
||||
* @return {boolean} Whether not Cvox Api exists.
|
||||
*/
|
||||
function cvoxApiExists() {
|
||||
return (typeof(cvox) !== 'undefined') && cvox && cvox.Api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of tries for Cvox loading.
|
||||
* @type {number}
|
||||
*/
|
||||
var tries = 0;
|
||||
|
||||
/**
|
||||
* Max number of tries to watch for Cvox loading.
|
||||
* @type {number}
|
||||
*/
|
||||
var MAX_TRIES = 15;
|
||||
|
||||
/**
|
||||
* Check for ChromeVox load.
|
||||
* @param {Object} editor Editor to use.
|
||||
*/
|
||||
function watchForCvoxLoad(editor) {
|
||||
if (cvoxApiExists()) {
|
||||
init(editor);
|
||||
} else {
|
||||
tries++;
|
||||
if (tries >= MAX_TRIES) {
|
||||
return;
|
||||
}
|
||||
window.setTimeout(watchForCvoxLoad, 500, editor);
|
||||
}
|
||||
}
|
||||
|
||||
var Editor = require('../editor').Editor;
|
||||
require('../config').defineOptions(Editor.prototype, 'editor', {
|
||||
enableChromevoxEnhancements: {
|
||||
set: function(val) {
|
||||
if (val) {
|
||||
watchForCvoxLoad(this);
|
||||
}
|
||||
},
|
||||
value: true // turn it on by default or check for window.cvox
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,319 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var ElasticTabstopsLite = function(editor) {
|
||||
this.$editor = editor;
|
||||
var self = this;
|
||||
var changedRows = [];
|
||||
var recordChanges = false;
|
||||
this.onAfterExec = function() {
|
||||
recordChanges = false;
|
||||
self.processRows(changedRows);
|
||||
changedRows = [];
|
||||
};
|
||||
this.onExec = function() {
|
||||
recordChanges = true;
|
||||
};
|
||||
this.onChange = function(e) {
|
||||
var range = e.data.range
|
||||
if (recordChanges) {
|
||||
if (changedRows.indexOf(range.start.row) == -1)
|
||||
changedRows.push(range.start.row);
|
||||
if (range.end.row != range.start.row)
|
||||
changedRows.push(range.end.row);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
(function() {
|
||||
this.processRows = function(rows) {
|
||||
this.$inChange = true;
|
||||
var checkedRows = [];
|
||||
|
||||
for (var r = 0, rowCount = rows.length; r < rowCount; r++) {
|
||||
var row = rows[r];
|
||||
|
||||
if (checkedRows.indexOf(row) > -1)
|
||||
continue;
|
||||
|
||||
var cellWidthObj = this.$findCellWidthsForBlock(row);
|
||||
var cellWidths = this.$setBlockCellWidthsToMax(cellWidthObj.cellWidths);
|
||||
var rowIndex = cellWidthObj.firstRow;
|
||||
|
||||
for (var w = 0, l = cellWidths.length; w < l; w++) {
|
||||
var widths = cellWidths[w];
|
||||
checkedRows.push(rowIndex);
|
||||
this.$adjustRow(rowIndex, widths);
|
||||
rowIndex++;
|
||||
}
|
||||
}
|
||||
this.$inChange = false;
|
||||
};
|
||||
|
||||
this.$findCellWidthsForBlock = function(row) {
|
||||
var cellWidths = [], widths;
|
||||
|
||||
// starting row and backward
|
||||
var rowIter = row;
|
||||
while (rowIter >= 0) {
|
||||
widths = this.$cellWidthsForRow(rowIter);
|
||||
if (widths.length == 0)
|
||||
break;
|
||||
|
||||
cellWidths.unshift(widths);
|
||||
rowIter--;
|
||||
}
|
||||
var firstRow = rowIter + 1;
|
||||
|
||||
// forward (not including starting row)
|
||||
rowIter = row;
|
||||
var numRows = this.$editor.session.getLength();
|
||||
|
||||
while (rowIter < numRows - 1) {
|
||||
rowIter++;
|
||||
|
||||
widths = this.$cellWidthsForRow(rowIter);
|
||||
if (widths.length == 0)
|
||||
break;
|
||||
|
||||
cellWidths.push(widths);
|
||||
}
|
||||
|
||||
return { cellWidths: cellWidths, firstRow: firstRow };
|
||||
};
|
||||
|
||||
this.$cellWidthsForRow = function(row) {
|
||||
var selectionColumns = this.$selectionColumnsForRow(row);
|
||||
// todo: support multicursor
|
||||
|
||||
var tabs = [-1].concat(this.$tabsForRow(row));
|
||||
var widths = tabs.map(function(el) { return 0; } ).slice(1);
|
||||
var line = this.$editor.session.getLine(row);
|
||||
|
||||
for (var i = 0, len = tabs.length - 1; i < len; i++) {
|
||||
var leftEdge = tabs[i]+1;
|
||||
var rightEdge = tabs[i+1];
|
||||
|
||||
var rightmostSelection = this.$rightmostSelectionInCell(selectionColumns, rightEdge);
|
||||
var cell = line.substring(leftEdge, rightEdge);
|
||||
widths[i] = Math.max(cell.replace(/\s+$/g,'').length, rightmostSelection - leftEdge);
|
||||
}
|
||||
|
||||
return widths;
|
||||
};
|
||||
|
||||
this.$selectionColumnsForRow = function(row) {
|
||||
var selections = [], cursor = this.$editor.getCursorPosition();
|
||||
if (this.$editor.session.getSelection().isEmpty()) {
|
||||
// todo: support multicursor
|
||||
if (row == cursor.row)
|
||||
selections.push(cursor.column);
|
||||
}
|
||||
|
||||
return selections;
|
||||
};
|
||||
|
||||
this.$setBlockCellWidthsToMax = function(cellWidths) {
|
||||
var startingNewBlock = true, blockStartRow, blockEndRow, maxWidth;
|
||||
var columnInfo = this.$izip_longest(cellWidths);
|
||||
|
||||
for (var c = 0, l = columnInfo.length; c < l; c++) {
|
||||
var column = columnInfo[c];
|
||||
if (!column.push) {
|
||||
console.error(column);
|
||||
continue;
|
||||
}
|
||||
// add an extra None to the end so that the end of the column automatically
|
||||
// finishes a block
|
||||
column.push(NaN);
|
||||
|
||||
for (var r = 0, s = column.length; r < s; r++) {
|
||||
var width = column[r];
|
||||
if (startingNewBlock) {
|
||||
blockStartRow = r;
|
||||
maxWidth = 0;
|
||||
startingNewBlock = false;
|
||||
}
|
||||
if (isNaN(width)) {
|
||||
// block ended
|
||||
blockEndRow = r;
|
||||
|
||||
for (var j = blockStartRow; j < blockEndRow; j++) {
|
||||
cellWidths[j][c] = maxWidth;
|
||||
}
|
||||
startingNewBlock = true;
|
||||
}
|
||||
|
||||
maxWidth = Math.max(maxWidth, width);
|
||||
}
|
||||
}
|
||||
|
||||
return cellWidths;
|
||||
};
|
||||
|
||||
this.$rightmostSelectionInCell = function(selectionColumns, cellRightEdge) {
|
||||
var rightmost = 0;
|
||||
|
||||
if (selectionColumns.length) {
|
||||
var lengths = [];
|
||||
for (var s = 0, length = selectionColumns.length; s < length; s++) {
|
||||
if (selectionColumns[s] <= cellRightEdge)
|
||||
lengths.push(s);
|
||||
else
|
||||
lengths.push(0);
|
||||
}
|
||||
rightmost = Math.max.apply(Math, lengths);
|
||||
}
|
||||
|
||||
return rightmost;
|
||||
};
|
||||
|
||||
this.$tabsForRow = function(row) {
|
||||
var rowTabs = [], line = this.$editor.session.getLine(row),
|
||||
re = /\t/g, match;
|
||||
|
||||
while ((match = re.exec(line)) != null) {
|
||||
rowTabs.push(match.index);
|
||||
}
|
||||
|
||||
return rowTabs;
|
||||
};
|
||||
|
||||
this.$adjustRow = function(row, widths) {
|
||||
var rowTabs = this.$tabsForRow(row);
|
||||
|
||||
if (rowTabs.length == 0)
|
||||
return;
|
||||
|
||||
var bias = 0, location = -1;
|
||||
|
||||
// this always only contains two elements, so we're safe in the loop below
|
||||
var expandedSet = this.$izip(widths, rowTabs);
|
||||
|
||||
for (var i = 0, l = expandedSet.length; i < l; i++) {
|
||||
var w = expandedSet[i][0], it = expandedSet[i][1];
|
||||
location += 1 + w;
|
||||
it += bias;
|
||||
var difference = location - it;
|
||||
|
||||
if (difference == 0)
|
||||
continue;
|
||||
|
||||
var partialLine = this.$editor.session.getLine(row).substr(0, it );
|
||||
var strippedPartialLine = partialLine.replace(/\s*$/g, "");
|
||||
var ispaces = partialLine.length - strippedPartialLine.length;
|
||||
|
||||
if (difference > 0) {
|
||||
// put the spaces after the tab and then delete the tab, so any insertion
|
||||
// points behave as expected
|
||||
this.$editor.session.getDocument().insertInLine({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t");
|
||||
this.$editor.session.getDocument().removeInLine(row, it, it + 1);
|
||||
|
||||
bias += difference;
|
||||
}
|
||||
|
||||
if (difference < 0 && ispaces >= -difference) {
|
||||
this.$editor.session.getDocument().removeInLine(row, it + difference, it);
|
||||
bias += difference;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// the is a (naive) Python port--but works for these purposes
|
||||
this.$izip_longest = function(iterables) {
|
||||
if (!iterables[0])
|
||||
return [];
|
||||
var longest = iterables[0].length;
|
||||
var iterablesLength = iterables.length;
|
||||
|
||||
for (var i = 1; i < iterablesLength; i++) {
|
||||
var iLength = iterables[i].length;
|
||||
if (iLength > longest)
|
||||
longest = iLength;
|
||||
}
|
||||
|
||||
var expandedSet = [];
|
||||
|
||||
for (var l = 0; l < longest; l++) {
|
||||
var set = [];
|
||||
for (var i = 0; i < iterablesLength; i++) {
|
||||
if (iterables[i][l] === "")
|
||||
set.push(NaN);
|
||||
else
|
||||
set.push(iterables[i][l]);
|
||||
}
|
||||
|
||||
expandedSet.push(set);
|
||||
}
|
||||
|
||||
|
||||
return expandedSet;
|
||||
};
|
||||
|
||||
// an even more (naive) Python port
|
||||
this.$izip = function(widths, tabs) {
|
||||
// grab the shorter size
|
||||
var size = widths.length >= tabs.length ? tabs.length : widths.length;
|
||||
|
||||
var expandedSet = [];
|
||||
for (var i = 0; i < size; i++) {
|
||||
var set = [ widths[i], tabs[i] ];
|
||||
expandedSet.push(set);
|
||||
}
|
||||
return expandedSet;
|
||||
};
|
||||
|
||||
}).call(ElasticTabstopsLite.prototype);
|
||||
|
||||
exports.ElasticTabstopsLite = ElasticTabstopsLite;
|
||||
|
||||
var Editor = require("../editor").Editor;
|
||||
require("../config").defineOptions(Editor.prototype, "editor", {
|
||||
useElasticTabstops: {
|
||||
set: function(val) {
|
||||
if (val) {
|
||||
if (!this.elasticTabstops)
|
||||
this.elasticTabstops = new ElasticTabstopsLite(this);
|
||||
this.commands.on("afterExec", this.elasticTabstops.onAfterExec);
|
||||
this.commands.on("exec", this.elasticTabstops.onExec);
|
||||
this.on("change", this.elasticTabstops.onChange);
|
||||
} else if (this.elasticTabstops) {
|
||||
this.commands.removeListener("afterExec", this.elasticTabstops.onAfterExec);
|
||||
this.commands.removeListener("exec", this.elasticTabstops.onExec);
|
||||
this.removeListener("change", this.elasticTabstops.onChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,434 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
|
||||
var Editor = require("ace/editor").Editor;
|
||||
var snippetManager = require("ace/snippets").snippetManager;
|
||||
var Range = require("ace/range").Range;
|
||||
var emmet, emmetPath;
|
||||
|
||||
/**
|
||||
* Implementation of {@link IEmmetEditor} interface for Ace
|
||||
*/
|
||||
function AceEmmetEditor() {}
|
||||
|
||||
AceEmmetEditor.prototype = {
|
||||
setupContext: function(editor) {
|
||||
this.ace = editor;
|
||||
this.indentation = editor.session.getTabString();
|
||||
if (!emmet)
|
||||
emmet = window.emmet;
|
||||
emmet.require("resources").setVariable("indentation", this.indentation);
|
||||
this.$syntax = null;
|
||||
this.$syntax = this.getSyntax();
|
||||
},
|
||||
/**
|
||||
* Returns character indexes of selected text: object with <code>start</code>
|
||||
* and <code>end</code> properties. If there's no selection, should return
|
||||
* object with <code>start</code> and <code>end</code> properties referring
|
||||
* to current caret position
|
||||
* @return {Object}
|
||||
* @example
|
||||
* var selection = editor.getSelectionRange();
|
||||
* alert(selection.start + ', ' + selection.end);
|
||||
*/
|
||||
getSelectionRange: function() {
|
||||
// TODO should start be caret position instead?
|
||||
var range = this.ace.getSelectionRange();
|
||||
var doc = this.ace.session.doc;
|
||||
return {
|
||||
start: doc.positionToIndex(range.start),
|
||||
end: doc.positionToIndex(range.end)
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates selection from <code>start</code> to <code>end</code> character
|
||||
* indexes. If <code>end</code> is ommited, this method should place caret
|
||||
* and <code>start</code> index
|
||||
* @param {Number} start
|
||||
* @param {Number} [end]
|
||||
* @example
|
||||
* editor.createSelection(10, 40);
|
||||
*
|
||||
* //move caret to 15th character
|
||||
* editor.createSelection(15);
|
||||
*/
|
||||
createSelection: function(start, end) {
|
||||
var doc = this.ace.session.doc;
|
||||
this.ace.selection.setRange({
|
||||
start: doc.indexToPosition(start),
|
||||
end: doc.indexToPosition(end)
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns current line's start and end indexes as object with <code>start</code>
|
||||
* and <code>end</code> properties
|
||||
* @return {Object}
|
||||
* @example
|
||||
* var range = editor.getCurrentLineRange();
|
||||
* alert(range.start + ', ' + range.end);
|
||||
*/
|
||||
getCurrentLineRange: function() {
|
||||
var ace = this.ace;
|
||||
var row = ace.getCursorPosition().row;
|
||||
var lineLength = ace.session.getLine(row).length;
|
||||
var index = ace.session.doc.positionToIndex({row: row, column: 0});
|
||||
return {
|
||||
start: index,
|
||||
end: index + lineLength
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns current caret position
|
||||
* @return {Number|null}
|
||||
*/
|
||||
getCaretPos: function(){
|
||||
var pos = this.ace.getCursorPosition();
|
||||
return this.ace.session.doc.positionToIndex(pos);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set new caret position
|
||||
* @param {Number} index Caret position
|
||||
*/
|
||||
setCaretPos: function(index){
|
||||
var pos = this.ace.session.doc.indexToPosition(index);
|
||||
this.ace.selection.moveToPosition(pos);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns content of current line
|
||||
* @return {String}
|
||||
*/
|
||||
getCurrentLine: function() {
|
||||
var row = this.ace.getCursorPosition().row;
|
||||
return this.ace.session.getLine(row);
|
||||
},
|
||||
|
||||
/**
|
||||
* Replace editor's content or it's part (from <code>start</code> to
|
||||
* <code>end</code> index). If <code>value</code> contains
|
||||
* <code>caret_placeholder</code>, the editor will put caret into
|
||||
* this position. If you skip <code>start</code> and <code>end</code>
|
||||
* arguments, the whole target's content will be replaced with
|
||||
* <code>value</code>.
|
||||
*
|
||||
* If you pass <code>start</code> argument only,
|
||||
* the <code>value</code> will be placed at <code>start</code> string
|
||||
* index of current content.
|
||||
*
|
||||
* If you pass <code>start</code> and <code>end</code> arguments,
|
||||
* the corresponding substring of current target's content will be
|
||||
* replaced with <code>value</code>.
|
||||
* @param {String} value Content you want to paste
|
||||
* @param {Number} [start] Start index of editor's content
|
||||
* @param {Number} [end] End index of editor's content
|
||||
* @param {Boolean} [noIndent] Do not auto indent <code>value</code>
|
||||
*/
|
||||
replaceContent: function(value, start, end, noIndent) {
|
||||
if (end == null)
|
||||
end = start == null ? this.getContent().length : start;
|
||||
if (start == null)
|
||||
start = 0;
|
||||
|
||||
var editor = this.ace;
|
||||
var doc = editor.session.doc;
|
||||
var range = Range.fromPoints(doc.indexToPosition(start), doc.indexToPosition(end));
|
||||
editor.session.remove(range);
|
||||
|
||||
range.end = range.start;
|
||||
//editor.selection.setRange(range);
|
||||
|
||||
value = this.$updateTabstops(value);
|
||||
snippetManager.insertSnippet(editor, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns editor's content
|
||||
* @return {String}
|
||||
*/
|
||||
getContent: function(){
|
||||
return this.ace.getValue();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns current editor's syntax mode
|
||||
* @return {String}
|
||||
*/
|
||||
getSyntax: function() {
|
||||
if (this.$syntax)
|
||||
return this.$syntax;
|
||||
var syntax = this.ace.session.$modeId.split("/").pop();
|
||||
if (syntax == "html" || syntax == "php") {
|
||||
var cursor = this.ace.getCursorPosition();
|
||||
var state = this.ace.session.getState(cursor.row);
|
||||
if (typeof state != "string")
|
||||
state = state[0];
|
||||
if (state) {
|
||||
state = state.split("-");
|
||||
if (state.length > 1)
|
||||
syntax = state[0];
|
||||
else if (syntax == "php")
|
||||
syntax = "html";
|
||||
}
|
||||
}
|
||||
return syntax;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns current output profile name (@see emmet#setupProfile)
|
||||
* @return {String}
|
||||
*/
|
||||
getProfileName: function() {
|
||||
switch(this.getSyntax()) {
|
||||
case "css": return "css";
|
||||
case "xml":
|
||||
case "xsl":
|
||||
return "xml";
|
||||
case "html":
|
||||
var profile = emmet.require("resources").getVariable("profile");
|
||||
// no forced profile, guess from content html or xhtml?
|
||||
if (!profile)
|
||||
profile = this.ace.session.getLines(0,2).join("").search(/<!DOCTYPE[^>]+XHTML/i) != -1 ? "xhtml": "html";
|
||||
return profile;
|
||||
}
|
||||
return "xhtml";
|
||||
},
|
||||
|
||||
/**
|
||||
* Ask user to enter something
|
||||
* @param {String} title Dialog title
|
||||
* @return {String} Entered data
|
||||
* @since 0.65
|
||||
*/
|
||||
prompt: function(title) {
|
||||
return prompt(title);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns current selection
|
||||
* @return {String}
|
||||
* @since 0.65
|
||||
*/
|
||||
getSelection: function() {
|
||||
return this.ace.session.getTextRange();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns current editor's file path
|
||||
* @return {String}
|
||||
* @since 0.65
|
||||
*/
|
||||
getFilePath: function() {
|
||||
return "";
|
||||
},
|
||||
|
||||
// update tabstops: make sure all caret placeholders are unique
|
||||
// by default, abbreviation parser generates all unlinked (un-mirrored)
|
||||
// tabstops as ${0}, so we have upgrade all caret tabstops with unique
|
||||
// positions but make sure that all other tabstops are not linked accidentally
|
||||
// based on https://github.com/sergeche/emmet-sublime/blob/master/editor.js#L119-L171
|
||||
$updateTabstops: function(value) {
|
||||
var base = 1000;
|
||||
var zeroBase = 0;
|
||||
var lastZero = null;
|
||||
var range = emmet.require('range');
|
||||
var ts = emmet.require('tabStops');
|
||||
var settings = emmet.require('resources').getVocabulary("user");
|
||||
var tabstopOptions = {
|
||||
tabstop: function(data) {
|
||||
var group = parseInt(data.group, 10);
|
||||
var isZero = group === 0;
|
||||
if (isZero)
|
||||
group = ++zeroBase;
|
||||
else
|
||||
group += base;
|
||||
|
||||
var placeholder = data.placeholder;
|
||||
if (placeholder) {
|
||||
// recursively update nested tabstops
|
||||
placeholder = ts.processText(placeholder, tabstopOptions);
|
||||
}
|
||||
|
||||
var result = '${' + group + (placeholder ? ':' + placeholder : '') + '}';
|
||||
|
||||
if (isZero) {
|
||||
lastZero = range.create(data.start, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
escape: function(ch) {
|
||||
if (ch == '$') return '\\$';
|
||||
if (ch == '\\') return '\\\\';
|
||||
return ch;
|
||||
}
|
||||
};
|
||||
|
||||
value = ts.processText(value, tabstopOptions);
|
||||
|
||||
if (settings.variables['insert_final_tabstop'] && !/\$\{0\}$/.test(value)) {
|
||||
value += '${0}';
|
||||
} else if (lastZero) {
|
||||
value = emmet.require('utils').replaceSubstring(value, '${0}', lastZero);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var keymap = {
|
||||
expand_abbreviation: {"mac": "ctrl+alt+e", "win": "alt+e"},
|
||||
match_pair_outward: {"mac": "ctrl+d", "win": "ctrl+,"},
|
||||
match_pair_inward: {"mac": "ctrl+j", "win": "ctrl+shift+0"},
|
||||
matching_pair: {"mac": "ctrl+alt+j", "win": "alt+j"},
|
||||
next_edit_point: "alt+right",
|
||||
prev_edit_point: "alt+left",
|
||||
toggle_comment: {"mac": "command+/", "win": "ctrl+/"},
|
||||
split_join_tag: {"mac": "shift+command+'", "win": "shift+ctrl+`"},
|
||||
remove_tag: {"mac": "command+'", "win": "shift+ctrl+;"},
|
||||
evaluate_math_expression: {"mac": "shift+command+y", "win": "shift+ctrl+y"},
|
||||
increment_number_by_1: "ctrl+up",
|
||||
decrement_number_by_1: "ctrl+down",
|
||||
increment_number_by_01: "alt+up",
|
||||
decrement_number_by_01: "alt+down",
|
||||
increment_number_by_10: {"mac": "alt+command+up", "win": "shift+alt+up"},
|
||||
decrement_number_by_10: {"mac": "alt+command+down", "win": "shift+alt+down"},
|
||||
select_next_item: {"mac": "shift+command+.", "win": "shift+ctrl+."},
|
||||
select_previous_item: {"mac": "shift+command+,", "win": "shift+ctrl+,"},
|
||||
reflect_css_value: {"mac": "shift+command+r", "win": "shift+ctrl+r"},
|
||||
|
||||
encode_decode_data_url: {"mac": "shift+ctrl+d", "win": "ctrl+'"},
|
||||
// update_image_size: {"mac": "shift+ctrl+i", "win": "ctrl+u"},
|
||||
// expand_as_you_type: "ctrl+alt+enter",
|
||||
// wrap_as_you_type: {"mac": "shift+ctrl+g", "win": "shift+ctrl+g"},
|
||||
expand_abbreviation_with_tab: "Tab",
|
||||
wrap_with_abbreviation: {"mac": "shift+ctrl+a", "win": "shift+ctrl+a"}
|
||||
};
|
||||
|
||||
var editorProxy = new AceEmmetEditor();
|
||||
exports.commands = new HashHandler();
|
||||
exports.runEmmetCommand = function(editor) {
|
||||
try {
|
||||
editorProxy.setupContext(editor);
|
||||
if (editorProxy.getSyntax() == "php")
|
||||
return false;
|
||||
var actions = emmet.require("actions");
|
||||
|
||||
if (this.action == "expand_abbreviation_with_tab") {
|
||||
if (!editor.selection.isEmpty())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.action == "wrap_with_abbreviation") {
|
||||
// without setTimeout prompt doesn't work on firefox
|
||||
return setTimeout(function() {
|
||||
actions.run("wrap_with_abbreviation", editorProxy);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
var pos = editor.selection.lead;
|
||||
var token = editor.session.getTokenAt(pos.row, pos.column);
|
||||
if (token && /\btag\b/.test(token.type))
|
||||
return false;
|
||||
|
||||
var result = actions.run(this.action, editorProxy);
|
||||
} catch(e) {
|
||||
editor._signal("changeStatus", typeof e == "string" ? e : e.message);
|
||||
console.log(e);
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
for (var command in keymap) {
|
||||
exports.commands.addCommand({
|
||||
name: "emmet:" + command,
|
||||
action: command,
|
||||
bindKey: keymap[command],
|
||||
exec: exports.runEmmetCommand,
|
||||
multiSelectAction: "forEach"
|
||||
});
|
||||
}
|
||||
|
||||
exports.updateCommands = function(editor, enabled) {
|
||||
if (enabled) {
|
||||
editor.keyBinding.addKeyboardHandler(exports.commands);
|
||||
} else {
|
||||
editor.keyBinding.removeKeyboardHandler(exports.commands);
|
||||
}
|
||||
};
|
||||
|
||||
exports.isSupportedMode = function(modeId) {
|
||||
return modeId && /css|less|scss|sass|stylus|html|php|twig|ejs/.test(modeId);
|
||||
};
|
||||
|
||||
var onChangeMode = function(e, target) {
|
||||
var editor = target;
|
||||
if (!editor)
|
||||
return;
|
||||
var enabled = exports.isSupportedMode(editor.session.$modeId);
|
||||
if (e.enableEmmet === false)
|
||||
enabled = false;
|
||||
if (enabled) {
|
||||
if (typeof emmetPath == "string") {
|
||||
require("ace/config").loadModule(emmetPath, function() {
|
||||
emmetPath = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.updateCommands(editor, enabled);
|
||||
};
|
||||
|
||||
exports.AceEmmetEditor = AceEmmetEditor;
|
||||
require("ace/config").defineOptions(Editor.prototype, "editor", {
|
||||
enableEmmet: {
|
||||
set: function(val) {
|
||||
this[val ? "on" : "removeListener"]("changeMode", onChangeMode);
|
||||
onChangeMode({enableEmmet: !!val}, this);
|
||||
},
|
||||
value: true
|
||||
}
|
||||
});
|
||||
|
||||
exports.setCore = function(e) {
|
||||
if (typeof e == "string")
|
||||
emmetPath = e;
|
||||
else
|
||||
emmet = e;
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var LineWidgets = require("../line_widgets").LineWidgets;
|
||||
var dom = require("../lib/dom");
|
||||
var Range = require("../range").Range;
|
||||
|
||||
function binarySearch(array, needle, comparator) {
|
||||
var first = 0;
|
||||
var last = array.length - 1;
|
||||
|
||||
while (first <= last) {
|
||||
var mid = (first + last) >> 1;
|
||||
var c = comparator(needle, array[mid]);
|
||||
if (c > 0)
|
||||
first = mid + 1;
|
||||
else if (c < 0)
|
||||
last = mid - 1;
|
||||
else
|
||||
return mid;
|
||||
}
|
||||
|
||||
// Return the nearest lesser index, "-1" means "0, "-2" means "1", etc.
|
||||
return -(first + 1);
|
||||
}
|
||||
|
||||
function findAnnotations(session, row, dir) {
|
||||
var annotations = session.getAnnotations().sort(Range.comparePoints);
|
||||
if (!annotations.length)
|
||||
return;
|
||||
|
||||
var i = binarySearch(annotations, {row: row, column: -1}, Range.comparePoints);
|
||||
if (i < 0)
|
||||
i = -i - 1;
|
||||
|
||||
if (i >= annotations.length - 1)
|
||||
i = dir > 0 ? 0 : annotations.length - 1;
|
||||
else if (i === 0 && dir < 0)
|
||||
i = annotations.length - 1;
|
||||
|
||||
var annotation = annotations[i];
|
||||
if (!annotation || !dir)
|
||||
return;
|
||||
|
||||
if (annotation.row === row) {
|
||||
do {
|
||||
annotation = annotations[i += dir];
|
||||
} while (annotation && annotation.row === row);
|
||||
if (!annotation)
|
||||
return annotations.slice();
|
||||
}
|
||||
|
||||
|
||||
var matched = [];
|
||||
row = annotation.row;
|
||||
do {
|
||||
matched[dir < 0 ? "unshift" : "push"](annotation);
|
||||
annotation = annotations[i += dir];
|
||||
} while (annotation && annotation.row == row);
|
||||
return matched.length && matched;
|
||||
}
|
||||
|
||||
exports.showErrorMarker = function(editor, dir) {
|
||||
var session = editor.session;
|
||||
if (!session.widgetManager) {
|
||||
session.widgetManager = new LineWidgets(session);
|
||||
session.widgetManager.attach(editor);
|
||||
}
|
||||
|
||||
var pos = editor.getCursorPosition();
|
||||
var row = pos.row;
|
||||
var oldWidget = session.lineWidgets && session.lineWidgets[row];
|
||||
if (oldWidget) {
|
||||
oldWidget.destroy();
|
||||
} else {
|
||||
row -= dir;
|
||||
}
|
||||
var annotations = findAnnotations(session, row, dir);
|
||||
var gutterAnno;
|
||||
if (annotations) {
|
||||
var annotation = annotations[0];
|
||||
pos.column = (annotation.pos && typeof annotation.column != "number"
|
||||
? annotation.pos.sc
|
||||
: annotation.column) || 0;
|
||||
pos.row = annotation.row;
|
||||
gutterAnno = editor.renderer.$gutterLayer.$annotations[pos.row];
|
||||
} else if (oldWidget) {
|
||||
return;
|
||||
} else {
|
||||
gutterAnno = {
|
||||
text: ["Looks good!"],
|
||||
className: "ace_ok"
|
||||
};
|
||||
}
|
||||
editor.session.unfold(pos.row);
|
||||
editor.selection.moveToPosition(pos);
|
||||
|
||||
var w = {
|
||||
row: pos.row,
|
||||
fixedWidth: true,
|
||||
coverGutter: true,
|
||||
el: dom.createElement("div")
|
||||
};
|
||||
var el = w.el.appendChild(dom.createElement("div"));
|
||||
var arrow = w.el.appendChild(dom.createElement("div"));
|
||||
arrow.className = "error_widget_arrow " + gutterAnno.className;
|
||||
|
||||
var left = editor.renderer.$cursorLayer
|
||||
.getPixelPosition(pos).left;
|
||||
arrow.style.left = left + editor.renderer.gutterWidth - 5 + "px";
|
||||
|
||||
w.el.className = "error_widget_wrapper";
|
||||
el.className = "error_widget " + gutterAnno.className;
|
||||
el.innerHTML = gutterAnno.text.join("<br>");
|
||||
|
||||
el.appendChild(dom.createElement("div"));
|
||||
|
||||
var kb = function(_, hashId, keyString) {
|
||||
if (hashId === 0 && (keyString === "esc" || keyString === "return")) {
|
||||
w.destroy();
|
||||
return {command: "null"};
|
||||
}
|
||||
};
|
||||
|
||||
w.destroy = function() {
|
||||
if (editor.$mouseHandler.isMousePressed)
|
||||
return;
|
||||
editor.keyBinding.removeKeyboardHandler(kb);
|
||||
session.widgetManager.removeLineWidget(w);
|
||||
editor.off("changeSelection", w.destroy);
|
||||
editor.off("changeSession", w.destroy);
|
||||
editor.off("mouseup", w.destroy);
|
||||
editor.off("change", w.destroy);
|
||||
};
|
||||
|
||||
editor.keyBinding.addKeyboardHandler(kb);
|
||||
editor.on("changeSelection", w.destroy);
|
||||
editor.on("changeSession", w.destroy);
|
||||
editor.on("mouseup", w.destroy);
|
||||
editor.on("change", w.destroy);
|
||||
|
||||
editor.session.widgetManager.addLineWidget(w);
|
||||
|
||||
w.el.onmousedown = editor.focus.bind(editor);
|
||||
|
||||
editor.renderer.scrollCursorIntoView(null, 0.5, {bottom: w.el.offsetHeight});
|
||||
};
|
||||
|
||||
|
||||
dom.importCssString("\
|
||||
.error_widget_wrapper {\
|
||||
background: inherit;\
|
||||
color: inherit;\
|
||||
border:none\
|
||||
}\
|
||||
.error_widget {\
|
||||
border-top: solid 2px;\
|
||||
border-bottom: solid 2px;\
|
||||
margin: 5px 0;\
|
||||
padding: 10px 40px;\
|
||||
white-space: pre-wrap;\
|
||||
}\
|
||||
.error_widget.ace_error, .error_widget_arrow.ace_error{\
|
||||
border-color: #ff5a5a\
|
||||
}\
|
||||
.error_widget.ace_warning, .error_widget_arrow.ace_warning{\
|
||||
border-color: #F1D817\
|
||||
}\
|
||||
.error_widget.ace_info, .error_widget_arrow.ace_info{\
|
||||
border-color: #5a5a5a\
|
||||
}\
|
||||
.error_widget.ace_ok, .error_widget_arrow.ace_ok{\
|
||||
border-color: #5aaa5a\
|
||||
}\
|
||||
.error_widget_arrow {\
|
||||
position: absolute;\
|
||||
border: solid 5px;\
|
||||
border-top-color: transparent!important;\
|
||||
border-right-color: transparent!important;\
|
||||
border-left-color: transparent!important;\
|
||||
top: -5px;\
|
||||
}\
|
||||
", "");
|
||||
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
|
||||
/*global define, require */
|
||||
|
||||
/**
|
||||
* Show Keyboard Shortcuts
|
||||
* @fileOverview Show Keyboard Shortcuts <br />
|
||||
* Generates a menu which displays the keyboard shortcuts.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var Editor = require("ace/editor").Editor;
|
||||
/**
|
||||
* Generates a menu which displays the keyboard shortcuts.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {ace.Editor} editor An instance of the ace editor.
|
||||
*/
|
||||
function showKeyboardShortcuts (editor) {
|
||||
// make sure the menu isn't open already.
|
||||
if(!document.getElementById('kbshortcutmenu')) {
|
||||
var overlayPage = require('./menu_tools/overlay_page').overlayPage;
|
||||
var getEditorKeybordShortcuts = require('./menu_tools/get_editor_keyboard_shortcuts').getEditorKeybordShortcuts;
|
||||
var kb = getEditorKeybordShortcuts(editor);
|
||||
var el = document.createElement('div');
|
||||
var commands = kb.reduce(function(previous, current) {
|
||||
return previous + '<div class="ace_optionsMenuEntry"><span class="ace_optionsMenuCommand">'
|
||||
+ current.command + '</span> : '
|
||||
+ '<span class="ace_optionsMenuKey">' + current.key + '</span></div>';
|
||||
}, '');
|
||||
|
||||
el.id = 'kbshortcutmenu';
|
||||
el.innerHTML = '<h1>Keyboard Shortcuts</h1>' + commands + '</div>';
|
||||
overlayPage(editor, el, '0', '0', '0', null);
|
||||
}
|
||||
};
|
||||
module.exports.init = function(editor) {
|
||||
Editor.prototype.showKeyboardShortcuts = function() {
|
||||
showKeyboardShortcuts(this);
|
||||
};
|
||||
editor.commands.addCommands([{
|
||||
name: "showKeyboardShortcuts",
|
||||
bindKey: {win: "Ctrl-Alt-h", mac: "Command-Alt-h"},
|
||||
exec: function(editor, line) {
|
||||
editor.showKeyboardShortcuts();
|
||||
}
|
||||
}]);
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,226 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2012, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var snippetManager = require("../snippets").snippetManager;
|
||||
var Autocomplete = require("../autocomplete").Autocomplete;
|
||||
var config = require("../config");
|
||||
var lang = require("../lib/lang");
|
||||
var util = require("../autocomplete/util");
|
||||
|
||||
var textCompleter = require("../autocomplete/text_completer");
|
||||
var keyWordCompleter = {
|
||||
getCompletions: function(editor, session, pos, prefix, callback) {
|
||||
if (session.$mode.completer) {
|
||||
return session.$mode.completer.getCompletions(editor, session, pos, prefix, callback);
|
||||
}
|
||||
var state = editor.session.getState(pos.row);
|
||||
var completions = session.$mode.getCompletions(state, session, pos, prefix);
|
||||
callback(null, completions);
|
||||
}
|
||||
};
|
||||
|
||||
var snippetCompleter = {
|
||||
getCompletions: function(editor, session, pos, prefix, callback) {
|
||||
var snippetMap = snippetManager.snippetMap;
|
||||
var completions = [];
|
||||
snippetManager.getActiveScopes(editor).forEach(function(scope) {
|
||||
var snippets = snippetMap[scope] || [];
|
||||
for (var i = snippets.length; i--;) {
|
||||
var s = snippets[i];
|
||||
var caption = s.name || s.tabTrigger;
|
||||
if (!caption)
|
||||
continue;
|
||||
completions.push({
|
||||
caption: caption,
|
||||
snippet: s.content,
|
||||
meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet",
|
||||
type: "snippet"
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
callback(null, completions);
|
||||
},
|
||||
getDocTooltip: function(item) {
|
||||
if (item.type == "snippet" && !item.docHTML) {
|
||||
item.docHTML = [
|
||||
"<b>", lang.escapeHTML(item.caption), "</b>", "<hr></hr>",
|
||||
lang.escapeHTML(item.snippet)
|
||||
].join("");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var completers = [snippetCompleter, textCompleter, keyWordCompleter];
|
||||
// Allows default completers to be removed or replaced with a explict set of completers
|
||||
// A null argument here will result in an empty completer array, not a null attribute
|
||||
exports.setCompleters = function(val) {
|
||||
completers = val || [];
|
||||
};
|
||||
exports.addCompleter = function(completer) {
|
||||
completers.push(completer);
|
||||
};
|
||||
|
||||
// Exports existing completer so that user can construct his own set of completers.
|
||||
exports.textCompleter = textCompleter;
|
||||
exports.keyWordCompleter = keyWordCompleter;
|
||||
exports.snippetCompleter = snippetCompleter;
|
||||
|
||||
var expandSnippet = {
|
||||
name: "expandSnippet",
|
||||
exec: function(editor) {
|
||||
return snippetManager.expandWithTab(editor);
|
||||
},
|
||||
bindKey: "Tab"
|
||||
};
|
||||
|
||||
var onChangeMode = function(e, editor) {
|
||||
loadSnippetsForMode(editor.session.$mode);
|
||||
};
|
||||
|
||||
var loadSnippetsForMode = function(mode) {
|
||||
var id = mode.$id;
|
||||
if (!snippetManager.files)
|
||||
snippetManager.files = {};
|
||||
loadSnippetFile(id);
|
||||
if (mode.modes)
|
||||
mode.modes.forEach(loadSnippetsForMode);
|
||||
};
|
||||
|
||||
var loadSnippetFile = function(id) {
|
||||
if (!id || snippetManager.files[id])
|
||||
return;
|
||||
var snippetFilePath = id.replace("mode", "snippets");
|
||||
snippetManager.files[id] = {};
|
||||
config.loadModule(snippetFilePath, function(m) {
|
||||
if (m) {
|
||||
snippetManager.files[id] = m;
|
||||
if (!m.snippets && m.snippetText)
|
||||
m.snippets = snippetManager.parseSnippetFile(m.snippetText);
|
||||
snippetManager.register(m.snippets || [], m.scope);
|
||||
if (m.includeScopes) {
|
||||
snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes;
|
||||
m.includeScopes.forEach(function(x) {
|
||||
loadSnippetFile("ace/mode/" + x);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function getCompletionPrefix(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var line = editor.session.getLine(pos.row);
|
||||
var prefix;
|
||||
// Try to find custom prefixes on the completers
|
||||
editor.completers.forEach(function(completer) {
|
||||
if (completer.identifierRegexps) {
|
||||
completer.identifierRegexps.forEach(function(identifierRegex) {
|
||||
if (!prefix && identifierRegex)
|
||||
prefix = util.retrievePrecedingIdentifier(line, pos.column, identifierRegex);
|
||||
});
|
||||
}
|
||||
});
|
||||
return prefix || util.retrievePrecedingIdentifier(line, pos.column);
|
||||
}
|
||||
|
||||
var doLiveAutocomplete = function(e) {
|
||||
var editor = e.editor;
|
||||
var text = e.args || "";
|
||||
var hasCompleter = editor.completer && editor.completer.activated;
|
||||
|
||||
// We don't want to autocomplete with no prefix
|
||||
if (e.command.name === "backspace") {
|
||||
if (hasCompleter && !getCompletionPrefix(editor))
|
||||
editor.completer.detach();
|
||||
}
|
||||
else if (e.command.name === "insertstring") {
|
||||
var prefix = getCompletionPrefix(editor);
|
||||
// Only autocomplete if there's a prefix that can be matched
|
||||
if (prefix && !hasCompleter) {
|
||||
if (!editor.completer) {
|
||||
// Create new autocompleter
|
||||
editor.completer = new Autocomplete();
|
||||
}
|
||||
// Disable autoInsert
|
||||
editor.completer.autoInsert = false;
|
||||
editor.completer.showPopup(editor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var Editor = require("../editor").Editor;
|
||||
require("../config").defineOptions(Editor.prototype, "editor", {
|
||||
enableBasicAutocompletion: {
|
||||
set: function(val) {
|
||||
if (val) {
|
||||
if (!this.completers)
|
||||
this.completers = Array.isArray(val)? val: completers;
|
||||
this.commands.addCommand(Autocomplete.startCommand);
|
||||
} else {
|
||||
this.commands.removeCommand(Autocomplete.startCommand);
|
||||
}
|
||||
},
|
||||
value: false
|
||||
},
|
||||
/**
|
||||
* Enable live autocomplete. If the value is an array, it is assumed to be an array of completers
|
||||
* and will use them instead of the default completers.
|
||||
*/
|
||||
enableLiveAutocompletion: {
|
||||
set: function(val) {
|
||||
if (val) {
|
||||
if (!this.completers)
|
||||
this.completers = Array.isArray(val)? val: completers;
|
||||
// On each change automatically trigger the autocomplete
|
||||
this.commands.on('afterExec', doLiveAutocomplete);
|
||||
} else {
|
||||
this.commands.removeListener('afterExec', doLiveAutocomplete);
|
||||
}
|
||||
},
|
||||
value: false
|
||||
},
|
||||
enableSnippets: {
|
||||
set: function(val) {
|
||||
if (val) {
|
||||
this.commands.addCommand(expandSnippet);
|
||||
this.on("changeMode", onChangeMode);
|
||||
onChangeMode(null, this);
|
||||
} else {
|
||||
this.commands.removeCommand(expandSnippet);
|
||||
this.off("changeMode", onChangeMode);
|
||||
}
|
||||
},
|
||||
value: false
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var Editor = require("ace/editor").Editor;
|
||||
|
||||
require("../config").defineOptions(Editor.prototype, "editor", {
|
||||
enableLinking: {
|
||||
set: function(val) {
|
||||
if (val) {
|
||||
this.on("click", onClick);
|
||||
this.on("mousemove", onMouseMove);
|
||||
} else {
|
||||
this.off("click", onClick);
|
||||
this.off("mousemove", onMouseMove);
|
||||
}
|
||||
},
|
||||
value: false
|
||||
}
|
||||
})
|
||||
|
||||
function onMouseMove(e) {
|
||||
var editor = e.editor;
|
||||
var ctrl = e.getAccelKey();
|
||||
|
||||
if (ctrl) {
|
||||
var editor = e.editor;
|
||||
var docPos = e.getDocumentPosition();
|
||||
var session = editor.session;
|
||||
var token = session.getTokenAt(docPos.row, docPos.column);
|
||||
|
||||
editor._emit("linkHover", {position: docPos, token: token});
|
||||
}
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
var ctrl = e.getAccelKey();
|
||||
var button = e.getButton();
|
||||
|
||||
if (button == 0 && ctrl) {
|
||||
var editor = e.editor;
|
||||
var docPos = e.getDocumentPosition();
|
||||
var session = editor.session;
|
||||
var token = session.getTokenAt(docPos.row, docPos.column);
|
||||
|
||||
editor._emit("linkClick", {position: docPos, token: token});
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
|
||||
/*global define, require */
|
||||
|
||||
/**
|
||||
* Add Editor Menu Options
|
||||
* @fileOverview Add Editor Menu Options <br />
|
||||
* The menu options property needs to be added to the editor
|
||||
* so that the settings menu can know about options for
|
||||
* selection elements and track which option is selected.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* The menu options property needs to be added to the editor
|
||||
* so that the settings menu can know about options for
|
||||
* selection elements and track which option is selected.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {ace.Editor} editor An instance of the ace editor.
|
||||
*/
|
||||
module.exports.addEditorMenuOptions = function addEditorMenuOptions (editor) {
|
||||
var modelist = require('../modelist');
|
||||
var themelist = require('../themelist');
|
||||
editor.menuOptions = {
|
||||
setNewLineMode: [{
|
||||
textContent: "unix",
|
||||
value: "unix"
|
||||
}, {
|
||||
textContent: "windows",
|
||||
value: "windows"
|
||||
}, {
|
||||
textContent: "auto",
|
||||
value: "auto"
|
||||
}],
|
||||
setTheme: [],
|
||||
setMode: [],
|
||||
setKeyboardHandler: [{
|
||||
textContent: "ace",
|
||||
value: ""
|
||||
}, {
|
||||
textContent: "vim",
|
||||
value: "ace/keyboard/vim"
|
||||
}, {
|
||||
textContent: "emacs",
|
||||
value: "ace/keyboard/emacs"
|
||||
}, {
|
||||
textContent: "textarea",
|
||||
value: "ace/keyboard/textarea"
|
||||
}, {
|
||||
textContent: "sublime",
|
||||
value: "ace/keyboard/sublime"
|
||||
}]
|
||||
};
|
||||
|
||||
editor.menuOptions.setTheme = themelist.themes.map(function(theme) {
|
||||
return {
|
||||
textContent: theme.caption,
|
||||
value: theme.theme
|
||||
};
|
||||
});
|
||||
|
||||
editor.menuOptions.setMode = modelist.modes.map(function(mode) {
|
||||
return {
|
||||
textContent: mode.name,
|
||||
value: mode.mode
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
|
||||
/*global define, require */
|
||||
|
||||
/**
|
||||
* Element Generator
|
||||
* @fileOverview Element Generator <br />
|
||||
* Contains methods for generating elements.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
/**
|
||||
* Creates a DOM option element
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {object} obj An object containing properties to add to the dom
|
||||
* element. If one of those properties is named `selected` then it will be
|
||||
* added as an attribute on the element instead.
|
||||
*/
|
||||
module.exports.createOption = function createOption (obj) {
|
||||
var attribute;
|
||||
var el = document.createElement('option');
|
||||
for(attribute in obj) {
|
||||
if(obj.hasOwnProperty(attribute)) {
|
||||
if(attribute === 'selected') {
|
||||
el.setAttribute(attribute, obj[attribute]);
|
||||
} else {
|
||||
el[attribute] = obj[attribute];
|
||||
}
|
||||
}
|
||||
}
|
||||
return el;
|
||||
};
|
||||
/**
|
||||
* Creates a DOM checkbox element.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {string} id The id of the element.
|
||||
* @param {boolean} checked Whether or not the element is checked.
|
||||
* @param {string} clss The class of the element.
|
||||
* @returns {DOMElement} Returns a checkbox element reference.
|
||||
*/
|
||||
module.exports.createCheckbox = function createCheckbox (id, checked, clss) {
|
||||
var el = document.createElement('input');
|
||||
el.setAttribute('type', 'checkbox');
|
||||
el.setAttribute('id', id);
|
||||
el.setAttribute('name', id);
|
||||
el.setAttribute('value', checked);
|
||||
el.setAttribute('class', clss);
|
||||
if(checked) {
|
||||
el.setAttribute('checked', 'checked');
|
||||
}
|
||||
return el;
|
||||
};
|
||||
/**
|
||||
* Creates a DOM text input element.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {string} id The id of the element.
|
||||
* @param {string} value The default value of the input element.
|
||||
* @param {string} clss The class of the element.
|
||||
* @returns {DOMElement} Returns an input element reference.
|
||||
*/
|
||||
module.exports.createInput = function createInput (id, value, clss) {
|
||||
var el = document.createElement('input');
|
||||
el.setAttribute('type', 'text');
|
||||
el.setAttribute('id', id);
|
||||
el.setAttribute('name', id);
|
||||
el.setAttribute('value', value);
|
||||
el.setAttribute('class', clss);
|
||||
return el;
|
||||
};
|
||||
/**
|
||||
* Creates a DOM label element.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {string} text The label text.
|
||||
* @param {string} labelFor The id of the element being labeled.
|
||||
* @returns {DOMElement} Returns a label element reference.
|
||||
*/
|
||||
module.exports.createLabel = function createLabel (text, labelFor) {
|
||||
var el = document.createElement('label');
|
||||
el.setAttribute('for', labelFor);
|
||||
el.textContent = text;
|
||||
return el;
|
||||
};
|
||||
/**
|
||||
* Creates a DOM selection element.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {string} id The id of the element.
|
||||
* @param {string} values An array of objects suitable for `createOption`
|
||||
* @param {string} clss The class of the element.
|
||||
* @returns {DOMElement} Returns a selection element reference.
|
||||
* @see ace/ext/element_generator.createOption
|
||||
*/
|
||||
module.exports.createSelection = function createSelection (id, values, clss) {
|
||||
var el = document.createElement('select');
|
||||
el.setAttribute('id', id);
|
||||
el.setAttribute('name', id);
|
||||
el.setAttribute('class', clss);
|
||||
values.forEach(function(item) {
|
||||
el.appendChild(module.exports.createOption(item));
|
||||
});
|
||||
return el;
|
||||
};
|
||||
|
||||
});
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* Generates the settings menu
|
||||
* @fileOverview Generates the settings menu.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
var egen = require('./element_generator');
|
||||
var addEditorMenuOptions = require('./add_editor_menu_options').addEditorMenuOptions;
|
||||
var getSetFunctions = require('./get_set_functions').getSetFunctions;
|
||||
|
||||
/**
|
||||
* Generates an interactive menu with settings useful to end users.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {ace.Editor} editor An instance of the ace editor.
|
||||
*/
|
||||
module.exports.generateSettingsMenu = function generateSettingsMenu (editor) {
|
||||
/**
|
||||
* container for dom elements that will go in the menu.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
var elements = [];
|
||||
/**
|
||||
* Sorts the menu entries (elements var) so they'll appear in alphabetical order
|
||||
* the sort is performed based on the value of the contains property
|
||||
* of each element. Since this is an `array.sort` the array is sorted
|
||||
* in place.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
function cleanupElementsList() {
|
||||
elements.sort(function(a, b) {
|
||||
var x = a.getAttribute('contains');
|
||||
var y = b.getAttribute('contains');
|
||||
return x.localeCompare(y);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Wraps all dom elements contained in the elements var with a single
|
||||
* div.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
function wrapElements() {
|
||||
var topmenu = document.createElement('div');
|
||||
topmenu.setAttribute('id', 'ace_settingsmenu');
|
||||
elements.forEach(function(element) {
|
||||
topmenu.appendChild(element);
|
||||
});
|
||||
|
||||
var el = topmenu.appendChild(document.createElement('div'));
|
||||
var version = "1.1.8";
|
||||
el.style.padding = "1em";
|
||||
el.textContent = "Ace version " + version;
|
||||
|
||||
return topmenu;
|
||||
}
|
||||
/**
|
||||
* Creates a new menu entry.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {object} obj This is a reference to the object containing the
|
||||
* set function. It is used to set up event listeners for when the
|
||||
* menu options change.
|
||||
* @param {string} clss Maps to the class of the dom element. This is
|
||||
* the name of the object containing the set function e.g. `editor`,
|
||||
* `session`, `renderer`.
|
||||
* @param {string} item This is the set function name. It maps to the
|
||||
* id of the dom element (check, select, input) and to the "contains"
|
||||
* attribute of the div holding both the element and its label.
|
||||
* @param {mixed} val This is the value of the setting. It is mapped to
|
||||
* the dom element's value, checked, or selected option accordingly.
|
||||
*/
|
||||
function createNewEntry(obj, clss, item, val) {
|
||||
var el;
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('contains', item);
|
||||
div.setAttribute('class', 'ace_optionsMenuEntry');
|
||||
div.setAttribute('style', 'clear: both;');
|
||||
|
||||
div.appendChild(egen.createLabel(
|
||||
item.replace(/^set/, '').replace(/([A-Z])/g, ' $1').trim(),
|
||||
item
|
||||
));
|
||||
|
||||
if (Array.isArray(val)) {
|
||||
el = egen.createSelection(item, val, clss);
|
||||
el.addEventListener('change', function(e) {
|
||||
try{
|
||||
editor.menuOptions[e.target.id].forEach(function(x) {
|
||||
if(x.textContent !== e.target.textContent) {
|
||||
delete x.selected;
|
||||
}
|
||||
});
|
||||
obj[e.target.id](e.target.value);
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
});
|
||||
} else if(typeof val === 'boolean') {
|
||||
el = egen.createCheckbox(item, val, clss);
|
||||
el.addEventListener('change', function(e) {
|
||||
try{
|
||||
// renderer['setHighlightGutterLine'](true);
|
||||
obj[e.target.id](!!e.target.checked);
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// this aids in giving the ability to specify settings through
|
||||
// post and get requests.
|
||||
// /ace_editor.html?setMode=ace/mode/html&setOverwrite=true
|
||||
el = egen.createInput(item, val, clss);
|
||||
el.addEventListener('change', function(e) {
|
||||
try{
|
||||
if(e.target.value === 'true') {
|
||||
obj[e.target.id](true);
|
||||
} else if(e.target.value === 'false') {
|
||||
obj[e.target.id](false);
|
||||
} else {
|
||||
obj[e.target.id](e.target.value);
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
el.style.cssText = 'float:right;';
|
||||
div.appendChild(el);
|
||||
return div;
|
||||
}
|
||||
/**
|
||||
* Generates selection fields for the menu and populates their options
|
||||
* using information from `editor.menuOptions`
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {string} item The set function name.
|
||||
* @param {object} esr A reference to the object having the set function.
|
||||
* @param {string} clss The name of the object containing the set function.
|
||||
* @param {string} fn The matching get function's function name.
|
||||
* @returns {DOMElement} Returns a dom element containing a selection
|
||||
* element populated with options. The option whose value matches that
|
||||
* returned from `esr[fn]()` will be selected.
|
||||
*/
|
||||
function makeDropdown(item, esr, clss, fn) {
|
||||
var val = editor.menuOptions[item];
|
||||
var currentVal = esr[fn]();
|
||||
if (typeof currentVal == 'object')
|
||||
currentVal = currentVal.$id;
|
||||
val.forEach(function(valuex) {
|
||||
if (valuex.value === currentVal)
|
||||
valuex.selected = 'selected';
|
||||
});
|
||||
return createNewEntry(esr, clss, item, val);
|
||||
}
|
||||
/**
|
||||
* Processes the set functions returned from `getSetFunctions`. First it
|
||||
* checks for menu options defined in `editor.menuOptions`. If no
|
||||
* options are specified then it checks whether there is a get function
|
||||
* (replace set with get) for the setting. When either of those
|
||||
* conditions are met it will attempt to create a new entry for the
|
||||
* settings menu and push it into the elements array defined above.
|
||||
* It can only do so for get functions which return
|
||||
* strings, numbers, and booleans. A special case is written in for
|
||||
* `getMode` where it looks at the returned objects `$id` property and
|
||||
* forwards that through instead. Other special cases could be written
|
||||
* in but that would get a bit ridiculous.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {object} setObj An item from the array returned by
|
||||
* `getSetFunctions`.
|
||||
*/
|
||||
function handleSet(setObj) {
|
||||
var item = setObj.functionName;
|
||||
var esr = setObj.parentObj;
|
||||
var clss = setObj.parentName;
|
||||
var val;
|
||||
var fn = item.replace(/^set/, 'get');
|
||||
if(editor.menuOptions[item] !== undefined) {
|
||||
// has options for select element
|
||||
elements.push(makeDropdown(item, esr, clss, fn));
|
||||
} else if(typeof esr[fn] === 'function') {
|
||||
// has get function
|
||||
try {
|
||||
val = esr[fn]();
|
||||
if(typeof val === 'object') {
|
||||
// setMode takes a string, getMode returns an object
|
||||
// the $id property of that object is the string
|
||||
// which may be given to setMode...
|
||||
val = val.$id;
|
||||
}
|
||||
// the rest of the get functions return strings,
|
||||
// booleans, or numbers.
|
||||
elements.push(
|
||||
createNewEntry(esr, clss, item, val)
|
||||
);
|
||||
} catch (e) {
|
||||
// if there are errors it is because the element
|
||||
// does not belong in the settings menu
|
||||
}
|
||||
}
|
||||
}
|
||||
addEditorMenuOptions(editor);
|
||||
// gather the set functions
|
||||
getSetFunctions(editor).forEach(function(setObj) {
|
||||
// populate the elements array with good stuff.
|
||||
handleSet(setObj);
|
||||
});
|
||||
// sort the menu entries in the elements list so people can find
|
||||
// the settings in alphabetical order.
|
||||
cleanupElementsList();
|
||||
// dump the entries from the elements list and wrap them up in a div
|
||||
return wrapElements();
|
||||
};
|
||||
|
||||
});
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
|
||||
/*global define, require */
|
||||
|
||||
/**
|
||||
* Get Editor Keyboard Shortcuts
|
||||
* @fileOverview Get Editor Keyboard Shortcuts <br />
|
||||
* Gets a map of keyboard shortcuts to command names for the current platform.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var keys = require("../../lib/keys");
|
||||
|
||||
/**
|
||||
* Gets a map of keyboard shortcuts to command names for the current platform.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {ace.Editor} editor An editor instance.
|
||||
* @returns {Array} Returns an array of objects representing the keyboard
|
||||
* shortcuts for the given editor.
|
||||
* @example
|
||||
* var getKbShortcuts = require('./get_keyboard_shortcuts');
|
||||
* console.log(getKbShortcuts(editor));
|
||||
* // [
|
||||
* // {'command' : aCommand, 'key' : 'Control-d'},
|
||||
* // {'command' : aCommand, 'key' : 'Control-d'}
|
||||
* // ]
|
||||
*/
|
||||
module.exports.getEditorKeybordShortcuts = function(editor) {
|
||||
var KEY_MODS = keys.KEY_MODS;
|
||||
var keybindings = [];
|
||||
var commandMap = {};
|
||||
editor.keyBinding.$handlers.forEach(function(handler) {
|
||||
var ckb = handler.commandKeyBinding;
|
||||
for (var i in ckb) {
|
||||
var key = i.replace(/(^|-)\w/g, function(x) { return x.toUpperCase(); });
|
||||
var commands = ckb[i];
|
||||
if (!Array.isArray(commands))
|
||||
commands = [commands];
|
||||
commands.forEach(function(command) {
|
||||
if (typeof command != "string")
|
||||
command = command.name
|
||||
if (commandMap[command]) {
|
||||
commandMap[command].key += "|" + key;
|
||||
} else {
|
||||
commandMap[command] = {key: key, command: command};
|
||||
keybindings.push(commandMap[command]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return keybindings;
|
||||
};
|
||||
|
||||
});
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true */
|
||||
/*global define*/
|
||||
|
||||
/**
|
||||
* Get Set Functions
|
||||
* @fileOverview Get Set Functions <br />
|
||||
* Gets various functions for setting settings.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
/**
|
||||
* Generates a list of set functions for the settings menu.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {object} editor The editor instance
|
||||
* @return {array} Returns an array of objects. Each object contains the
|
||||
* following properties: functionName, parentObj, and parentName. The
|
||||
* function name will be the name of a method beginning with the string
|
||||
* `set` which was found. The parent object will be a reference to the
|
||||
* object having the method matching the function name. The parent name
|
||||
* will be a string representing the identifier of the parent object e.g.
|
||||
* `editor`, `session`, or `renderer`.
|
||||
*/
|
||||
module.exports.getSetFunctions = function getSetFunctions (editor) {
|
||||
/**
|
||||
* Output array. Will hold the objects described above.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
var out = [];
|
||||
/**
|
||||
* This object provides a map between the objects which will be
|
||||
* traversed and the parent name which will appear in the output.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
var my = {
|
||||
'editor' : editor,
|
||||
'session' : editor.session,
|
||||
'renderer' : editor.renderer
|
||||
};
|
||||
/**
|
||||
* This array will hold the set function names which have already been
|
||||
* found so that they are not added to the output multiple times.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
var opts = [];
|
||||
/**
|
||||
* This is a list of set functions which will not appear in the settings
|
||||
* menu. I don't know what to do with setKeyboardHandler. When I tried
|
||||
* to use it, it didn't appear to be working. Someone who knows better
|
||||
* could remove it from this list and add it's options to
|
||||
* add_editor_menu_options.js
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
var skip = [
|
||||
'setOption',
|
||||
'setUndoManager',
|
||||
'setDocument',
|
||||
'setValue',
|
||||
'setBreakpoints',
|
||||
'setScrollTop',
|
||||
'setScrollLeft',
|
||||
'setSelectionStyle',
|
||||
'setWrapLimitRange'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* This will search the objects mapped to the `my` variable above. When
|
||||
* it finds a set function in the object that is not listed in the
|
||||
* `skip` list or the `opts` list it will push a new object to the
|
||||
* output array.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
['renderer', 'session', 'editor'].forEach(function(esra) {
|
||||
var esr = my[esra];
|
||||
var clss = esra;
|
||||
for(var fn in esr) {
|
||||
if(skip.indexOf(fn) === -1) {
|
||||
if(/^set/.test(fn) && opts.indexOf(fn) === -1) {
|
||||
// found set function
|
||||
opts.push(fn);
|
||||
out.push({
|
||||
'functionName' : fn,
|
||||
'parentObj' : esr,
|
||||
'parentName' : clss
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return out;
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,116 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
|
||||
/*global define, require */
|
||||
|
||||
/**
|
||||
* Overlay Page
|
||||
* @fileOverview Overlay Page <br />
|
||||
* Generates an overlay for displaying menus. The overlay is an absolutely
|
||||
* positioned div.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
var dom = require("../../lib/dom");
|
||||
var cssText = require("../../requirejs/text!./settings_menu.css");
|
||||
dom.importCssString(cssText);
|
||||
|
||||
/**
|
||||
* Generates an overlay for displaying menus. The overlay is an absolutely
|
||||
* positioned div.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {DOMElement} contentElement Any element which may be presented inside
|
||||
* a div.
|
||||
* @param {string|number} top absolute position value.
|
||||
* @param {string|number} right absolute position value.
|
||||
* @param {string|number} bottom absolute position value.
|
||||
* @param {string|number} left absolute position value.
|
||||
*/
|
||||
module.exports.overlayPage = function overlayPage(editor, contentElement, top, right, bottom, left) {
|
||||
top = top ? 'top: ' + top + ';' : '';
|
||||
bottom = bottom ? 'bottom: ' + bottom + ';' : '';
|
||||
right = right ? 'right: ' + right + ';' : '';
|
||||
left = left ? 'left: ' + left + ';' : '';
|
||||
|
||||
var closer = document.createElement('div');
|
||||
var contentContainer = document.createElement('div');
|
||||
|
||||
function documentEscListener(e) {
|
||||
if (e.keyCode === 27) {
|
||||
closer.click();
|
||||
}
|
||||
}
|
||||
|
||||
closer.style.cssText = 'margin: 0; padding: 0; ' +
|
||||
'position: fixed; top:0; bottom:0; left:0; right:0;' +
|
||||
'z-index: 9990; ' +
|
||||
'background-color: rgba(0, 0, 0, 0.3);';
|
||||
closer.addEventListener('click', function() {
|
||||
document.removeEventListener('keydown', documentEscListener);
|
||||
closer.parentNode.removeChild(closer);
|
||||
editor.focus();
|
||||
closer = null;
|
||||
});
|
||||
// click closer if esc key is pressed
|
||||
document.addEventListener('keydown', documentEscListener);
|
||||
|
||||
contentContainer.style.cssText = top + right + bottom + left;
|
||||
contentContainer.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
var wrapper = dom.createElement("div");
|
||||
wrapper.style.position = "relative";
|
||||
|
||||
var closeButton = dom.createElement("div");
|
||||
closeButton.className = "ace_closeButton";
|
||||
closeButton.addEventListener('click', function() {
|
||||
closer.click();
|
||||
});
|
||||
|
||||
wrapper.appendChild(closeButton);
|
||||
contentContainer.appendChild(wrapper);
|
||||
|
||||
contentContainer.appendChild(contentElement);
|
||||
closer.appendChild(contentContainer);
|
||||
document.body.appendChild(closer);
|
||||
editor.blur();
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
#ace_settingsmenu, #kbshortcutmenu {
|
||||
background-color: #F7F7F7;
|
||||
color: black;
|
||||
box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);
|
||||
padding: 1em 0.5em 2em 1em;
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 9991;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {
|
||||
box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.ace_optionsMenuEntry:hover {
|
||||
background-color: rgba(100, 100, 100, 0.1);
|
||||
-webkit-transition: all 0.5s;
|
||||
transition: all 0.3s
|
||||
}
|
||||
|
||||
.ace_closeButton {
|
||||
background: rgba(245, 146, 146, 0.5);
|
||||
border: 1px solid #F48A8A;
|
||||
border-radius: 50%;
|
||||
padding: 7px;
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
z-index: 1000;
|
||||
}
|
||||
.ace_closeButton{
|
||||
background: rgba(245, 146, 146, 0.9);
|
||||
}
|
||||
.ace_optionsMenuKey {
|
||||
color: darkslateblue;
|
||||
font-weight: bold;
|
||||
}
|
||||
.ace_optionsMenuCommand {
|
||||
color: darkcyan;
|
||||
font-weight: normal;
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var modes = [];
|
||||
/**
|
||||
* Suggests a mode based on the file extension present in the given path
|
||||
* @param {string} path The path to the file
|
||||
* @returns {object} Returns an object containing information about the
|
||||
* suggested mode.
|
||||
*/
|
||||
function getModeForPath(path) {
|
||||
var mode = modesByName.text;
|
||||
var fileName = path.split(/[\/\\]/).pop();
|
||||
for (var i = 0; i < modes.length; i++) {
|
||||
if (modes[i].supportsFile(fileName)) {
|
||||
mode = modes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
var Mode = function(name, caption, extensions) {
|
||||
this.name = name;
|
||||
this.caption = caption;
|
||||
this.mode = "ace/mode/" + name;
|
||||
this.extensions = extensions;
|
||||
if (/\^/.test(extensions)) {
|
||||
var re = extensions.replace(/\|(\^)?/g, function(a, b){
|
||||
return "$|" + (b ? "^" : "^.*\\.");
|
||||
}) + "$";
|
||||
} else {
|
||||
var re = "^.*\\.(" + extensions + ")$";
|
||||
}
|
||||
|
||||
this.extRe = new RegExp(re, "gi");
|
||||
};
|
||||
|
||||
Mode.prototype.supportsFile = function(filename) {
|
||||
return filename.match(this.extRe);
|
||||
};
|
||||
|
||||
// todo firstlinematch
|
||||
var supportedModes = {
|
||||
ABAP: ["abap"],
|
||||
ABC: ["abc"],
|
||||
ActionScript:["as"],
|
||||
ADA: ["ada|adb"],
|
||||
Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],
|
||||
AsciiDoc: ["asciidoc"],
|
||||
Assembly_x86:["asm"],
|
||||
AutoHotKey: ["ahk"],
|
||||
BatchFile: ["bat|cmd"],
|
||||
C9Search: ["c9search_results"],
|
||||
C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp"],
|
||||
Cirru: ["cirru|cr"],
|
||||
Clojure: ["clj|cljs"],
|
||||
Cobol: ["CBL|COB"],
|
||||
coffee: ["coffee|cf|cson|^Cakefile"],
|
||||
ColdFusion: ["cfm"],
|
||||
CSharp: ["cs"],
|
||||
CSS: ["css"],
|
||||
Curly: ["curly"],
|
||||
D: ["d|di"],
|
||||
Dart: ["dart"],
|
||||
Diff: ["diff|patch"],
|
||||
Dockerfile: ["^Dockerfile"],
|
||||
Dot: ["dot"],
|
||||
Dummy: ["dummy"],
|
||||
DummySyntax: ["dummy"],
|
||||
Eiffel: ["e"],
|
||||
EJS: ["ejs"],
|
||||
Elixir: ["ex|exs"],
|
||||
Elm: ["elm"],
|
||||
Erlang: ["erl|hrl"],
|
||||
Forth: ["frt|fs|ldr"],
|
||||
FTL: ["ftl"],
|
||||
Gcode: ["gcode"],
|
||||
Gherkin: ["feature"],
|
||||
Gitignore: ["^.gitignore"],
|
||||
Glsl: ["glsl|frag|vert"],
|
||||
golang: ["go"],
|
||||
Groovy: ["groovy"],
|
||||
HAML: ["haml"],
|
||||
Handlebars: ["hbs|handlebars|tpl|mustache"],
|
||||
Haskell: ["hs"],
|
||||
haXe: ["hx"],
|
||||
HTML: ["html|htm|xhtml"],
|
||||
HTML_Ruby: ["erb|rhtml|html.erb"],
|
||||
INI: ["ini|conf|cfg|prefs"],
|
||||
Io: ["io"],
|
||||
Jack: ["jack"],
|
||||
Jade: ["jade"],
|
||||
Java: ["java"],
|
||||
JavaScript: ["js|jsm"],
|
||||
JSON: ["json"],
|
||||
JSONiq: ["jq"],
|
||||
JSP: ["jsp"],
|
||||
JSX: ["jsx"],
|
||||
Julia: ["jl"],
|
||||
LaTeX: ["tex|latex|ltx|bib"],
|
||||
LESS: ["less"],
|
||||
Liquid: ["liquid"],
|
||||
Lisp: ["lisp"],
|
||||
LiveScript: ["ls"],
|
||||
LogiQL: ["logic|lql"],
|
||||
LSL: ["lsl"],
|
||||
Lua: ["lua"],
|
||||
LuaPage: ["lp"],
|
||||
Lucene: ["lucene"],
|
||||
Makefile: ["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],
|
||||
Markdown: ["md|markdown"],
|
||||
Mask: ["mask"],
|
||||
MATLAB: ["matlab"],
|
||||
MEL: ["mel"],
|
||||
MUSHCode: ["mc|mush"],
|
||||
MySQL: ["mysql"],
|
||||
Nix: ["nix"],
|
||||
ObjectiveC: ["m|mm"],
|
||||
OCaml: ["ml|mli"],
|
||||
Pascal: ["pas|p"],
|
||||
Perl: ["pl|pm"],
|
||||
pgSQL: ["pgsql"],
|
||||
PHP: ["php|phtml"],
|
||||
Powershell: ["ps1"],
|
||||
Praat: ["praat|praatscript|psc|proc"],
|
||||
Prolog: ["plg|prolog"],
|
||||
Properties: ["properties"],
|
||||
Protobuf: ["proto"],
|
||||
Python: ["py"],
|
||||
R: ["r"],
|
||||
RDoc: ["Rd"],
|
||||
RHTML: ["Rhtml"],
|
||||
Ruby: ["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],
|
||||
Rust: ["rs"],
|
||||
SASS: ["sass"],
|
||||
SCAD: ["scad"],
|
||||
Scala: ["scala"],
|
||||
Scheme: ["scm|rkt"],
|
||||
SCSS: ["scss"],
|
||||
SH: ["sh|bash|^.bashrc"],
|
||||
SJS: ["sjs"],
|
||||
Smarty: ["smarty|tpl"],
|
||||
snippets: ["snippets"],
|
||||
Soy_Template:["soy"],
|
||||
Space: ["space"],
|
||||
SQL: ["sql"],
|
||||
Stylus: ["styl|stylus"],
|
||||
SVG: ["svg"],
|
||||
Tcl: ["tcl"],
|
||||
Tex: ["tex"],
|
||||
Text: ["txt"],
|
||||
Textile: ["textile"],
|
||||
Toml: ["toml"],
|
||||
Twig: ["twig"],
|
||||
Typescript: ["ts|typescript|str"],
|
||||
Vala: ["vala"],
|
||||
VBScript: ["vbs|vb"],
|
||||
Velocity: ["vm"],
|
||||
Verilog: ["v|vh|sv|svh"],
|
||||
VHDL: ["vhd|vhdl"],
|
||||
XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl"],
|
||||
XQuery: ["xq"],
|
||||
YAML: ["yaml|yml"],
|
||||
// Add the missing mode "Django" to ext-modelist
|
||||
Django: ["html"]
|
||||
};
|
||||
|
||||
var nameOverrides = {
|
||||
ObjectiveC: "Objective-C",
|
||||
CSharp: "C#",
|
||||
golang: "Go",
|
||||
C_Cpp: "C and C++",
|
||||
coffee: "CoffeeScript",
|
||||
HTML_Ruby: "HTML (Ruby)",
|
||||
FTL: "FreeMarker"
|
||||
};
|
||||
var modesByName = {};
|
||||
for (var name in supportedModes) {
|
||||
var data = supportedModes[name];
|
||||
var displayName = (nameOverrides[name] || name).replace(/_/g, " ");
|
||||
var filename = name.toLowerCase();
|
||||
var mode = new Mode(filename, displayName, data[0]);
|
||||
modesByName[filename] = mode;
|
||||
modes.push(mode);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getModeForPath: getModeForPath,
|
||||
modes: modes,
|
||||
modesByName: modesByName
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var MAX_TOKEN_COUNT = 1000;
|
||||
var useragent = require("../lib/useragent");
|
||||
var TokenizerModule = require("../tokenizer");
|
||||
|
||||
function patch(obj, name, regexp, replacement) {
|
||||
eval("obj['" + name + "']=" + obj[name].toString().replace(
|
||||
regexp, replacement
|
||||
));
|
||||
}
|
||||
|
||||
if (useragent.isIE && useragent.isIE < 10 && window.top.document.compatMode === "BackCompat")
|
||||
useragent.isOldIE = true;
|
||||
|
||||
if (typeof document != "undefined" && !document.documentElement.querySelector) {
|
||||
useragent.isOldIE = true;
|
||||
var qs = function(el, selector) {
|
||||
if (selector.charAt(0) == ".") {
|
||||
var classNeme = selector.slice(1);
|
||||
} else {
|
||||
var m = selector.match(/(\w+)=(\w+)/);
|
||||
var attr = m && m[1];
|
||||
var attrVal = m && m[2];
|
||||
}
|
||||
for (var i = 0; i < el.all.length; i++) {
|
||||
var ch = el.all[i];
|
||||
if (classNeme) {
|
||||
if (ch.className.indexOf(classNeme) != -1)
|
||||
return ch;
|
||||
} else if (attr) {
|
||||
if (ch.getAttribute(attr) == attrVal)
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
};
|
||||
var sb = require("./searchbox").SearchBox.prototype;
|
||||
patch(
|
||||
sb, "$initElements",
|
||||
/([^\s=]*).querySelector\((".*?")\)/g,
|
||||
"qs($1, $2)"
|
||||
);
|
||||
}
|
||||
|
||||
var compliantExecNpcg = /()??/.exec("")[1] === undefined;
|
||||
if (compliantExecNpcg)
|
||||
return;
|
||||
var proto = TokenizerModule.Tokenizer.prototype;
|
||||
TokenizerModule.Tokenizer_orig = TokenizerModule.Tokenizer;
|
||||
proto.getLineTokens_orig = proto.getLineTokens;
|
||||
|
||||
patch(
|
||||
TokenizerModule, "Tokenizer",
|
||||
"ruleRegExps.push(adjustedregex);\n",
|
||||
function(m) {
|
||||
return m + '\
|
||||
if (state[i].next && RegExp(adjustedregex).test(""))\n\
|
||||
rule._qre = RegExp(adjustedregex, "g");\n\
|
||||
';
|
||||
}
|
||||
);
|
||||
TokenizerModule.Tokenizer.prototype = proto;
|
||||
patch(
|
||||
proto, "getLineTokens",
|
||||
/if \(match\[i \+ 1\] === undefined\)\s*continue;/,
|
||||
"if (!match[i + 1]) {\n\
|
||||
if (value)continue;\n\
|
||||
var qre = state[mapping[i]]._qre;\n\
|
||||
if (!qre) continue;\n\
|
||||
qre.lastIndex = lastIndex;\n\
|
||||
if (!qre.exec(line) || qre.lastIndex != lastIndex)\n\
|
||||
continue;\n\
|
||||
}"
|
||||
);
|
||||
|
||||
patch(
|
||||
require("../mode/text").Mode.prototype, "getTokenizer",
|
||||
/Tokenizer/,
|
||||
"TokenizerModule.Tokenizer"
|
||||
);
|
||||
|
||||
useragent.isOldIE = true;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var assert = require("../test/assertions");
|
||||
|
||||
module.exports = {
|
||||
"test: getTokenizer() (smoke test)" : function() {
|
||||
var exec = RegExp.prototype.exec
|
||||
var brokenExec = function(str) {
|
||||
var result = exec.call(this, str);
|
||||
if (result) {
|
||||
for (var i = result.length; i--;)
|
||||
if (!result[i])
|
||||
result[i] = "";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
// break this to emulate old ie
|
||||
RegExp.prototype.exec = brokenExec;
|
||||
require("./old_ie");
|
||||
var Tokenizer = require("../tokenizer").Tokenizer;
|
||||
var JavaScriptHighlightRules = require("../mode/javascript_highlight_rules").JavaScriptHighlightRules;
|
||||
var tokenizer = new Tokenizer((new JavaScriptHighlightRules).getRules());
|
||||
|
||||
var tokens = tokenizer.getLineTokens("'juhu'", "start").tokens;
|
||||
assert.equal("string", tokens[0].type);
|
||||
} finally {
|
||||
// restore modified functions
|
||||
RegExp.prototype.exec = exec;
|
||||
var module = require("../tokenizer");
|
||||
module.Tokenizer = module.Tokenizer_orig;
|
||||
module.Tokenizer.prototype.getLineTokens = module.Tokenizer.prototype.getLineTokens_orig;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------
|
||||
* Editor Search Form
|
||||
* --------------------------------------------------------------------------------------- */
|
||||
.ace_search {
|
||||
background-color: #ddd;
|
||||
border: 1px solid #cbcbcb;
|
||||
border-top: 0 none;
|
||||
max-width: 325px;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 4px;
|
||||
padding-right: 6px;
|
||||
padding-bottom: 0;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
z-index: 99;
|
||||
white-space: normal;
|
||||
}
|
||||
.ace_search.left {
|
||||
border-left: 0 none;
|
||||
border-radius: 0px 0px 5px 0px;
|
||||
left: 0;
|
||||
}
|
||||
.ace_search.right {
|
||||
border-radius: 0px 0px 0px 5px;
|
||||
border-right: 0 none;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ace_search_form, .ace_replace_form {
|
||||
border-radius: 3px;
|
||||
border: 1px solid #cbcbcb;
|
||||
float: left;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ace_search_form.ace_nomatch {
|
||||
outline: 1px solid red;
|
||||
}
|
||||
|
||||
.ace_search_field {
|
||||
background-color: white;
|
||||
border-right: 1px solid #cbcbcb;
|
||||
border: 0 none;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
height: 22px;
|
||||
outline: 0;
|
||||
padding: 0 7px;
|
||||
width: 214px;
|
||||
margin: 0;
|
||||
}
|
||||
.ace_searchbtn,
|
||||
.ace_replacebtn {
|
||||
background: #fff;
|
||||
border: 0 none;
|
||||
border-left: 1px solid #dcdcdc;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
height: 22px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
.ace_searchbtn:last-child,
|
||||
.ace_replacebtn:last-child {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
.ace_searchbtn:disabled {
|
||||
background: none;
|
||||
cursor: default;
|
||||
}
|
||||
.ace_searchbtn {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
width: 27px;
|
||||
}
|
||||
.ace_searchbtn.prev {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADFJREFUeNpiSU1NZUAC/6E0I0yACYskCpsJiySKIiY0SUZk40FyTEgCjGgKwTRAgAEAQJUIPCE+qfkAAAAASUVORK5CYII=);
|
||||
}
|
||||
.ace_searchbtn.next {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNpiTE1NZQCC/0DMyIAKwGJMUAYDEo3M/s+EpvM/mkKwCQxYjIeLMaELoLMBAgwAU7UJObTKsvAAAAAASUVORK5CYII=);
|
||||
}
|
||||
.ace_searchbtn_close {
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;
|
||||
border-radius: 50%;
|
||||
border: 0 none;
|
||||
color: #656565;
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font: 16px/16px Arial;
|
||||
height: 14px;
|
||||
margin: 5px 1px 9px 5px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
width: 14px;
|
||||
}
|
||||
.ace_searchbtn_close:hover {
|
||||
background-color: #656565;
|
||||
background-position: 50% 100%;
|
||||
color: white;
|
||||
}
|
||||
.ace_replacebtn.prev {
|
||||
width: 54px
|
||||
}
|
||||
.ace_replacebtn.next {
|
||||
width: 27px
|
||||
}
|
||||
|
||||
.ace_button {
|
||||
margin-left: 2px;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-o-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
opacity: 0.7;
|
||||
border: 1px solid rgba(100,100,100,0.23);
|
||||
padding: 1px;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.ace_button:hover {
|
||||
background-color: #eee;
|
||||
opacity:1;
|
||||
}
|
||||
.ace_button:active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.ace_button.checked {
|
||||
border-color: #3399ff;
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
.ace_search_options{
|
||||
margin-bottom: 3px;
|
||||
text-align: right;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-o-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
var lang = require("../lib/lang");
|
||||
var event = require("../lib/event");
|
||||
var searchboxCss = require("../requirejs/text!./searchbox.css");
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
var keyUtil = require("../lib/keys");
|
||||
|
||||
dom.importCssString(searchboxCss, "ace_searchbox");
|
||||
|
||||
var html = '<div class="ace_search right">\
|
||||
<button type="button" action="hide" class="ace_searchbtn_close"></button>\
|
||||
<div class="ace_search_form">\
|
||||
<input class="ace_search_field" placeholder="Search for" spellcheck="false"></input>\
|
||||
<button type="button" action="findNext" class="ace_searchbtn next"></button>\
|
||||
<button type="button" action="findPrev" class="ace_searchbtn prev"></button>\
|
||||
<button type="button" action="findAll" class="ace_searchbtn" title="Alt-Enter">All</button>\
|
||||
</div>\
|
||||
<div class="ace_replace_form">\
|
||||
<input class="ace_search_field" placeholder="Replace with" spellcheck="false"></input>\
|
||||
<button type="button" action="replaceAndFindNext" class="ace_replacebtn">Replace</button>\
|
||||
<button type="button" action="replaceAll" class="ace_replacebtn">All</button>\
|
||||
</div>\
|
||||
<div class="ace_search_options">\
|
||||
<span action="toggleRegexpMode" class="ace_button" title="RegExp Search">.*</span>\
|
||||
<span action="toggleCaseSensitive" class="ace_button" title="CaseSensitive Search">Aa</span>\
|
||||
<span action="toggleWholeWords" class="ace_button" title="Whole Word Search">\\b</span>\
|
||||
</div>\
|
||||
</div>'.replace(/>\s+/g, ">");
|
||||
|
||||
var SearchBox = function(editor, range, showReplaceForm) {
|
||||
var div = dom.createElement("div");
|
||||
div.innerHTML = html;
|
||||
this.element = div.firstChild;
|
||||
|
||||
this.$init();
|
||||
this.setEditor(editor);
|
||||
};
|
||||
|
||||
(function() {
|
||||
this.setEditor = function(editor) {
|
||||
editor.searchBox = this;
|
||||
editor.container.appendChild(this.element);
|
||||
this.editor = editor;
|
||||
};
|
||||
|
||||
this.$initElements = function(sb) {
|
||||
this.searchBox = sb.querySelector(".ace_search_form");
|
||||
this.replaceBox = sb.querySelector(".ace_replace_form");
|
||||
this.searchOptions = sb.querySelector(".ace_search_options");
|
||||
this.regExpOption = sb.querySelector("[action=toggleRegexpMode]");
|
||||
this.caseSensitiveOption = sb.querySelector("[action=toggleCaseSensitive]");
|
||||
this.wholeWordOption = sb.querySelector("[action=toggleWholeWords]");
|
||||
this.searchInput = this.searchBox.querySelector(".ace_search_field");
|
||||
this.replaceInput = this.replaceBox.querySelector(".ace_search_field");
|
||||
};
|
||||
|
||||
this.$init = function() {
|
||||
var sb = this.element;
|
||||
|
||||
this.$initElements(sb);
|
||||
|
||||
var _this = this;
|
||||
event.addListener(sb, "mousedown", function(e) {
|
||||
setTimeout(function(){
|
||||
_this.activeInput.focus();
|
||||
}, 0);
|
||||
event.stopPropagation(e);
|
||||
});
|
||||
event.addListener(sb, "click", function(e) {
|
||||
var t = e.target || e.srcElement;
|
||||
var action = t.getAttribute("action");
|
||||
if (action && _this[action])
|
||||
_this[action]();
|
||||
else if (_this.$searchBarKb.commands[action])
|
||||
_this.$searchBarKb.commands[action].exec(_this);
|
||||
event.stopPropagation(e);
|
||||
});
|
||||
|
||||
event.addCommandKeyListener(sb, function(e, hashId, keyCode) {
|
||||
var keyString = keyUtil.keyCodeToString(keyCode);
|
||||
var command = _this.$searchBarKb.findKeyCommand(hashId, keyString);
|
||||
if (command && command.exec) {
|
||||
command.exec(_this);
|
||||
event.stopEvent(e);
|
||||
}
|
||||
});
|
||||
|
||||
this.$onChange = lang.delayedCall(function() {
|
||||
_this.find(false, false);
|
||||
});
|
||||
|
||||
event.addListener(this.searchInput, "input", function() {
|
||||
_this.$onChange.schedule(20);
|
||||
});
|
||||
event.addListener(this.searchInput, "focus", function() {
|
||||
_this.activeInput = _this.searchInput;
|
||||
_this.searchInput.value && _this.highlight();
|
||||
});
|
||||
event.addListener(this.replaceInput, "focus", function() {
|
||||
_this.activeInput = _this.replaceInput;
|
||||
_this.searchInput.value && _this.highlight();
|
||||
});
|
||||
};
|
||||
|
||||
//keybinging outsite of the searchbox
|
||||
this.$closeSearchBarKb = new HashHandler([{
|
||||
bindKey: "Esc",
|
||||
name: "closeSearchBar",
|
||||
exec: function(editor) {
|
||||
editor.searchBox.hide();
|
||||
}
|
||||
}]);
|
||||
|
||||
//keybinging outsite of the searchbox
|
||||
this.$searchBarKb = new HashHandler();
|
||||
this.$searchBarKb.bindKeys({
|
||||
"Ctrl-f|Command-f|Ctrl-H|Command-Option-F": function(sb) {
|
||||
var isReplace = sb.isReplace = !sb.isReplace;
|
||||
sb.replaceBox.style.display = isReplace ? "" : "none";
|
||||
sb[isReplace ? "replaceInput" : "searchInput"].focus();
|
||||
},
|
||||
"Ctrl-G|Command-G": function(sb) {
|
||||
sb.findNext();
|
||||
},
|
||||
"Ctrl-Shift-G|Command-Shift-G": function(sb) {
|
||||
sb.findPrev();
|
||||
},
|
||||
"esc": function(sb) {
|
||||
setTimeout(function() { sb.hide();});
|
||||
},
|
||||
"Return": function(sb) {
|
||||
if (sb.activeInput == sb.replaceInput)
|
||||
sb.replace();
|
||||
sb.findNext();
|
||||
},
|
||||
"Shift-Return": function(sb) {
|
||||
if (sb.activeInput == sb.replaceInput)
|
||||
sb.replace();
|
||||
sb.findPrev();
|
||||
},
|
||||
"Alt-Return": function(sb) {
|
||||
if (sb.activeInput == sb.replaceInput)
|
||||
sb.replaceAll();
|
||||
sb.findAll();
|
||||
},
|
||||
"Tab": function(sb) {
|
||||
(sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus();
|
||||
}
|
||||
});
|
||||
|
||||
this.$searchBarKb.addCommands([{
|
||||
name: "toggleRegexpMode",
|
||||
bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"},
|
||||
exec: function(sb) {
|
||||
sb.regExpOption.checked = !sb.regExpOption.checked;
|
||||
sb.$syncOptions();
|
||||
}
|
||||
}, {
|
||||
name: "toggleCaseSensitive",
|
||||
bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"},
|
||||
exec: function(sb) {
|
||||
sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked;
|
||||
sb.$syncOptions();
|
||||
}
|
||||
}, {
|
||||
name: "toggleWholeWords",
|
||||
bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"},
|
||||
exec: function(sb) {
|
||||
sb.wholeWordOption.checked = !sb.wholeWordOption.checked;
|
||||
sb.$syncOptions();
|
||||
}
|
||||
}]);
|
||||
|
||||
this.$syncOptions = function() {
|
||||
dom.setCssClass(this.regExpOption, "checked", this.regExpOption.checked);
|
||||
dom.setCssClass(this.wholeWordOption, "checked", this.wholeWordOption.checked);
|
||||
dom.setCssClass(this.caseSensitiveOption, "checked", this.caseSensitiveOption.checked);
|
||||
this.find(false, false);
|
||||
};
|
||||
|
||||
this.highlight = function(re) {
|
||||
this.editor.session.highlight(re || this.editor.$search.$options.re);
|
||||
this.editor.renderer.updateBackMarkers()
|
||||
};
|
||||
this.find = function(skipCurrent, backwards) {
|
||||
var range = this.editor.find(this.searchInput.value, {
|
||||
skipCurrent: skipCurrent,
|
||||
backwards: backwards,
|
||||
wrap: true,
|
||||
regExp: this.regExpOption.checked,
|
||||
caseSensitive: this.caseSensitiveOption.checked,
|
||||
wholeWord: this.wholeWordOption.checked
|
||||
});
|
||||
var noMatch = !range && this.searchInput.value;
|
||||
dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
|
||||
this.editor._emit("findSearchBox", { match: !noMatch });
|
||||
this.highlight();
|
||||
};
|
||||
this.findNext = function() {
|
||||
this.find(true, false);
|
||||
};
|
||||
this.findPrev = function() {
|
||||
this.find(true, true);
|
||||
};
|
||||
this.findAll = function(){
|
||||
var range = this.editor.findAll(this.searchInput.value, {
|
||||
regExp: this.regExpOption.checked,
|
||||
caseSensitive: this.caseSensitiveOption.checked,
|
||||
wholeWord: this.wholeWordOption.checked
|
||||
});
|
||||
var noMatch = !range && this.searchInput.value;
|
||||
dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
|
||||
this.editor._emit("findSearchBox", { match: !noMatch });
|
||||
this.highlight();
|
||||
this.hide();
|
||||
};
|
||||
this.replace = function() {
|
||||
if (!this.editor.getReadOnly())
|
||||
this.editor.replace(this.replaceInput.value);
|
||||
};
|
||||
this.replaceAndFindNext = function() {
|
||||
if (!this.editor.getReadOnly()) {
|
||||
this.editor.replace(this.replaceInput.value);
|
||||
this.findNext()
|
||||
}
|
||||
};
|
||||
this.replaceAll = function() {
|
||||
if (!this.editor.getReadOnly())
|
||||
this.editor.replaceAll(this.replaceInput.value);
|
||||
};
|
||||
|
||||
this.hide = function() {
|
||||
this.element.style.display = "none";
|
||||
this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb);
|
||||
this.editor.focus();
|
||||
};
|
||||
this.show = function(value, isReplace) {
|
||||
this.element.style.display = "";
|
||||
this.replaceBox.style.display = isReplace ? "" : "none";
|
||||
|
||||
this.isReplace = isReplace;
|
||||
|
||||
if (value)
|
||||
this.searchInput.value = value;
|
||||
this.searchInput.focus();
|
||||
this.searchInput.select();
|
||||
|
||||
this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb);
|
||||
};
|
||||
|
||||
this.isFocused = function() {
|
||||
var el = document.activeElement;
|
||||
return el == this.searchInput || el == this.replaceInput;
|
||||
}
|
||||
}).call(SearchBox.prototype);
|
||||
|
||||
exports.SearchBox = SearchBox;
|
||||
|
||||
exports.Search = function(editor, isReplace) {
|
||||
var sb = editor.searchBox || new SearchBox(editor);
|
||||
sb.show(editor.session.getTextRange(), isReplace);
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------
|
||||
* TODO
|
||||
* --------------------------------------------------------------------------------------- */
|
||||
/*
|
||||
- move search form to the left if it masks current word
|
||||
- includ all options that search has. ex: regex
|
||||
- searchbox.searchbox is not that pretty. we should have just searchbox
|
||||
- disable prev button if it makes sence
|
||||
*/
|
||||
@@ -0,0 +1,76 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
|
||||
/*global define, require */
|
||||
|
||||
/**
|
||||
* Show Settings Menu
|
||||
* @fileOverview Show Settings Menu <br />
|
||||
* Displays an interactive settings menu mostly generated on the fly based on
|
||||
* the current state of the editor.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var generateSettingsMenu = require('./menu_tools/generate_settings_menu').generateSettingsMenu;
|
||||
var overlayPage = require('./menu_tools/overlay_page').overlayPage;
|
||||
/**
|
||||
* This displays the settings menu if it is not already being shown.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
* @param {ace.Editor} editor An instance of the ace editor.
|
||||
*/
|
||||
function showSettingsMenu(editor) {
|
||||
// make sure the menu isn't open already.
|
||||
var sm = document.getElementById('ace_settingsmenu');
|
||||
if (!sm)
|
||||
overlayPage(editor, generateSettingsMenu(editor), '0', '0', '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the settings menu extension. It adds the showSettingsMenu
|
||||
* method to the given editor object and adds the showSettingsMenu command
|
||||
* to the editor with appropriate keyboard shortcuts.
|
||||
* @param {ace.Editor} editor An instance of the Editor.
|
||||
*/
|
||||
module.exports.init = function(editor) {
|
||||
var Editor = require("ace/editor").Editor;
|
||||
Editor.prototype.showSettingsMenu = function() {
|
||||
showSettingsMenu(this);
|
||||
};
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
var event = require("../lib/event");
|
||||
|
||||
exports.contextMenuHandler = function(e){
|
||||
var host = e.target;
|
||||
var text = host.textInput.getElement();
|
||||
if (!host.selection.isEmpty())
|
||||
return;
|
||||
var c = host.getCursorPosition();
|
||||
var r = host.session.getWordRange(c.row, c.column);
|
||||
var w = host.session.getTextRange(r);
|
||||
|
||||
host.session.tokenRe.lastIndex = 0;
|
||||
if (!host.session.tokenRe.test(w))
|
||||
return;
|
||||
var PLACEHOLDER = "\x01\x01";
|
||||
var value = w + " " + PLACEHOLDER;
|
||||
text.value = value;
|
||||
text.setSelectionRange(w.length, w.length + 1);
|
||||
text.setSelectionRange(0, 0);
|
||||
text.setSelectionRange(0, w.length);
|
||||
|
||||
var afterKeydown = false;
|
||||
event.addListener(text, "keydown", function onKeydown() {
|
||||
event.removeListener(text, "keydown", onKeydown);
|
||||
afterKeydown = true;
|
||||
});
|
||||
|
||||
host.textInput.setInputHandler(function(newVal) {
|
||||
console.log(newVal , value, text.selectionStart, text.selectionEnd)
|
||||
if (newVal == value)
|
||||
return '';
|
||||
if (newVal.lastIndexOf(value, 0) === 0)
|
||||
return newVal.slice(value.length);
|
||||
if (newVal.substr(text.selectionEnd) == value)
|
||||
return newVal.slice(0, -value.length);
|
||||
if (newVal.slice(-2) == PLACEHOLDER) {
|
||||
var val = newVal.slice(0, -2);
|
||||
if (val.slice(-1) == " ") {
|
||||
if (afterKeydown)
|
||||
return val.substring(0, text.selectionEnd);
|
||||
val = val.slice(0, -1);
|
||||
host.session.replace(r, val);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return newVal;
|
||||
});
|
||||
};
|
||||
// todo support highlighting with typo.js
|
||||
var Editor = require("../editor").Editor;
|
||||
require("../config").defineOptions(Editor.prototype, "editor", {
|
||||
spellcheck: {
|
||||
set: function(val) {
|
||||
var text = this.textInput.getElement();
|
||||
text.spellcheck = !!val;
|
||||
if (!val)
|
||||
this.removeListener("nativecontextmenu", exports.contextMenuHandler);
|
||||
else
|
||||
this.on("nativecontextmenu", exports.contextMenuHandler);
|
||||
},
|
||||
value: true
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
+6
-8
@@ -29,14 +29,12 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
"never use strict";
|
||||
|
||||
module.exports = {
|
||||
_default: {
|
||||
text: "",
|
||||
isLine: false
|
||||
}
|
||||
};
|
||||
/**
|
||||
* this is experimental, and subject to change, use at your own risk!
|
||||
*/
|
||||
module.exports = require("../split");
|
||||
|
||||
});
|
||||
|
||||
@@ -1,22 +1,31 @@
|
||||
.ace_editor {
|
||||
font-family: 'Monaco', 'Menlo', 'Droid Sans Mono', 'Courier New', monospace;
|
||||
.ace_static_highlight {
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ace_editor .ace_gutter {
|
||||
.ace_static_highlight .ace_gutter {
|
||||
width: 25px !important;
|
||||
display: block;
|
||||
float: left;
|
||||
text-align: right;
|
||||
padding: 0 3px 0 0;
|
||||
margin-right: 3px;
|
||||
position: static !important;
|
||||
}
|
||||
|
||||
.ace_line { clear: both; }
|
||||
.ace_static_highlight .ace_line { clear: both; }
|
||||
|
||||
*.ace_gutter-cell {
|
||||
.ace_static_highlight .ace_gutter-cell {
|
||||
-moz-user-select: -moz-none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
||||
.ace_static_highlight .ace_gutter-cell:before {
|
||||
content: counter(ace_line, decimal);
|
||||
counter-increment: ace_line;
|
||||
}
|
||||
.ace_static_highlight {
|
||||
counter-reset: ace_line;
|
||||
}
|
||||
|
||||
@@ -34,21 +34,120 @@ define(function(require, exports, module) {
|
||||
var EditSession = require("../edit_session").EditSession;
|
||||
var TextLayer = require("../layer/text").Text;
|
||||
var baseStyles = require("../requirejs/text!./static.css");
|
||||
var config = require("../config");
|
||||
var dom = require("../lib/dom");
|
||||
|
||||
/* Transforms a given input code snippet into HTML using the given mode
|
||||
*
|
||||
* @param {string} input Code snippet
|
||||
* @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode')
|
||||
* @param {string} r Code snippet
|
||||
* @returns {object} An object containing: html, css
|
||||
*/
|
||||
|
||||
exports.render = function(input, mode, theme, lineStart, disableGutter) {
|
||||
var highlight = function(el, opts, callback) {
|
||||
var m = el.className.match(/lang-(\w+)/);
|
||||
var mode = opts.mode || m && ("ace/mode/" + m[1]);
|
||||
if (!mode)
|
||||
return false;
|
||||
var theme = opts.theme || "ace/theme/textmate";
|
||||
|
||||
var data = "";
|
||||
var nodes = [];
|
||||
|
||||
if (el.firstElementChild) {
|
||||
var textLen = 0;
|
||||
for (var i = 0; i < el.childNodes.length; i++) {
|
||||
var ch = el.childNodes[i];
|
||||
if (ch.nodeType == 3) {
|
||||
textLen += ch.data.length;
|
||||
data += ch.data;
|
||||
} else {
|
||||
nodes.push(textLen, ch);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = dom.getInnerText(el);
|
||||
if (opts.trim)
|
||||
data = data.trim();
|
||||
}
|
||||
|
||||
highlight.render(data, mode, theme, opts.firstLineNumber, !opts.showGutter, function (highlighted) {
|
||||
dom.importCssString(highlighted.css, "ace_highlight");
|
||||
el.innerHTML = highlighted.html;
|
||||
var container = el.firstChild.firstChild;
|
||||
for (var i = 0; i < nodes.length; i += 2) {
|
||||
var pos = highlighted.session.doc.indexToPosition(nodes[i]);
|
||||
var node = nodes[i + 1];
|
||||
var lineEl = container.children[pos.row];
|
||||
lineEl && lineEl.appendChild(node);
|
||||
}
|
||||
callback && callback();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Transforms a given input code snippet into HTML using the given mode
|
||||
*
|
||||
* @param {string} input Code snippet
|
||||
* @param {string|mode} mode String specifying the mode to load such as
|
||||
* `ace/mode/javascript` or, a mode loaded from `/ace/mode`
|
||||
* (use 'ServerSideHiglighter.getMode').
|
||||
* @param {string|theme} theme String specifying the theme to load such as
|
||||
* `ace/theme/twilight` or, a theme loaded from `/ace/theme`.
|
||||
* @param {number} lineStart A number indicating the first line number. Defaults
|
||||
* to 1.
|
||||
* @param {boolean} disableGutter Specifies whether or not to disable the gutter.
|
||||
* `true` disables the gutter, `false` enables the gutter. Defaults to `false`.
|
||||
* @param {function} callback When specifying the mode or theme as a string,
|
||||
* this method has no return value and you must specify a callback function. The
|
||||
* callback will receive the rendered object containing the properties `html`
|
||||
* and `css`.
|
||||
* @returns {object} An object containing the properties `html` and `css`.
|
||||
*/
|
||||
highlight.render = function(input, mode, theme, lineStart, disableGutter, callback) {
|
||||
var waiting = 1;
|
||||
var modeCache = EditSession.prototype.$modes;
|
||||
|
||||
// if either the theme or the mode were specified as objects
|
||||
// then we need to lazily load them.
|
||||
if (typeof theme == "string") {
|
||||
waiting++;
|
||||
config.loadModule(['theme', theme], function(m) {
|
||||
theme = m;
|
||||
--waiting || done();
|
||||
});
|
||||
}
|
||||
// allow setting mode options e.h {path: "ace/mode/php", inline:true}
|
||||
var modeOptions;
|
||||
if (mode && typeof mode === "object" && !mode.getTokenizer) {
|
||||
modeOptions = mode;
|
||||
mode = modeOptions.path;
|
||||
}
|
||||
if (typeof mode == "string") {
|
||||
waiting++;
|
||||
config.loadModule(['mode', mode], function(m) {
|
||||
if (!modeCache[mode] || modeOptions)
|
||||
modeCache[mode] = new m.Mode(modeOptions);
|
||||
mode = modeCache[mode];
|
||||
--waiting || done();
|
||||
});
|
||||
}
|
||||
|
||||
// loads or passes the specified mode module then calls renderer
|
||||
function done() {
|
||||
var result = highlight.renderSync(input, mode, theme, lineStart, disableGutter);
|
||||
return callback ? callback(result) : result;
|
||||
}
|
||||
return --waiting || done();
|
||||
};
|
||||
|
||||
/**
|
||||
* Transforms a given input code snippet into HTML using the given mode
|
||||
* @param {string} input Code snippet
|
||||
* @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode')
|
||||
* @param {string} r Code snippet
|
||||
* @returns {object} An object containing: html, css
|
||||
*/
|
||||
highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) {
|
||||
lineStart = parseInt(lineStart || 1, 10);
|
||||
|
||||
var session = new EditSession("");
|
||||
session.setMode(mode);
|
||||
session.setUseWorker(false);
|
||||
session.setMode(mode);
|
||||
|
||||
var textLayer = new TextLayer(document.createElement("div"));
|
||||
textLayer.setSession(session);
|
||||
@@ -65,24 +164,27 @@ exports.render = function(input, mode, theme, lineStart, disableGutter) {
|
||||
for(var ix = 0; ix < length; ix++) {
|
||||
stringBuilder.push("<div class='ace_line'>");
|
||||
if (!disableGutter)
|
||||
stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + (ix + lineStart) + "</span>");
|
||||
stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + /*(ix + lineStart) + */ "</span>");
|
||||
textLayer.$renderLine(stringBuilder, ix, true, false);
|
||||
stringBuilder.push("</div>");
|
||||
stringBuilder.push("\n</div>");
|
||||
}
|
||||
|
||||
// let's prepare the whole html
|
||||
var html = "<div class=':cssClass'>\
|
||||
<div class='ace_editor ace_scroller ace_text-layer'>\
|
||||
:code\
|
||||
</div>\
|
||||
</div>".replace(/:cssClass/, theme.cssClass).replace(/:code/, stringBuilder.join(""));
|
||||
var html = "<div class='" + theme.cssClass + "'>" +
|
||||
"<div class='ace_static_highlight' style='counter-reset:ace_line " + (lineStart - 1) + "'>" +
|
||||
stringBuilder.join("") +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
|
||||
textLayer.destroy();
|
||||
|
||||
return {
|
||||
css: baseStyles + theme.cssText,
|
||||
html: html
|
||||
html: html,
|
||||
session: session
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = highlight;
|
||||
module.exports.highlight =highlight;
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ define(function(require, exports, module) {
|
||||
var assert = require("assert");
|
||||
var highlighter = require("./static_highlight");
|
||||
var JavaScriptMode = require("../mode/javascript").Mode;
|
||||
var TextMode = require("../mode/text").Mode;
|
||||
|
||||
// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite
|
||||
module.exports = {
|
||||
@@ -16,55 +17,74 @@ module.exports = {
|
||||
|
||||
"test simple snippet": function(next) {
|
||||
var theme = require("../theme/tomorrow");
|
||||
var snippet = "\
|
||||
/** this is a function\n\
|
||||
*\n\
|
||||
*/\n\
|
||||
function hello (a, b, c) {\n\
|
||||
console.log(a * b + c + 'sup?');\n\
|
||||
}";
|
||||
var snippet = [
|
||||
"/** this is a function",
|
||||
"*",
|
||||
"*/",
|
||||
"function hello (a, b, c) {",
|
||||
" console.log(a * b + c + 'sup$');",
|
||||
"}"
|
||||
].join("\n");
|
||||
var mode = new JavaScriptMode();
|
||||
|
||||
var result = highlighter.render(snippet, mode, theme);
|
||||
assert.equal(result.html, "<div class='ace-tomorrow'> <div class='ace_editor ace_scroller ace_text-layer'> <div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>1</span><span class='ace_comment ace_doc'>/** this is a function</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>2</span><span class='ace_comment ace_doc'>*</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>3</span><span class='ace_comment ace_doc'>*/</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>4</span><span class='ace_storage ace_type'>function</span> <span class='ace_entity ace_name ace_function'>hello</span> <span class='ace_paren ace_lparen'>(</span><span class='ace_variable ace_parameter'>a</span><span class='ace_punctuation ace_operator'>, </span><span class='ace_variable ace_parameter'>b</span><span class='ace_punctuation ace_operator'>, </span><span class='ace_variable ace_parameter'>c</span><span class='ace_paren ace_rparen'>)</span> <span class='ace_paren ace_lparen'>{</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>5</span>    <span class='ace_storage ace_type'>console</span><span class='ace_punctuation ace_operator'>.</span><span class='ace_support ace_function ace_firebug'>log</span><span class='ace_paren ace_lparen'>(</span><span class='ace_identifier'>a</span> <span class='ace_keyword ace_operator'>*</span> <span class='ace_identifier'>b</span> <span class='ace_keyword ace_operator'>+</span> <span class='ace_identifier'>c</span> <span class='ace_keyword ace_operator'>+</span> <span class='ace_string'>'sup?'</span><span class='ace_paren ace_rparen'>)</span><span class='ace_punctuation ace_operator'>;</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>6</span><span class='ace_paren ace_rparen'>}</span></div> </div> </div>");
|
||||
assert.equal(result.html, "<div class='ace-tomorrow'><div class='ace_static_highlight' style='counter-reset:ace_line 0'>"
|
||||
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>/**\xa0this\xa0is\xa0a\xa0function</span>\n</div>"
|
||||
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>*</span>\n</div>"
|
||||
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>*/</span>\n</div>"
|
||||
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_storage ace_type'>function</span>\xa0<span class='ace_entity ace_name ace_function'>hello</span>\xa0<span class='ace_paren ace_lparen'>(</span><span class='ace_variable ace_parameter'>a</span><span class='ace_punctuation ace_operator'>,\xa0</span><span class='ace_variable ace_parameter'>b</span><span class='ace_punctuation ace_operator'>,\xa0</span><span class='ace_variable ace_parameter'>c</span><span class='ace_paren ace_rparen'>)</span>\xa0<span class='ace_paren ace_lparen'>{</span>\n</div>"
|
||||
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span>\xa0\xa0\xa0\xa0<span class='ace_storage ace_type'>console</span><span class='ace_punctuation ace_operator'>.</span><span class='ace_support ace_function ace_firebug'>log</span><span class='ace_paren ace_lparen'>(</span><span class='ace_identifier'>a</span>\xa0<span class='ace_keyword ace_operator'>*</span>\xa0<span class='ace_identifier'>b</span>\xa0<span class='ace_keyword ace_operator'>+</span>\xa0<span class='ace_identifier'>c</span>\xa0<span class='ace_keyword ace_operator'>+</span>\xa0<span class='ace_string'>'sup$'</span><span class='ace_paren ace_rparen'>)</span><span class='ace_punctuation ace_operator'>;</span>\n</div>"
|
||||
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_paren ace_rparen'>}</span>\n</div>"
|
||||
+ "</div></div>");
|
||||
assert.ok(!!result.css);
|
||||
next();
|
||||
},
|
||||
|
||||
"test css from theme is used": function(next) {
|
||||
var theme = require("../theme/tomorrow");
|
||||
var snippet = "\
|
||||
/** this is a function\n\
|
||||
*\n\
|
||||
*/\n\
|
||||
function hello (a, b, c) {\n\
|
||||
console.log(a * b + c + 'sup?');\n\
|
||||
}";
|
||||
var snippet = [
|
||||
"/** this is a function",
|
||||
"*",
|
||||
"*/",
|
||||
"function hello (a, b, c) {",
|
||||
" console.log(a * b + c + 'sup?');",
|
||||
"}"
|
||||
].join("\n");
|
||||
var mode = new JavaScriptMode();
|
||||
|
||||
var isError = false, result;
|
||||
result = highlighter.render(snippet, mode, theme);
|
||||
var result = highlighter.render(snippet, mode, theme);
|
||||
|
||||
assert.ok(result.css.indexOf(theme.cssText) !== -1);
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
"test theme classname should be in output html": function (next) {
|
||||
"test theme classname should be in output html": function(next) {
|
||||
var theme = require("../theme/tomorrow");
|
||||
var snippet = "\
|
||||
/** this is a function\n\
|
||||
*\n\
|
||||
*/\n\
|
||||
function hello (a, b, c) {\n\
|
||||
console.log(a * b + c + 'sup?');\n\
|
||||
}";
|
||||
var snippet = [
|
||||
"/** this is a function",
|
||||
"*",
|
||||
"*/",
|
||||
"function hello (a, b, c) {",
|
||||
" console.log(a * b + c + 'sup?');",
|
||||
"}"
|
||||
].join("\n");
|
||||
var mode = new JavaScriptMode();
|
||||
|
||||
var isError = false, result;
|
||||
result = highlighter.render(snippet, mode, theme);
|
||||
var result = highlighter.render(snippet, mode, theme);
|
||||
assert.equal(!!result.html.match(/<div class='ace-tomorrow'>/), true);
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
"test js string replace specials": function(next) {
|
||||
var theme = require("../theme/tomorrow");
|
||||
var snippet = "$'$1$2$$$&";
|
||||
var mode = new TextMode();
|
||||
|
||||
var result = highlighter.render(snippet, mode, theme);
|
||||
assert.ok(result.html.indexOf(snippet) != -1);
|
||||
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
/** simple statusbar **/
|
||||
var dom = require("ace/lib/dom");
|
||||
var lang = require("ace/lib/lang");
|
||||
|
||||
var StatusBar = function(editor, parentNode) {
|
||||
this.element = dom.createElement("div");
|
||||
this.element.className = "ace_status-indicator";
|
||||
this.element.style.cssText = "display: inline-block;";
|
||||
parentNode.appendChild(this.element);
|
||||
|
||||
var statusUpdate = lang.delayedCall(function(){
|
||||
this.updateStatus(editor)
|
||||
}.bind(this));
|
||||
editor.on("changeStatus", function() {
|
||||
statusUpdate.schedule(100);
|
||||
});
|
||||
editor.on("changeSelection", function() {
|
||||
statusUpdate.schedule(100);
|
||||
});
|
||||
};
|
||||
|
||||
(function(){
|
||||
this.updateStatus = function(editor) {
|
||||
var status = [];
|
||||
function add(str, separator) {
|
||||
str && status.push(str, separator || "|");
|
||||
}
|
||||
|
||||
add(editor.keyBinding.getStatusText(editor));
|
||||
if (editor.commands.recording)
|
||||
add("REC");
|
||||
|
||||
var c = editor.selection.lead;
|
||||
add(c.row + ":" + c.column, " ");
|
||||
if (!editor.selection.isEmpty()) {
|
||||
var r = editor.getSelectionRange();
|
||||
add("(" + (r.end.row - r.start.row) + ":" +(r.end.column - r.start.column) + ")");
|
||||
}
|
||||
status.pop();
|
||||
this.element.textContent = status.join("");
|
||||
};
|
||||
}).call(StatusBar.prototype);
|
||||
|
||||
exports.StatusBar = StatusBar;
|
||||
|
||||
});
|
||||
@@ -74,7 +74,7 @@ function applyStyles(elm, styles) {
|
||||
|
||||
function setupContainer(element, getValue) {
|
||||
if (element.type != 'textarea') {
|
||||
throw "Textarea required!";
|
||||
throw new Error("Textarea required!");
|
||||
}
|
||||
|
||||
var parentNode = element.parentNode;
|
||||
@@ -132,11 +132,7 @@ function setupContainer(element, getValue) {
|
||||
resizeEvent();
|
||||
|
||||
// Insert the div container after the element.
|
||||
if (element.nextSibling) {
|
||||
parentNode.insertBefore(container, element.nextSibling);
|
||||
} else {
|
||||
parentNode.appendChild(container);
|
||||
}
|
||||
|
||||
// Override the forms onsubmit function. Set the innerHTML and value
|
||||
// of the textarea before submitting.
|
||||
@@ -145,7 +141,6 @@ function setupContainer(element, getValue) {
|
||||
var oldSumit = parentNode.onsubmit;
|
||||
// Override the onsubmit function of the form.
|
||||
parentNode.onsubmit = function(evt) {
|
||||
element.innerHTML = getValue();
|
||||
element.value = getValue();
|
||||
// If there is a onsubmit function already, then call
|
||||
// it with the current context and pass the event.
|
||||
@@ -160,7 +155,7 @@ function setupContainer(element, getValue) {
|
||||
return container;
|
||||
}
|
||||
|
||||
exports.transformTextarea = function(element, loader) {
|
||||
exports.transformTextarea = function(element, options) {
|
||||
var session;
|
||||
var container = setupContainer(element, function() {
|
||||
return session.getValue();
|
||||
@@ -177,7 +172,8 @@ exports.transformTextarea = function(element, loader) {
|
||||
left: "0px",
|
||||
right: "0px",
|
||||
bottom: "0px",
|
||||
border: "1px solid gray"
|
||||
border: "1px solid gray",
|
||||
position: "absolute"
|
||||
});
|
||||
container.appendChild(editorDiv);
|
||||
|
||||
@@ -198,7 +194,7 @@ exports.transformTextarea = function(element, loader) {
|
||||
var settingDiv = document.createElement("div");
|
||||
var settingDivStyles = {
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
left: "20%",
|
||||
right: "0px",
|
||||
bottom: "0px",
|
||||
position: "absolute",
|
||||
@@ -207,7 +203,8 @@ exports.transformTextarea = function(element, loader) {
|
||||
color: "white",
|
||||
display: "none",
|
||||
overflow: "auto",
|
||||
fontSize: "14px"
|
||||
fontSize: "14px",
|
||||
boxShadow: "-5px 2px 3px gray"
|
||||
};
|
||||
if (!UA.isOldIE) {
|
||||
settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
||||
@@ -218,9 +215,8 @@ exports.transformTextarea = function(element, loader) {
|
||||
applyStyles(settingDiv, settingDivStyles);
|
||||
container.appendChild(settingDiv);
|
||||
|
||||
options = options || exports.defaultOptions;
|
||||
// Power up ace on the textarea:
|
||||
var options = {};
|
||||
|
||||
var editor = ace.edit(editorDiv);
|
||||
session = editor.getSession();
|
||||
|
||||
@@ -228,13 +224,13 @@ exports.transformTextarea = function(element, loader) {
|
||||
editor.focus();
|
||||
|
||||
// Add the settingPanel opener to the editor's div.
|
||||
editorDiv.appendChild(settingOpener);
|
||||
container.appendChild(settingOpener);
|
||||
|
||||
// Create the API.
|
||||
setupApi(editor, editorDiv, settingDiv, ace, options, loader);
|
||||
setupApi(editor, editorDiv, settingDiv, ace, options, load);
|
||||
|
||||
// Create the setting's panel.
|
||||
setupSettingPanel(settingDiv, settingOpener, editor, options);
|
||||
setupSettingPanel(settingDiv, settingOpener, editor);
|
||||
|
||||
var state = "";
|
||||
event.addListener(settingOpener, "mousemove", function(e) {
|
||||
@@ -280,117 +276,98 @@ function setupApi(editor, editorDiv, settingDiv, ace, options, loader) {
|
||||
loader = loader || load;
|
||||
|
||||
function toBool(value) {
|
||||
return value == "true";
|
||||
return value === "true" || value == true;
|
||||
}
|
||||
|
||||
editor.setDisplaySettings = function(display) {
|
||||
if (display == null)
|
||||
display = settingDiv.style.display == "none";
|
||||
settingDiv.style.display = display ? "block" : "none";
|
||||
if (display) {
|
||||
settingDiv.style.display = "block";
|
||||
settingDiv.hideButton.focus();
|
||||
editor.on("focus", function onFocus() {
|
||||
editor.removeListener("focus", onFocus);
|
||||
settingDiv.style.display = "none";
|
||||
});
|
||||
} else {
|
||||
editor.focus();
|
||||
}
|
||||
};
|
||||
|
||||
editor.$setOption = editor.setOption;
|
||||
editor.$getOption = editor.getOption;
|
||||
editor.setOption = function(key, value) {
|
||||
if (options[key] == value) return;
|
||||
|
||||
switch (key) {
|
||||
case "gutter":
|
||||
renderer.setShowGutter(toBool(value));
|
||||
break;
|
||||
|
||||
case "mode":
|
||||
if (value != "text") {
|
||||
// Load the required mode file. Files get loaded only once.
|
||||
loader("mode-" + value + ".js", "ace/mode/" + value, function() {
|
||||
var aceMode = require("../mode/" + value).Mode;
|
||||
session.setMode(new aceMode());
|
||||
});
|
||||
} else {
|
||||
session.setMode(new (require("../mode/text").Mode));
|
||||
}
|
||||
editor.$setOption("mode", "ace/mode/" + value)
|
||||
break;
|
||||
|
||||
case "theme":
|
||||
if (value != "textmate") {
|
||||
// Load the required theme file. Files get loaded only once.
|
||||
loader("theme-" + value + ".js", "ace/theme/" + value, function() {
|
||||
editor.setTheme("ace/theme/" + value);
|
||||
});
|
||||
} else {
|
||||
editor.setTheme("ace/theme/textmate");
|
||||
}
|
||||
editor.$setOption("theme", "ace/theme/" + value)
|
||||
break;
|
||||
|
||||
case "fontSize":
|
||||
editorDiv.style.fontSize = value;
|
||||
case "keybindings":
|
||||
switch (value) {
|
||||
case "vim":
|
||||
editor.setKeyboardHandler("ace/keyboard/vim");
|
||||
break;
|
||||
case "emacs":
|
||||
editor.setKeyboardHandler("ace/keyboard/emacs");
|
||||
break;
|
||||
default:
|
||||
editor.setKeyboardHandler(null);
|
||||
}
|
||||
break;
|
||||
|
||||
case "softWrap":
|
||||
switch (value) {
|
||||
case "off":
|
||||
session.setUseWrapMode(false);
|
||||
renderer.setPrintMarginColumn(80);
|
||||
break;
|
||||
case "40":
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(40, 40);
|
||||
renderer.setPrintMarginColumn(40);
|
||||
break;
|
||||
case "80":
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(80, 80);
|
||||
renderer.setPrintMarginColumn(80);
|
||||
break;
|
||||
case "free":
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(null, null);
|
||||
renderer.setPrintMarginColumn(80);
|
||||
case "fontSize":
|
||||
editor.$setOption(key, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
editor.$setOption(key, toBool(value));
|
||||
}
|
||||
break;
|
||||
|
||||
case "useSoftTabs":
|
||||
session.setUseSoftTabs(toBool(value));
|
||||
break;
|
||||
|
||||
case "showPrintMargin":
|
||||
renderer.setShowPrintMargin(toBool(value));
|
||||
break;
|
||||
|
||||
case "showInvisibles":
|
||||
editor.setShowInvisibles(toBool(value));
|
||||
break;
|
||||
}
|
||||
|
||||
options[key] = value;
|
||||
};
|
||||
|
||||
editor.getOption = function(key) {
|
||||
return options[key];
|
||||
};
|
||||
switch (key) {
|
||||
case "mode":
|
||||
return editor.$getOption("mode").substr("ace/mode/".length)
|
||||
break;
|
||||
|
||||
editor.getOptions = function() {
|
||||
return options;
|
||||
};
|
||||
case "theme":
|
||||
return editor.$getOption("theme").substr("ace/theme/".length)
|
||||
break;
|
||||
|
||||
for (var option in exports.options) {
|
||||
editor.setOption(option, exports.options[option]);
|
||||
case "keybindings":
|
||||
var value = editor.getKeyboardHandler()
|
||||
switch (value && value.$id) {
|
||||
case "ace/keyboard/vim":
|
||||
return "vim";
|
||||
case "ace/keyboard/emacs":
|
||||
return "emacs";
|
||||
default:
|
||||
return "ace";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return editor.$getOption(key);
|
||||
}
|
||||
};
|
||||
|
||||
editor.setOptions(options);
|
||||
return editor;
|
||||
}
|
||||
|
||||
function setupSettingPanel(settingDiv, settingOpener, editor, options) {
|
||||
var BOOL = {
|
||||
"true": true,
|
||||
"false": false
|
||||
};
|
||||
function setupSettingPanel(settingDiv, settingOpener, editor) {
|
||||
var BOOL = null;
|
||||
|
||||
var desc = {
|
||||
mode: "Mode:",
|
||||
gutter: "Display Gutter:",
|
||||
wrap: "Soft Wrap:",
|
||||
theme: "Theme:",
|
||||
fontSize: "Font Size:",
|
||||
softWrap: "Soft Wrap:",
|
||||
showGutter: "Display Gutter:",
|
||||
keybindings: "Keyboard",
|
||||
showPrintMargin: "Show Print Margin:",
|
||||
useSoftTabs: "Use Soft Tabs:",
|
||||
showInvisibles: "Show Invisibles"
|
||||
@@ -442,7 +419,7 @@ function setupSettingPanel(settingDiv, settingOpener, editor, options) {
|
||||
twilight: "Twilight",
|
||||
vibrant_ink: "Vibrant Ink"
|
||||
},
|
||||
gutter: BOOL,
|
||||
showGutter: BOOL,
|
||||
fontSize: {
|
||||
"10px": "10px",
|
||||
"11px": "11px",
|
||||
@@ -450,12 +427,17 @@ function setupSettingPanel(settingDiv, settingOpener, editor, options) {
|
||||
"14px": "14px",
|
||||
"16px": "16px"
|
||||
},
|
||||
softWrap: {
|
||||
wrap: {
|
||||
off: "Off",
|
||||
40: "40",
|
||||
80: "80",
|
||||
free: "Free"
|
||||
},
|
||||
keybindings: {
|
||||
ace: "ace",
|
||||
vim: "vim",
|
||||
emacs: "emacs"
|
||||
},
|
||||
showPrintMargin: BOOL,
|
||||
useSoftTabs: BOOL,
|
||||
showInvisibles: BOOL
|
||||
@@ -465,6 +447,14 @@ function setupSettingPanel(settingDiv, settingOpener, editor, options) {
|
||||
table.push("<table><tr><th>Setting</th><th>Value</th></tr>");
|
||||
|
||||
function renderOption(builder, option, obj, cValue) {
|
||||
if (!obj) {
|
||||
builder.push(
|
||||
"<input type='checkbox' title='", option, "' ",
|
||||
cValue + "" == "true" ? "checked='true'" : "",
|
||||
"'></input>"
|
||||
);
|
||||
return;
|
||||
}
|
||||
builder.push("<select title='" + option + "'>");
|
||||
for (var value in obj) {
|
||||
builder.push("<option value='" + value + "' ");
|
||||
@@ -480,27 +470,30 @@ function setupSettingPanel(settingDiv, settingOpener, editor, options) {
|
||||
builder.push("</select>");
|
||||
}
|
||||
|
||||
for (var option in options) {
|
||||
for (var option in exports.defaultOptions) {
|
||||
table.push("<tr><td>", desc[option], "</td>");
|
||||
table.push("<td>");
|
||||
renderOption(table, option, optionValues[option], options[option]);
|
||||
renderOption(table, option, optionValues[option], editor.getOption(option));
|
||||
table.push("</td></tr>");
|
||||
}
|
||||
table.push("</table>");
|
||||
settingDiv.innerHTML = table.join("");
|
||||
|
||||
var selects = settingDiv.getElementsByTagName("select");
|
||||
for (var i = 0; i < selects.length; i++) {
|
||||
var onChange = (function() {
|
||||
var select = selects[i];
|
||||
return function() {
|
||||
var option = select.title;
|
||||
var value = select.value;
|
||||
editor.setOption(option, value);
|
||||
var onChange = function(e) {
|
||||
var select = e.currentTarget;
|
||||
editor.setOption(select.title, select.value);
|
||||
};
|
||||
})();
|
||||
var onClick = function(e) {
|
||||
var cb = e.currentTarget;
|
||||
editor.setOption(cb.title, cb.checked);
|
||||
};
|
||||
var selects = settingDiv.getElementsByTagName("select");
|
||||
for (var i = 0; i < selects.length; i++)
|
||||
selects[i].onchange = onChange;
|
||||
}
|
||||
var cbs = settingDiv.getElementsByTagName("input");
|
||||
for (var i = 0; i < cbs.length; i++)
|
||||
cbs[i].onclick = onClick;
|
||||
|
||||
|
||||
var button = document.createElement("input");
|
||||
button.type = "button";
|
||||
@@ -509,18 +502,20 @@ function setupSettingPanel(settingDiv, settingOpener, editor, options) {
|
||||
editor.setDisplaySettings(false);
|
||||
});
|
||||
settingDiv.appendChild(button);
|
||||
settingDiv.hideButton = button;
|
||||
}
|
||||
|
||||
// Default startup options.
|
||||
exports.options = {
|
||||
mode: "text",
|
||||
exports.defaultOptions = {
|
||||
mode: "javascript",
|
||||
theme: "textmate",
|
||||
gutter: "false",
|
||||
wrap: "off",
|
||||
fontSize: "12px",
|
||||
softWrap: "off",
|
||||
showGutter: "false",
|
||||
keybindings: "ace",
|
||||
showPrintMargin: "false",
|
||||
useSoftTabs: "true",
|
||||
showInvisibles: "true"
|
||||
showInvisibles: "false"
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributed to Ajax.org under the BSD license.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Generates a list of themes available when ace was built.
|
||||
* @fileOverview Generates a list of themes available when ace was built.
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">
|
||||
* Matthew Christopher Kastor-Inare III </a><br />
|
||||
* ☭ Hial Atropa!! ☭
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
require("ace/lib/fixoldbrowsers");
|
||||
|
||||
var themeData = [
|
||||
["Chrome" ],
|
||||
["Clouds" ],
|
||||
["Crimson Editor" ],
|
||||
["Dawn" ],
|
||||
["Dreamweaver" ],
|
||||
["Eclipse" ],
|
||||
["GitHub" ],
|
||||
["Solarized Light"],
|
||||
["TextMate" ],
|
||||
["Tomorrow" ],
|
||||
["XCode" ],
|
||||
["Kuroir"],
|
||||
["KatzenMilch"],
|
||||
["Ambiance" ,"ambiance" , "dark"],
|
||||
["Chaos" ,"chaos" , "dark"],
|
||||
["Clouds Midnight" ,"clouds_midnight" , "dark"],
|
||||
["Cobalt" ,"cobalt" , "dark"],
|
||||
["idle Fingers" ,"idle_fingers" , "dark"],
|
||||
["krTheme" ,"kr_theme" , "dark"],
|
||||
["Merbivore" ,"merbivore" , "dark"],
|
||||
["Merbivore Soft" ,"merbivore_soft" , "dark"],
|
||||
["Mono Industrial" ,"mono_industrial" , "dark"],
|
||||
["Monokai" ,"monokai" , "dark"],
|
||||
["Pastel on dark" ,"pastel_on_dark" , "dark"],
|
||||
["Solarized Dark" ,"solarized_dark" , "dark"],
|
||||
["Terminal" ,"terminal" , "dark"],
|
||||
["Tomorrow Night" ,"tomorrow_night" , "dark"],
|
||||
["Tomorrow Night Blue" ,"tomorrow_night_blue" , "dark"],
|
||||
["Tomorrow Night Bright","tomorrow_night_bright" , "dark"],
|
||||
["Tomorrow Night 80s" ,"tomorrow_night_eighties" , "dark"],
|
||||
["Twilight" ,"twilight" , "dark"],
|
||||
["Vibrant Ink" ,"vibrant_ink" , "dark"]
|
||||
];
|
||||
|
||||
|
||||
exports.themesByName = {};
|
||||
|
||||
/**
|
||||
* An array containing information about available themes.
|
||||
*/
|
||||
exports.themes = themeData.map(function(data) {
|
||||
var name = data[1] || data[0].replace(/ /g, "_").toLowerCase();
|
||||
var theme = {
|
||||
caption: data[0],
|
||||
theme: "ace/theme/" + name,
|
||||
isDark: data[2] == "dark",
|
||||
name: name
|
||||
};
|
||||
exports.themesByName[name] = theme;
|
||||
return theme;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var lang = require("../lib/lang");
|
||||
|
||||
// based on http://www.freehackers.org/Indent_Finder
|
||||
exports.$detectIndentation = function(lines, fallback) {
|
||||
var stats = [];
|
||||
var changes = [];
|
||||
var tabIndents = 0;
|
||||
var prevSpaces = 0;
|
||||
var max = Math.min(lines.length, 1000);
|
||||
for (var i = 0; i < max; i++) {
|
||||
var line = lines[i];
|
||||
// ignore empty and comment lines
|
||||
if (!/^\s*[^*+\-\s]/.test(line))
|
||||
continue;
|
||||
|
||||
if (line[0] == "\t")
|
||||
tabIndents++;
|
||||
|
||||
var spaces = line.match(/^ */)[0].length;
|
||||
if (spaces && line[spaces] != "\t") {
|
||||
var diff = spaces - prevSpaces;
|
||||
if (diff > 0 && !(prevSpaces%diff) && !(spaces%diff))
|
||||
changes[diff] = (changes[diff] || 0) + 1;
|
||||
|
||||
stats[spaces] = (stats[spaces] || 0) + 1;
|
||||
}
|
||||
prevSpaces = spaces;
|
||||
|
||||
// ignore lines ending with backslash
|
||||
while (i < max && line[line.length - 1] == "\\")
|
||||
line = lines[i++];
|
||||
}
|
||||
|
||||
function getScore(indent) {
|
||||
var score = 0;
|
||||
for (var i = indent; i < stats.length; i += indent)
|
||||
score += stats[i] || 0;
|
||||
return score;
|
||||
}
|
||||
|
||||
var changesTotal = changes.reduce(function(a,b){return a+b}, 0);
|
||||
|
||||
var first = {score: 0, length: 0};
|
||||
var spaceIndents = 0;
|
||||
for (var i = 1; i < 12; i++) {
|
||||
var score = getScore(i);
|
||||
if (i == 1) {
|
||||
spaceIndents = score;
|
||||
score = stats[1] ? 0.9 : 0.8;
|
||||
if (!stats.length)
|
||||
score = 0
|
||||
} else
|
||||
score /= spaceIndents;
|
||||
|
||||
if (changes[i])
|
||||
score += changes[i] / changesTotal;
|
||||
|
||||
if (score > first.score)
|
||||
first = {score: score, length: i};
|
||||
}
|
||||
|
||||
if (first.score && first.score > 1.4)
|
||||
var tabLength = first.length;
|
||||
|
||||
if (tabIndents > spaceIndents + 1)
|
||||
return {ch: "\t", length: tabLength};
|
||||
|
||||
if (spaceIndents > tabIndents + 1)
|
||||
return {ch: " ", length: tabLength};
|
||||
};
|
||||
|
||||
exports.detectIndentation = function(session) {
|
||||
var lines = session.getLines(0, 1000);
|
||||
var indent = exports.$detectIndentation(lines) || {};
|
||||
|
||||
if (indent.ch)
|
||||
session.setUseSoftTabs(indent.ch == " ");
|
||||
|
||||
if (indent.length)
|
||||
session.setTabSize(indent.length);
|
||||
return indent;
|
||||
};
|
||||
|
||||
exports.trimTrailingSpace = function(session, trimEmpty) {
|
||||
var doc = session.getDocument();
|
||||
var lines = doc.getAllLines();
|
||||
|
||||
var min = trimEmpty ? -1 : 0;
|
||||
|
||||
for (var i = 0, l=lines.length; i < l; i++) {
|
||||
var line = lines[i];
|
||||
var index = line.search(/\s+$/);
|
||||
|
||||
if (index > min)
|
||||
doc.removeInLine(i, index, line.length);
|
||||
}
|
||||
};
|
||||
|
||||
exports.convertIndentation = function(session, ch, len) {
|
||||
var oldCh = session.getTabString()[0];
|
||||
var oldLen = session.getTabSize();
|
||||
if (!len) len = oldLen;
|
||||
if (!ch) ch = oldCh;
|
||||
|
||||
var tab = ch == "\t" ? ch: lang.stringRepeat(ch, len);
|
||||
|
||||
var doc = session.doc;
|
||||
var lines = doc.getAllLines();
|
||||
|
||||
var cache = {};
|
||||
var spaceCache = {};
|
||||
for (var i = 0, l=lines.length; i < l; i++) {
|
||||
var line = lines[i];
|
||||
var match = line.match(/^\s*/)[0];
|
||||
if (match) {
|
||||
var w = session.$getStringScreenWidth(match)[0];
|
||||
var tabCount = Math.floor(w/oldLen);
|
||||
var reminder = w%oldLen;
|
||||
var toInsert = cache[tabCount] || (cache[tabCount] = lang.stringRepeat(tab, tabCount));
|
||||
toInsert += spaceCache[reminder] || (spaceCache[reminder] = lang.stringRepeat(" ", reminder));
|
||||
|
||||
if (toInsert != match) {
|
||||
doc.removeInLine(i, 0, match.length);
|
||||
doc.insertInLine({row: i, column: 0}, toInsert);
|
||||
}
|
||||
}
|
||||
}
|
||||
session.setTabSize(len);
|
||||
session.setUseSoftTabs(ch == " ");
|
||||
};
|
||||
|
||||
exports.$parseStringArg = function(text) {
|
||||
var indent = {};
|
||||
if (/t/.test(text))
|
||||
indent.ch = "\t";
|
||||
else if (/s/.test(text))
|
||||
indent.ch = " ";
|
||||
var m = text.match(/\d+/);
|
||||
if (m)
|
||||
indent.length = parseInt(m[0], 10);
|
||||
return indent;
|
||||
};
|
||||
|
||||
exports.$parseArg = function(arg) {
|
||||
if (!arg)
|
||||
return {};
|
||||
if (typeof arg == "string")
|
||||
return exports.$parseStringArg(arg);
|
||||
if (typeof arg.text == "string")
|
||||
return exports.$parseStringArg(arg.text);
|
||||
return arg;
|
||||
};
|
||||
|
||||
exports.commands = [{
|
||||
name: "detectIndentation",
|
||||
exec: function(editor) {
|
||||
exports.detectIndentation(editor.session);
|
||||
// todo show message?
|
||||
}
|
||||
}, {
|
||||
name: "trimTrailingSpace",
|
||||
exec: function(editor) {
|
||||
exports.trimTrailingSpace(editor.session);
|
||||
}
|
||||
}, {
|
||||
name: "convertIndentation",
|
||||
exec: function(editor, arg) {
|
||||
var indent = exports.$parseArg(arg);
|
||||
exports.convertIndentation(editor.session, indent.ch, indent.length);
|
||||
}
|
||||
}, {
|
||||
name: "setIndentation",
|
||||
exec: function(editor, arg) {
|
||||
var indent = exports.$parseArg(arg);
|
||||
indent.length && editor.session.setTabSize(indent.length);
|
||||
indent.ch && editor.session.setUseSoftTabs(indent.ch == " ");
|
||||
}
|
||||
}];
|
||||
|
||||
});
|
||||
@@ -0,0 +1,116 @@
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("../test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var EditSession = require("../edit_session").EditSession;
|
||||
var whitespace = require("./whitespace");
|
||||
|
||||
// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite
|
||||
module.exports = {
|
||||
timeout: 10000,
|
||||
|
||||
"test tab detection": function(next) {
|
||||
var s = new EditSession([
|
||||
"define({",
|
||||
"\tfoo:1,",
|
||||
"\tbar:2,",
|
||||
"\tbaz:{,",
|
||||
"\t\tx:3",
|
||||
"\t}",
|
||||
"})"
|
||||
]);
|
||||
|
||||
var indent = whitespace.$detectIndentation(s.doc.$lines);
|
||||
assert.equal(indent.ch, "\t");
|
||||
assert.equal(indent.length, undefined);
|
||||
|
||||
s.insert({row: 0, column: 0}, " ");
|
||||
indent = whitespace.$detectIndentation(s.doc.$lines);
|
||||
assert.equal(indent.ch, "\t");
|
||||
assert.equal(indent.length, 4);
|
||||
|
||||
s.setValue("");
|
||||
indent = whitespace.$detectIndentation(s.doc.$lines);
|
||||
assert.ok(!indent);
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
"test empty session": function(next) {
|
||||
var s = new EditSession([
|
||||
"define({",
|
||||
"foo:1,",
|
||||
"})"
|
||||
]);
|
||||
var indent = whitespace.$detectIndentation(s.doc.$lines);
|
||||
assert.ok(!indent);
|
||||
s.insert({row: 1, column: 0}, " x\n ");
|
||||
|
||||
indent = whitespace.$detectIndentation(s.doc.$lines);
|
||||
assert.equal(indent.ch, " ");
|
||||
assert.equal(indent.length, 4);
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
"!test one line": function(next) {
|
||||
var s = new EditSession([
|
||||
"define({",
|
||||
" foo:1,",
|
||||
"})"
|
||||
]);
|
||||
var indent = whitespace.$detectIndentation(s.doc.$lines);
|
||||
assert.equal(indent.ch, " ");
|
||||
assert.equal(indent.length, 4);
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
"test 1 width indents": function(next) {
|
||||
var s = new EditSession([
|
||||
"define({",
|
||||
" foo:1,",
|
||||
"})",
|
||||
"define({",
|
||||
" bar:1,",
|
||||
"})",
|
||||
" t",
|
||||
" t",
|
||||
" t",
|
||||
" t",
|
||||
" t",
|
||||
" t",
|
||||
" t",
|
||||
" t"
|
||||
]);
|
||||
var indent = whitespace.$detectIndentation(s.doc.$lines);
|
||||
// assert.equal(indent.ch, " ");
|
||||
// assert.equal(indent.length, 4);
|
||||
|
||||
s = new EditSession([
|
||||
"{",
|
||||
" foo:1,",
|
||||
" bar: {",
|
||||
" baz:2",
|
||||
" }",
|
||||
"}"
|
||||
]);
|
||||
indent = whitespace.$detectIndentation(s.doc.$lines);
|
||||
assert.equal(indent.ch, " ");
|
||||
assert.equal(indent.length, 1);
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var Range = require("./range").Range;
|
||||
var Search = require("./search").Search;
|
||||
var SearchHighlight = require("./search_highlight").SearchHighlight;
|
||||
var iSearchCommandModule = require("./commands/incremental_search_commands");
|
||||
var ISearchKbd = iSearchCommandModule.IncrementalSearchKeyboardHandler;
|
||||
|
||||
/**
|
||||
* @class IncrementalSearch
|
||||
*
|
||||
* Implements immediate searching while the user is typing. When incremental
|
||||
* search is activated, keystrokes into the editor will be used for composing
|
||||
* a search term. Immediately after every keystroke the search is updated:
|
||||
* - so-far-matching characters are highlighted
|
||||
* - the cursor is moved to the next match
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Creates a new `IncrementalSearch` object.
|
||||
*
|
||||
* @constructor
|
||||
**/
|
||||
function IncrementalSearch() {
|
||||
this.$options = {wrap: false, skipCurrent: false};
|
||||
this.$keyboardHandler = new ISearchKbd(this);
|
||||
}
|
||||
|
||||
oop.inherits(IncrementalSearch, Search);
|
||||
|
||||
// regexp handling
|
||||
|
||||
function isRegExp(obj) {
|
||||
return obj instanceof RegExp;
|
||||
}
|
||||
|
||||
function regExpToObject(re) {
|
||||
var string = String(re),
|
||||
start = string.indexOf('/'),
|
||||
flagStart = string.lastIndexOf('/');
|
||||
return {
|
||||
expression: string.slice(start+1, flagStart),
|
||||
flags: string.slice(flagStart+1)
|
||||
}
|
||||
}
|
||||
|
||||
function stringToRegExp(string, flags) {
|
||||
try {
|
||||
return new RegExp(string, flags);
|
||||
} catch (e) { return string; }
|
||||
}
|
||||
|
||||
function objectToRegExp(obj) {
|
||||
return stringToRegExp(obj.expression, obj.flags);
|
||||
}
|
||||
|
||||
// iSearch class
|
||||
|
||||
;(function() {
|
||||
|
||||
this.activate = function(ed, backwards) {
|
||||
this.$editor = ed;
|
||||
this.$startPos = this.$currentPos = ed.getCursorPosition();
|
||||
this.$options.needle = '';
|
||||
this.$options.backwards = backwards;
|
||||
ed.keyBinding.addKeyboardHandler(this.$keyboardHandler);
|
||||
// we need to completely intercept paste, just registering an event handler does not work
|
||||
this.$originalEditorOnPaste = ed.onPaste; ed.onPaste = this.onPaste.bind(this);
|
||||
this.$mousedownHandler = ed.addEventListener('mousedown', this.onMouseDown.bind(this));
|
||||
this.selectionFix(ed);
|
||||
this.statusMessage(true);
|
||||
}
|
||||
|
||||
this.deactivate = function(reset) {
|
||||
this.cancelSearch(reset);
|
||||
var ed = this.$editor;
|
||||
ed.keyBinding.removeKeyboardHandler(this.$keyboardHandler);
|
||||
if (this.$mousedownHandler) {
|
||||
ed.removeEventListener('mousedown', this.$mousedownHandler);
|
||||
delete this.$mousedownHandler;
|
||||
}
|
||||
ed.onPaste = this.$originalEditorOnPaste;
|
||||
this.message('');
|
||||
}
|
||||
|
||||
this.selectionFix = function(editor) {
|
||||
// Fix selection bug: When clicked inside the editor
|
||||
// editor.selection.$isEmpty is false even if the mouse click did not
|
||||
// open a selection. This is interpreted by the move commands to
|
||||
// extend the selection. To only extend the selection when there is
|
||||
// one, we clear it here
|
||||
if (editor.selection.isEmpty() && !editor.session.$emacsMark) {
|
||||
editor.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
this.highlight = function(regexp) {
|
||||
var sess = this.$editor.session,
|
||||
hl = sess.$isearchHighlight = sess.$isearchHighlight || sess.addDynamicMarker(
|
||||
new SearchHighlight(null, "ace_isearch-result", "text"));
|
||||
hl.setRegexp(regexp);
|
||||
sess._emit("changeBackMarker"); // force highlight layer redraw
|
||||
}
|
||||
|
||||
this.cancelSearch = function(reset) {
|
||||
var e = this.$editor;
|
||||
this.$prevNeedle = this.$options.needle;
|
||||
this.$options.needle = '';
|
||||
if (reset) {
|
||||
e.moveCursorToPosition(this.$startPos);
|
||||
this.$currentPos = this.$startPos;
|
||||
} else {
|
||||
e.pushEmacsMark && e.pushEmacsMark(this.$startPos, false);
|
||||
}
|
||||
this.highlight(null);
|
||||
return Range.fromPoints(this.$currentPos, this.$currentPos);
|
||||
}
|
||||
|
||||
this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) {
|
||||
if (!this.$editor) return null;
|
||||
var options = this.$options;
|
||||
|
||||
// get search term
|
||||
if (needleUpdateFunc) {
|
||||
options.needle = needleUpdateFunc.call(this, options.needle || '') || '';
|
||||
}
|
||||
if (options.needle.length === 0) {
|
||||
this.statusMessage(true);
|
||||
return this.cancelSearch(true);
|
||||
};
|
||||
|
||||
// try to find the next occurence and enable highlighting marker
|
||||
options.start = this.$currentPos;
|
||||
var session = this.$editor.session,
|
||||
found = this.find(session),
|
||||
shouldSelect = this.$editor.emacsMark ?
|
||||
!!this.$editor.emacsMark() : !this.$editor.selection.isEmpty();
|
||||
if (found) {
|
||||
if (options.backwards) found = Range.fromPoints(found.end, found.start);
|
||||
this.$editor.selection.setRange(Range.fromPoints(shouldSelect ? this.$startPos : found.end, found.end));
|
||||
if (moveToNext) this.$currentPos = found.end;
|
||||
// highlight after cursor move, so selection works properly
|
||||
this.highlight(options.re)
|
||||
}
|
||||
|
||||
this.statusMessage(found);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
this.addString = function(s) {
|
||||
return this.highlightAndFindWithNeedle(false, function(needle) {
|
||||
if (!isRegExp(needle))
|
||||
return needle + s;
|
||||
var reObj = regExpToObject(needle);
|
||||
reObj.expression += s;
|
||||
return objectToRegExp(reObj);
|
||||
});
|
||||
}
|
||||
|
||||
this.removeChar = function(c) {
|
||||
return this.highlightAndFindWithNeedle(false, function(needle) {
|
||||
if (!isRegExp(needle))
|
||||
return needle.substring(0, needle.length-1);
|
||||
var reObj = regExpToObject(needle);
|
||||
reObj.expression = reObj.expression.substring(0, reObj.expression.length-1);
|
||||
return objectToRegExp(reObj);
|
||||
});
|
||||
}
|
||||
|
||||
this.next = function(options) {
|
||||
// try to find the next occurence of whatever we have searched for
|
||||
// earlier.
|
||||
// options = {[backwards: BOOL], [useCurrentOrPrevSearch: BOOL]}
|
||||
options = options || {};
|
||||
this.$options.backwards = !!options.backwards;
|
||||
this.$currentPos = this.$editor.getCursorPosition();
|
||||
return this.highlightAndFindWithNeedle(true, function(needle) {
|
||||
return options.useCurrentOrPrevSearch && needle.length === 0 ?
|
||||
this.$prevNeedle || '' : needle;
|
||||
});
|
||||
}
|
||||
|
||||
this.onMouseDown = function(evt) {
|
||||
// when mouse interaction happens then we quit incremental search
|
||||
this.deactivate();
|
||||
return true;
|
||||
}
|
||||
|
||||
this.onPaste = function(text) {
|
||||
this.addString(text);
|
||||
}
|
||||
|
||||
this.convertNeedleToRegExp = function() {
|
||||
return this.highlightAndFindWithNeedle(false, function(needle) {
|
||||
return isRegExp(needle) ? needle : stringToRegExp(needle, 'ig');
|
||||
});
|
||||
}
|
||||
|
||||
this.convertNeedleToString = function() {
|
||||
return this.highlightAndFindWithNeedle(false, function(needle) {
|
||||
return isRegExp(needle) ? regExpToObject(needle).expression : needle;
|
||||
});
|
||||
}
|
||||
|
||||
this.statusMessage = function(found) {
|
||||
var options = this.$options, msg = '';
|
||||
msg += options.backwards ? 'reverse-' : '';
|
||||
msg += 'isearch: ' + options.needle;
|
||||
msg += found ? '' : ' (not found)';
|
||||
this.message(msg);
|
||||
}
|
||||
|
||||
this.message = function(msg) {
|
||||
if (this.$editor.showCommandLine) {
|
||||
this.$editor.showCommandLine(msg);
|
||||
this.$editor.focus();
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}).call(IncrementalSearch.prototype);
|
||||
|
||||
|
||||
exports.IncrementalSearch = IncrementalSearch;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Config settings for enabling/disabling [[IncrementalSearch `IncrementalSearch`]].
|
||||
*
|
||||
**/
|
||||
|
||||
var dom = require('./lib/dom');
|
||||
dom.importCssString && dom.importCssString("\
|
||||
.ace_marker-layer .ace_isearch-result {\
|
||||
position: absolute;\
|
||||
z-index: 6;\
|
||||
-moz-box-sizing: border-box;\
|
||||
-webkit-box-sizing: border-box;\
|
||||
box-sizing: border-box;\
|
||||
}\
|
||||
div.ace_isearch-result {\
|
||||
border-radius: 4px;\
|
||||
background-color: rgba(255, 200, 0, 0.5);\
|
||||
box-shadow: 0 0 4px rgb(255, 200, 0);\
|
||||
}\
|
||||
.ace_dark div.ace_isearch-result {\
|
||||
background-color: rgb(100, 110, 160);\
|
||||
box-shadow: 0 0 4px rgb(80, 90, 140);\
|
||||
}", "incremental-search-highlighting");
|
||||
|
||||
// support for default keyboard handler
|
||||
var commands = require("./commands/command_manager");
|
||||
(function() {
|
||||
this.setupIncrementalSearch = function(editor, val) {
|
||||
if (this.usesIncrementalSearch == val) return;
|
||||
this.usesIncrementalSearch = val;
|
||||
var iSearchCommands = iSearchCommandModule.iSearchStartCommands;
|
||||
var method = val ? 'addCommands' : 'removeCommands';
|
||||
this[method](iSearchCommands);
|
||||
};
|
||||
}).call(commands.CommandManager.prototype);
|
||||
|
||||
// incremental search config option
|
||||
var Editor = require("./editor").Editor;
|
||||
require("./config").defineOptions(Editor.prototype, "editor", {
|
||||
useIncrementalSearch: {
|
||||
set: function(val) {
|
||||
this.keyBinding.$handlers.forEach(function(handler) {
|
||||
if (handler.setupIncrementalSearch) {
|
||||
handler.setupIncrementalSearch(this, val);
|
||||
}
|
||||
});
|
||||
this._emit('incrementalSearchSettingChanged', {isEnabled: val});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,213 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var emacs = require('./keyboard/emacs');
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var Range = require("./range").Range;
|
||||
var MultiSelect = require("./multi_select").MultiSelect;
|
||||
var assert = require("./test/assertions");
|
||||
var IncrementalSearch = require("./incremental_search").IncrementalSearch;
|
||||
|
||||
require("./multi_select");
|
||||
|
||||
var editor, iSearch;
|
||||
function testRanges(str, ranges) {
|
||||
ranges = ranges || editor.selection.getAllRanges();
|
||||
assert.equal(ranges + "", str + "");
|
||||
}
|
||||
|
||||
// force "rerender"
|
||||
function callHighlighterUpdate() {
|
||||
var session = editor.session,
|
||||
ranges = [],
|
||||
mockMarkerLayer = {
|
||||
drawSingleLineMarker: function(_, markerRanges) {
|
||||
ranges = ranges.concat(markerRanges);
|
||||
}
|
||||
}
|
||||
session.$isearchHighlight.update([], mockMarkerLayer, session, {
|
||||
firstRow: 0, lastRow: session.getRowLength()});
|
||||
return ranges;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
name: "ACE incremental_search.js",
|
||||
|
||||
setUp: function() {
|
||||
var session = new EditSession(["abc123", "xyz124"]);
|
||||
editor = new Editor(new MockRenderer(), session);
|
||||
new MultiSelect(editor);
|
||||
iSearch = new IncrementalSearch();
|
||||
},
|
||||
|
||||
"test: keyboard handler setup" : function() {
|
||||
iSearch.activate(editor);
|
||||
assert.equal(editor.getKeyboardHandler(), iSearch.$keyboardHandler);
|
||||
iSearch.deactivate();
|
||||
assert.notEqual(editor.getKeyboardHandler(), iSearch.$keyboardHandler);
|
||||
},
|
||||
|
||||
"test: isearch highlight setup" : function() {
|
||||
var sess = editor.session;
|
||||
iSearch.activate(editor);
|
||||
iSearch.highlight('foo');
|
||||
var highl = sess.$isearchHighlight.id;
|
||||
assert.ok(sess.$isearchHighlight, 'session has no isearch highlighter');
|
||||
assert.equal(sess.getMarkers()[highl.id], highl.id, 'isearch highlight not in markers');
|
||||
iSearch.deactivate();
|
||||
iSearch.activate(editor);
|
||||
iSearch.highlight('bar');
|
||||
var highl2 = sess.$isearchHighlight.id;
|
||||
assert.equal(highl2, highl, 'multiple isearch highlights');
|
||||
},
|
||||
|
||||
"test: find simple text incrementally" : function() {
|
||||
iSearch.activate(editor);
|
||||
var range = iSearch.addString('1'), // "1"
|
||||
highlightRanges = callHighlighterUpdate(editor.session);
|
||||
testRanges("Range: [0/3] -> [0/4]", [range], "range");
|
||||
testRanges("Range: [0/3] -> [0/4],Range: [1/3] -> [1/4]", highlightRanges, "highlight");
|
||||
|
||||
range = iSearch.addString('2'); // "12"
|
||||
highlightRanges = callHighlighterUpdate(editor.session);
|
||||
testRanges("Range: [0/3] -> [0/5]", [range], "range");
|
||||
testRanges("Range: [0/3] -> [0/5],Range: [1/3] -> [1/5]", highlightRanges, "highlight");
|
||||
|
||||
range = iSearch.addString('3'); // "123"
|
||||
highlightRanges = callHighlighterUpdate(editor.session);
|
||||
testRanges("Range: [0/3] -> [0/6]", [range], "range");
|
||||
testRanges("Range: [0/3] -> [0/6]", highlightRanges, "highlight");
|
||||
|
||||
range = iSearch.removeChar(); // "12"
|
||||
highlightRanges = callHighlighterUpdate(editor.session);
|
||||
testRanges("Range: [0/3] -> [0/5]", [range], "range");
|
||||
testRanges("Range: [0/3] -> [0/5],Range: [1/3] -> [1/5]", highlightRanges, "highlight");
|
||||
},
|
||||
|
||||
"test: forward / backward" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addString('1'); iSearch.addString('2');
|
||||
var range = iSearch.next();
|
||||
testRanges("Range: [1/3] -> [1/5]", [range], "range");
|
||||
|
||||
range = iSearch.next(); // nothing to find
|
||||
testRanges("", [range], "range");
|
||||
|
||||
range = iSearch.next({backwards: true}); // backwards
|
||||
testRanges("Range: [1/5] -> [1/3]", [range], "range");
|
||||
},
|
||||
|
||||
"test: cancelSearch" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addString('1'); iSearch.addString('2');
|
||||
var range = iSearch.cancelSearch(true);
|
||||
testRanges("Range: [0/0] -> [0/0]", [range], "range");
|
||||
|
||||
iSearch.addString('1'); range = iSearch.addString('2');
|
||||
testRanges("Range: [0/3] -> [0/5]", [range], "range");
|
||||
},
|
||||
|
||||
"test: failing search keeps pos" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addString('1'); iSearch.addString('2');
|
||||
var range = iSearch.addString('x');
|
||||
testRanges("", [range], "range");
|
||||
assert.position(editor.getCursorPosition(), 0, 5);
|
||||
},
|
||||
|
||||
"test: backwards search" : function() {
|
||||
editor.moveCursorTo(1,0);
|
||||
iSearch.activate(editor, true);
|
||||
iSearch.addString('1'); var range = iSearch.addString('2');;
|
||||
testRanges("Range: [0/5] -> [0/3]", [range], "range");
|
||||
assert.position(editor.getCursorPosition(), 0, 3);
|
||||
},
|
||||
|
||||
"test: forwards then backwards, same result, reoriented range" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addString('1'); var range = iSearch.addString('2');;
|
||||
testRanges("Range: [0/3] -> [0/5]", [range], "range");
|
||||
assert.position(editor.getCursorPosition(), 0, 5);
|
||||
|
||||
range = iSearch.next({backwards: true});
|
||||
testRanges("Range: [0/5] -> [0/3]", [range], "range");
|
||||
assert.position(editor.getCursorPosition(), 0, 3);
|
||||
},
|
||||
|
||||
"test: reuse prev search via option" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addString('1'); iSearch.addString('2');;
|
||||
assert.position(editor.getCursorPosition(), 0, 5);
|
||||
iSearch.deactivate();
|
||||
|
||||
iSearch.activate(editor);
|
||||
iSearch.next({backwards: false, useCurrentOrPrevSearch: true});
|
||||
assert.position(editor.getCursorPosition(), 1, 5);
|
||||
},
|
||||
|
||||
"test: don't extend selection range if selection is empty" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addString('1'); iSearch.addString('2');;
|
||||
testRanges("Range: [0/5] -> [0/5]", [editor.getSelectionRange()], "sel range");
|
||||
},
|
||||
|
||||
"test: extend selection range if selection exists" : function() {
|
||||
iSearch.activate(editor);
|
||||
editor.selection.selectTo(0, 1);
|
||||
iSearch.addString('1'); iSearch.addString('2');;
|
||||
testRanges("Range: [0/0] -> [0/5]", [editor.getSelectionRange()], "sel range");
|
||||
},
|
||||
|
||||
"test: extend selection in emacs mark mode" : function() {
|
||||
var emacs = require('./keyboard/emacs');
|
||||
editor.keyBinding.addKeyboardHandler(emacs.handler);
|
||||
emacs.handler.commands.setMark.exec(editor);
|
||||
iSearch.activate(editor);
|
||||
iSearch.addString('1'); iSearch.addString('2');
|
||||
testRanges("Range: [0/0] -> [0/5]", [editor.getSelectionRange()], "sel range");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -32,15 +32,18 @@ define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
require("../incremental_search");
|
||||
var iSearchCommandModule = require("../commands/incremental_search_commands");
|
||||
|
||||
var screenToTextBlockCoordinates = function(pageX, pageY) {
|
||||
|
||||
var screenToTextBlockCoordinates = function(x, y) {
|
||||
var canvasPos = this.scroller.getBoundingClientRect();
|
||||
|
||||
var col = Math.floor(
|
||||
(pageX + this.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft()) / this.characterWidth
|
||||
(x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth
|
||||
);
|
||||
var row = Math.floor(
|
||||
(pageY + this.scrollTop - canvasPos.top - dom.getPageScrollTop()) / this.lineHeight
|
||||
(y + this.scrollTop - canvasPos.top) / this.lineHeight
|
||||
);
|
||||
|
||||
return this.session.screenToDocumentPosition(row, col);
|
||||
@@ -49,20 +52,26 @@ var screenToTextBlockCoordinates = function(pageX, pageY) {
|
||||
var HashHandler = require("./hash_handler").HashHandler;
|
||||
exports.handler = new HashHandler();
|
||||
|
||||
exports.handler.isEmacs = true;
|
||||
exports.handler.$id = "ace/keyboard/emacs";
|
||||
|
||||
var initialized = false;
|
||||
var $formerLongWords;
|
||||
var $formerLineStart;
|
||||
|
||||
exports.handler.attach = function(editor) {
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
dom.importCssString('\
|
||||
.emacs-mode .ace_cursor{\
|
||||
border: 2px rgba(50,250,50,0.8) solid!important;\
|
||||
border: 1px rgba(50,250,50,0.8) solid!important;\
|
||||
-moz-box-sizing: border-box!important;\
|
||||
-webkit-box-sizing: border-box!important;\
|
||||
box-sizing: border-box!important;\
|
||||
background-color: rgba(0,250,0,0.9);\
|
||||
opacity: 0.5;\
|
||||
}\
|
||||
.emacs-mode .ace_cursor.ace_hidden{\
|
||||
.emacs-mode .ace_hidden-cursors .ace_cursor{\
|
||||
opacity: 1;\
|
||||
background-color: transparent;\
|
||||
}\
|
||||
@@ -79,110 +88,268 @@ exports.handler.attach = function(editor) {
|
||||
}', 'emacsMode'
|
||||
);
|
||||
}
|
||||
// in emacs, gotowordleft/right should not count a space as a word..
|
||||
$formerLongWords = editor.session.$selectLongWords;
|
||||
editor.session.$selectLongWords = true;
|
||||
// CTRL-A should go to actual beginning of line
|
||||
$formerLineStart = editor.session.$useEmacsStyleLineStart;
|
||||
editor.session.$useEmacsStyleLineStart = true;
|
||||
|
||||
editor.session.$emacsMark = null; // the active mark
|
||||
editor.session.$emacsMarkRing = editor.session.$emacsMarkRing || [];
|
||||
|
||||
editor.emacsMark = function() {
|
||||
return this.session.$emacsMark;
|
||||
};
|
||||
|
||||
editor.setEmacsMark = function(p) {
|
||||
// to deactivate pass in a falsy value
|
||||
this.session.$emacsMark = p;
|
||||
};
|
||||
|
||||
editor.pushEmacsMark = function(p, activate) {
|
||||
var prevMark = this.session.$emacsMark;
|
||||
if (prevMark)
|
||||
this.session.$emacsMarkRing.push(prevMark);
|
||||
if (!p || activate) this.setEmacsMark(p);
|
||||
else this.session.$emacsMarkRing.push(p);
|
||||
};
|
||||
|
||||
editor.popEmacsMark = function() {
|
||||
var mark = this.emacsMark();
|
||||
if (mark) { this.setEmacsMark(null); return mark; }
|
||||
return this.session.$emacsMarkRing.pop();
|
||||
};
|
||||
|
||||
editor.getLastEmacsMark = function(p) {
|
||||
return this.session.$emacsMark || this.session.$emacsMarkRing.slice(-1)[0];
|
||||
};
|
||||
|
||||
editor.emacsMarkForSelection = function(replacement) {
|
||||
// find the mark in $emacsMarkRing corresponding to the current
|
||||
// selection
|
||||
var sel = this.selection,
|
||||
multiRangeLength = this.multiSelect ?
|
||||
this.multiSelect.getAllRanges().length : 1,
|
||||
selIndex = sel.index || 0,
|
||||
markRing = this.session.$emacsMarkRing,
|
||||
markIndex = markRing.length - (multiRangeLength - selIndex),
|
||||
lastMark = markRing[markIndex] || sel.anchor;
|
||||
if (replacement) {
|
||||
markRing.splice(markIndex, 1,
|
||||
"row" in replacement && "column" in replacement ?
|
||||
replacement : undefined);
|
||||
}
|
||||
return lastMark;
|
||||
}
|
||||
|
||||
editor.on("click", $resetMarkMode);
|
||||
editor.on("changeSession", $kbSessionChange);
|
||||
editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates;
|
||||
editor.setStyle("emacs-mode");
|
||||
editor.commands.addCommands(commands);
|
||||
exports.handler.platform = editor.commands.platform;
|
||||
editor.$emacsModeHandler = this;
|
||||
editor.addEventListener('copy', this.onCopy);
|
||||
editor.addEventListener('paste', this.onPaste);
|
||||
};
|
||||
|
||||
exports.handler.detach = function(editor) {
|
||||
delete editor.renderer.screenToTextCoordinates;
|
||||
editor.session.$selectLongWords = $formerLongWords;
|
||||
editor.session.$useEmacsStyleLineStart = $formerLineStart;
|
||||
editor.removeEventListener("click", $resetMarkMode);
|
||||
editor.removeEventListener("changeSession", $kbSessionChange);
|
||||
editor.unsetStyle("emacs-mode");
|
||||
editor.commands.removeCommands(commands);
|
||||
editor.removeEventListener('copy', this.onCopy);
|
||||
editor.removeEventListener('paste', this.onPaste);
|
||||
editor.$emacsModeHandler = null;
|
||||
};
|
||||
|
||||
var $kbSessionChange = function(e) {
|
||||
if (e.oldSession) {
|
||||
e.oldSession.$selectLongWords = $formerLongWords;
|
||||
e.oldSession.$useEmacsStyleLineStart = $formerLineStart;
|
||||
}
|
||||
|
||||
$formerLongWords = e.session.$selectLongWords;
|
||||
e.session.$selectLongWords = true;
|
||||
$formerLineStart = e.session.$useEmacsStyleLineStart;
|
||||
e.session.$useEmacsStyleLineStart = true;
|
||||
|
||||
if (!e.session.hasOwnProperty('$emacsMark'))
|
||||
e.session.$emacsMark = null;
|
||||
if (!e.session.hasOwnProperty('$emacsMarkRing'))
|
||||
e.session.$emacsMarkRing = [];
|
||||
};
|
||||
|
||||
var $resetMarkMode = function(e) {
|
||||
e.editor.session.$emacsMark = null;
|
||||
};
|
||||
|
||||
var keys = require("../lib/keys").KEY_MODS;
|
||||
var eMods = {
|
||||
C: "ctrl", S: "shift", M: "alt"
|
||||
};
|
||||
["S-C-M", "S-C", "S-M", "C-M", "S", "C", "M"].forEach(function(c) {
|
||||
var eMods = {C: "ctrl", S: "shift", M: "alt", CMD: "command"};
|
||||
var combinations = ["C-S-M-CMD",
|
||||
"S-M-CMD", "C-M-CMD", "C-S-CMD", "C-S-M",
|
||||
"M-CMD", "S-CMD", "S-M", "C-CMD", "C-M", "C-S",
|
||||
"CMD", "M", "S", "C"];
|
||||
combinations.forEach(function(c) {
|
||||
var hashId = 0;
|
||||
c.split("-").forEach(function(c){
|
||||
c.split("-").forEach(function(c) {
|
||||
hashId = hashId | keys[eMods[c]];
|
||||
});
|
||||
eMods[hashId] = c.toLowerCase() + "-";
|
||||
});
|
||||
|
||||
exports.handler.onCopy = function(e, editor) {
|
||||
if (editor.$handlesEmacsOnCopy) return;
|
||||
editor.$handlesEmacsOnCopy = true;
|
||||
exports.handler.commands.killRingSave.exec(editor);
|
||||
editor.$handlesEmacsOnCopy = false;
|
||||
};
|
||||
|
||||
exports.handler.onPaste = function(e, editor) {
|
||||
editor.pushEmacsMark(editor.getCursorPosition());
|
||||
};
|
||||
|
||||
exports.handler.bindKey = function(key, command) {
|
||||
if (typeof key == "object")
|
||||
key = key[this.platform];
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
var ckb = this.commmandKeyBinding;
|
||||
var ckb = this.commandKeyBinding;
|
||||
key.split("|").forEach(function(keyPart) {
|
||||
keyPart = keyPart.toLowerCase();
|
||||
ckb[keyPart] = command;
|
||||
keyPart = keyPart.split(" ")[0];
|
||||
if (!ckb[keyPart])
|
||||
ckb[keyPart] = "null";
|
||||
// register all partial key combos as null commands
|
||||
// to be able to activate key combos with arbitrary length
|
||||
// Example: if keyPart is "C-c C-l t" then "C-c C-l t" will
|
||||
// get command assigned and "C-c" and "C-c C-l" will get
|
||||
// a null command assigned in this.commandKeyBinding. For
|
||||
// the lookup logic see handleKeyboard()
|
||||
var keyParts = keyPart.split(" ").slice(0,-1);
|
||||
keyParts.reduce(function(keyMapKeys, keyPart, i) {
|
||||
var prefix = keyMapKeys[i-1] ? keyMapKeys[i-1] + ' ' : '';
|
||||
return keyMapKeys.concat([prefix + keyPart]);
|
||||
}, []).forEach(function(keyPart) {
|
||||
if (!ckb[keyPart]) ckb[keyPart] = "null";
|
||||
});
|
||||
}, this);
|
||||
};
|
||||
|
||||
exports.handler.getStatusText = function(editor, data) {
|
||||
var str = "";
|
||||
if (data.count)
|
||||
str += data.count;
|
||||
if (data.keyChain)
|
||||
str += " " + data.keyChain
|
||||
return str;
|
||||
};
|
||||
|
||||
exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {
|
||||
// if keyCode == -1 a non-printable key was pressed, such as just
|
||||
// control. Handling those is currently not supported in this handler
|
||||
if (keyCode === -1) return undefined;
|
||||
|
||||
var editor = data.editor;
|
||||
editor._signal("changeStatus");
|
||||
// insertstring data.count times
|
||||
if (hashId == -1) {
|
||||
editor.pushEmacsMark();
|
||||
if (data.count) {
|
||||
var str = Array(data.count + 1).join(key);
|
||||
var str = new Array(data.count + 1).join(key);
|
||||
data.count = null;
|
||||
return {command: "insertstring", args: str};
|
||||
}
|
||||
}
|
||||
|
||||
if (key == "\x00")
|
||||
return;
|
||||
|
||||
var modifier = eMods[hashId];
|
||||
if (modifier == "c-" || data.universalArgument) {
|
||||
|
||||
// CTRL + number / universalArgument for setting data.count
|
||||
if (modifier == "c-" || data.count) {
|
||||
var count = parseInt(key[key.length - 1]);
|
||||
if (count) {
|
||||
data.count = count;
|
||||
if (typeof count === 'number' && !isNaN(count)) {
|
||||
data.count = Math.max(data.count, 0) || 0;
|
||||
data.count = 10 * data.count + count;
|
||||
return {command: "null"};
|
||||
}
|
||||
}
|
||||
data.universalArgument = false;
|
||||
|
||||
if (modifier)
|
||||
key = modifier + key;
|
||||
// this.commandKeyBinding maps key specs like "c-p" (for CTRL + P) to
|
||||
// command objects, for lookup key needs to include the modifier
|
||||
if (modifier) key = modifier + key;
|
||||
|
||||
if (data.keyChain)
|
||||
key = data.keyChain += " " + key;
|
||||
// Key combos like CTRL+X H build up the data.keyChain
|
||||
if (data.keyChain) key = data.keyChain += " " + key;
|
||||
|
||||
var command = this.commmandKeyBinding[key];
|
||||
// Key combo prefixes get stored as "null" (String!) in this
|
||||
// this.commandKeyBinding. When encountered no command is invoked but we
|
||||
// buld up data.keyChain
|
||||
var command = this.commandKeyBinding[key];
|
||||
data.keyChain = command == "null" ? key : "";
|
||||
|
||||
if (!command)
|
||||
return;
|
||||
// there really is no command
|
||||
if (!command) return undefined;
|
||||
|
||||
if (command == "null")
|
||||
return {command: "null"};
|
||||
// we pass b/c of key combo or universalArgument
|
||||
if (command === "null") return {command: "null"};
|
||||
|
||||
if (command == "universalArgument") {
|
||||
data.universalArgument = true;
|
||||
if (command === "universalArgument") {
|
||||
// if no number pressed emacs repeats action 4 times.
|
||||
// minus sign is needed to allow next keypress to replace it
|
||||
data.count = -4;
|
||||
return {command: "null"};
|
||||
}
|
||||
|
||||
if (typeof command != "string") {
|
||||
var args = command.args;
|
||||
command = command.command;
|
||||
// lookup command
|
||||
// TODO extract special handling of markmode
|
||||
// TODO special case command.command is really unnecessary, remove
|
||||
var args;
|
||||
if (typeof command !== "string") {
|
||||
args = command.args;
|
||||
if (command.command) command = command.command;
|
||||
if (command === "goorselect") {
|
||||
command = editor.emacsMark() ? args[1] : args[0];
|
||||
args = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof command == "string") {
|
||||
command = this.commands[command] || data.editor.commands.commands[command];
|
||||
if (typeof command === "string") {
|
||||
if (command === "insertstring" ||
|
||||
command === "splitline" ||
|
||||
command === "togglecomment") {
|
||||
editor.pushEmacsMark();
|
||||
}
|
||||
command = this.commands[command] || editor.commands.commands[command];
|
||||
if (!command) return undefined;
|
||||
}
|
||||
|
||||
if (!command.readonly && !command.isYank)
|
||||
if (!command.readOnly && !command.isYank)
|
||||
data.lastCommand = null;
|
||||
|
||||
if (!command.readOnly && editor.emacsMark())
|
||||
editor.setEmacsMark(null)
|
||||
|
||||
if (data.count) {
|
||||
var count = data.count;
|
||||
data.count = 0;
|
||||
if (!command || !command.handlesCount) {
|
||||
return {
|
||||
args: args,
|
||||
command: {
|
||||
exec: function(editor, args) {
|
||||
for (var i = 0; i < count; i++)
|
||||
command.exec(editor, args);
|
||||
}
|
||||
},
|
||||
multiSelectAction: command.multiSelectAction
|
||||
}
|
||||
};
|
||||
} else {
|
||||
if (!args) args = {};
|
||||
if (typeof args === 'object') args.count = count;
|
||||
}
|
||||
}
|
||||
|
||||
return {command: command, args: args};
|
||||
@@ -190,16 +357,16 @@ exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {
|
||||
|
||||
exports.emacsKeys = {
|
||||
// movement
|
||||
"Up|C-p" : "golineup",
|
||||
"Down|C-n" : "golinedown",
|
||||
"Left|C-b" : "gotoleft",
|
||||
"Right|C-f" : "gotoright",
|
||||
"C-Left|M-b" : "gotowordleft",
|
||||
"C-Right|M-f" : "gotowordright",
|
||||
"Home|C-a" : "gotolinestart",
|
||||
"End|C-e" : "gotolineend",
|
||||
"C-Home|S-M-,": "gotostart",
|
||||
"C-End|S-M-." : "gotoend",
|
||||
"Up|C-p" : {command: "goorselect", args: ["golineup","selectup"]},
|
||||
"Down|C-n" : {command: "goorselect", args: ["golinedown","selectdown"]},
|
||||
"Left|C-b" : {command: "goorselect", args: ["gotoleft","selectleft"]},
|
||||
"Right|C-f" : {command: "goorselect", args: ["gotoright","selectright"]},
|
||||
"C-Left|M-b" : {command: "goorselect", args: ["gotowordleft","selectwordleft"]},
|
||||
"C-Right|M-f" : {command: "goorselect", args: ["gotowordright","selectwordright"]},
|
||||
"Home|C-a" : {command: "goorselect", args: ["gotolinestart","selecttolinestart"]},
|
||||
"End|C-e" : {command: "goorselect", args: ["gotolineend","selecttolineend"]},
|
||||
"C-Home|S-M-,": {command: "goorselect", args: ["gotostart","selecttostart"]},
|
||||
"C-End|S-M-." : {command: "goorselect", args: ["gotoend","selecttoend"]},
|
||||
|
||||
// selection
|
||||
"S-Up|S-C-p" : "selectup",
|
||||
@@ -219,14 +386,16 @@ exports.emacsKeys = {
|
||||
"C-x C-p": "selectall",
|
||||
|
||||
// todo fix these
|
||||
"C-Down": "gotopagedown",
|
||||
"C-Up": "gotopageup",
|
||||
"PageDown|C-v": "gotopagedown",
|
||||
"PageUp|M-v": "gotopageup",
|
||||
"C-Down": {command: "goorselect", args: ["gotopagedown","selectpagedown"]},
|
||||
"C-Up": {command: "goorselect", args: ["gotopageup","selectpageup"]},
|
||||
"PageDown|C-v": {command: "goorselect", args: ["gotopagedown","selectpagedown"]},
|
||||
"PageUp|M-v": {command: "goorselect", args: ["gotopageup","selectpageup"]},
|
||||
"S-C-Down": "selectpagedown",
|
||||
"S-C-Up": "selectpageup",
|
||||
"C-s": "findnext",
|
||||
"C-r": "findprevious",
|
||||
|
||||
"C-s": "iSearch",
|
||||
"C-r": "iSearchBackwards",
|
||||
|
||||
"M-C-s": "findnext",
|
||||
"M-C-r": "findprevious",
|
||||
"S-M-5": "replace",
|
||||
@@ -245,27 +414,26 @@ exports.emacsKeys = {
|
||||
"M-y": "yankRotate",
|
||||
"C-g": "keyboardQuit",
|
||||
|
||||
"C-w": "killRegion",
|
||||
"C-w|C-S-W": "killRegion",
|
||||
"M-w": "killRingSave",
|
||||
|
||||
"C-Space": "setMark",
|
||||
"C-x C-x": "exchangePointAndMark",
|
||||
|
||||
"C-t": "transposeletters",
|
||||
|
||||
"M-u": "touppercase",
|
||||
"M-u": "touppercase", // Doesn't work
|
||||
"M-l": "tolowercase",
|
||||
"M-/": "autocomplete",
|
||||
"M-/": "autocomplete", // Doesn't work
|
||||
"C-u": "universalArgument",
|
||||
|
||||
"M-;": "togglecomment",
|
||||
|
||||
"C-/|C-x u|S-C--|C-z": "undo",
|
||||
"S-C-/|S-C-x u|C--|S-C-z": "redo", //infinite undo?
|
||||
// vertical editing
|
||||
"C-x r": "selectRectangularRegion"
|
||||
|
||||
"C-x r": "selectRectangularRegion",
|
||||
"M-x": {command: "focusCommandLine", args: "M-x "}
|
||||
// todo
|
||||
// "M-x" "C-x C-t" "M-t" "M-c" "F11" "C-M- "M-q"
|
||||
// "C-x C-t" "M-t" "M-c" "F11" "C-M- "M-q"
|
||||
};
|
||||
|
||||
|
||||
@@ -289,15 +457,74 @@ exports.handler.addCommands({
|
||||
selectRectangularRegion: function(editor) {
|
||||
editor.multiSelect.toggleBlockSelection();
|
||||
},
|
||||
setMark: function() {
|
||||
setMark: {
|
||||
exec: function(editor, args) {
|
||||
// Sets mark-mode and clears current selection.
|
||||
// When mark is set, keyboard cursor movement commands become
|
||||
// selection modification commands. That is,
|
||||
// "goto" commands become "select" commands.
|
||||
// Any insertion or mouse click resets mark-mode.
|
||||
// setMark twice in a row at the same place resets markmode.
|
||||
// in multi select mode, ea selection is handled individually
|
||||
|
||||
if (args && args.count) {
|
||||
if (editor.inMultiSelectMode) editor.forEachSelection(moveToMark);
|
||||
else moveToMark();
|
||||
moveToMark();
|
||||
return;
|
||||
}
|
||||
|
||||
var mark = editor.emacsMark(),
|
||||
ranges = editor.selection.getAllRanges(),
|
||||
rangePositions = ranges.map(function(r) { return {row: r.start.row, column: r.start.column}; }),
|
||||
transientMarkModeActive = true,
|
||||
hasNoSelection = ranges.every(function(range) { return range.isEmpty(); });
|
||||
// if transientMarkModeActive then mark behavior is a little
|
||||
// different. Deactivate the mark when setMark is run with active
|
||||
// mark
|
||||
if (transientMarkModeActive && (mark || !hasNoSelection)) {
|
||||
if (editor.inMultiSelectMode) editor.forEachSelection({exec: editor.clearSelection.bind(editor)})
|
||||
else editor.clearSelection();
|
||||
if (mark) editor.pushEmacsMark(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mark) {
|
||||
rangePositions.forEach(function(pos) { editor.pushEmacsMark(pos); });
|
||||
editor.setEmacsMark(rangePositions[rangePositions.length-1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
function moveToMark() {
|
||||
var mark = editor.popEmacsMark();
|
||||
mark && editor.moveCursorToPosition(mark);
|
||||
}
|
||||
|
||||
},
|
||||
readOnly: true,
|
||||
handlesCount: true
|
||||
},
|
||||
exchangePointAndMark: {
|
||||
exec: function(editor) {
|
||||
var range = editor.selection.getRange();
|
||||
editor.selection.setSelectionRange(range, !editor.selection.isBackwards());
|
||||
exec: function exchangePointAndMark$exec(editor, args) {
|
||||
var sel = editor.selection;
|
||||
if (!args.count && !sel.isEmpty()) { // just invert selection
|
||||
sel.setSelectionRange(sel.getRange(), !sel.isBackwards());
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.count) { // replace mark and point
|
||||
var pos = {row: sel.lead.row, column: sel.lead.column};
|
||||
sel.clearSelection();
|
||||
sel.moveCursorToPosition(editor.emacsMarkForSelection(pos));
|
||||
} else { // create selection to last mark
|
||||
sel.selectToPosition(editor.emacsMarkForSelection());
|
||||
}
|
||||
},
|
||||
readonly: true,
|
||||
multiselectAction: "forEach"
|
||||
readOnly: true,
|
||||
handlesCount: true,
|
||||
multiSelectAction: "forEach"
|
||||
},
|
||||
killWord: {
|
||||
exec: function(editor, dir) {
|
||||
@@ -314,10 +541,23 @@ exports.handler.addCommands({
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
},
|
||||
multiselectAction: "forEach"
|
||||
multiSelectAction: "forEach"
|
||||
},
|
||||
killLine: function(editor) {
|
||||
editor.pushEmacsMark(null);
|
||||
var pos = editor.getCursorPosition();
|
||||
if (pos.column === 0 &&
|
||||
editor.session.doc.getLine(pos.row).length === 0) {
|
||||
// If an already empty line is killed, remove
|
||||
// the line entirely
|
||||
editor.selection.selectLine();
|
||||
} else {
|
||||
// otherwise just remove from the current cursor position
|
||||
// to the end (but don't delete the selection if it's before
|
||||
// the cursor)
|
||||
editor.clearSelection();
|
||||
editor.selection.selectLineEnd();
|
||||
}
|
||||
var range = editor.getSelectionRange();
|
||||
var text = editor.session.getTextRange(range);
|
||||
exports.killRing.add(text);
|
||||
@@ -326,26 +566,63 @@ exports.handler.addCommands({
|
||||
editor.clearSelection();
|
||||
},
|
||||
yank: function(editor) {
|
||||
editor.onPaste(exports.killRing.get());
|
||||
editor.onPaste(exports.killRing.get() || '');
|
||||
editor.keyBinding.$data.lastCommand = "yank";
|
||||
},
|
||||
yankRotate: function(editor) {
|
||||
if (editor.keyBinding.$data.lastCommand != "yank")
|
||||
return;
|
||||
|
||||
editor.undo();
|
||||
editor.session.$emacsMarkRing.pop(); // also undo recording mark
|
||||
editor.onPaste(exports.killRing.rotate());
|
||||
editor.keyBinding.$data.lastCommand = "yank";
|
||||
},
|
||||
killRegion: function(editor) {
|
||||
killRegion: {
|
||||
exec: function(editor) {
|
||||
exports.killRing.add(editor.getCopyText());
|
||||
editor.commands.byName.cut.exec(editor);
|
||||
},
|
||||
killRingSave: function(editor) {
|
||||
readOnly: true,
|
||||
multiSelectAction: "forEach"
|
||||
},
|
||||
killRingSave: {
|
||||
exec: function(editor) {
|
||||
// copy text and deselect. will save marks for starts of the
|
||||
// selection(s)
|
||||
|
||||
editor.$handlesEmacsOnCopy = true;
|
||||
var marks = editor.session.$emacsMarkRing.slice(),
|
||||
deselectedMarks = [];
|
||||
exports.killRing.add(editor.getCopyText());
|
||||
|
||||
setTimeout(function() {
|
||||
function deselect() {
|
||||
var sel = editor.selection, range = sel.getRange(),
|
||||
pos = sel.isBackwards() ? range.end : range.start;
|
||||
deselectedMarks.push({row: pos.row, column: pos.column});
|
||||
sel.clearSelection();
|
||||
}
|
||||
editor.$handlesEmacsOnCopy = false;
|
||||
if (editor.inMultiSelectMode) editor.forEachSelection({exec: deselect});
|
||||
else deselect();
|
||||
editor.session.$emacsMarkRing = marks.concat(deselectedMarks.reverse());
|
||||
}, 0);
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
keyboardQuit: function(editor) {
|
||||
editor.selection.clearSelection();
|
||||
editor.setEmacsMark(null);
|
||||
editor.keyBinding.$data.count = null;
|
||||
},
|
||||
focusCommandLine: function(editor, arg) {
|
||||
if (editor.showCommandLine)
|
||||
editor.showCommandLine(arg);
|
||||
}
|
||||
});
|
||||
|
||||
exports.handler.addCommands(iSearchCommandModule.iSearchStartCommands);
|
||||
|
||||
var commands = exports.handler.commands;
|
||||
commands.yank.isYank = true;
|
||||
commands.yankRotate.isYank = true;
|
||||
@@ -357,8 +634,9 @@ exports.killRing = {
|
||||
if (this.$data.length > 30)
|
||||
this.$data.shift();
|
||||
},
|
||||
get: function() {
|
||||
return this.$data[this.$data.length - 1] || "";
|
||||
get: function(n) {
|
||||
n = n || 1;
|
||||
return this.$data.slice(this.$data.length-n, this.$data.length).reverse().join('\n');
|
||||
},
|
||||
pop: function() {
|
||||
if (this.$data.length > 1)
|
||||
@@ -371,5 +649,4 @@ exports.killRing = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
require("../multi_select");
|
||||
|
||||
var EditSession = require("./../edit_session").EditSession,
|
||||
Editor = require("./../editor").Editor,
|
||||
Range = require("./../range").Range,
|
||||
MockRenderer = require("./../test/mockrenderer").MockRenderer,
|
||||
emacs = require('./emacs'),
|
||||
assert = require("./../test/assertions"),
|
||||
editor, sel;
|
||||
|
||||
function initEditor(docString) {
|
||||
var doc = new EditSession(docString.split("\n"));
|
||||
editor = new Editor(new MockRenderer(), doc);
|
||||
editor.setKeyboardHandler(emacs.handler);
|
||||
sel = editor.selection;
|
||||
}
|
||||
|
||||
function print(obj) {
|
||||
return JSON.stringify(obj, null, 2);
|
||||
}
|
||||
|
||||
function pluck(arr, what) {
|
||||
return arr.map(function(ea) { return ea[what]; });
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test: detach removes emacs commands from command manager": function() {
|
||||
initEditor('');
|
||||
assert.ok(!!editor.commands.byName["keyboardQuit"], 'setup error: emacs commands not installed');
|
||||
editor.keyBinding.removeKeyboardHandler(editor.getKeyboardHandler());
|
||||
assert.ok(!editor.commands.byName["keyboardQuit"], 'emacs commands not removed');
|
||||
},
|
||||
|
||||
"test: keyboardQuit clears selection": function() {
|
||||
initEditor('foo');
|
||||
editor.selectAll();
|
||||
editor.execCommand('keyboardQuit');
|
||||
assert.ok(editor.selection.isEmpty(), 'selection non-empty');
|
||||
},
|
||||
|
||||
"test: exchangePointAndMark without mark set": function() {
|
||||
initEditor('foo');
|
||||
sel.setRange(Range.fromPoints({row: 0, column: 1}, {row: 0, column: 3}));
|
||||
editor.execCommand('exchangePointAndMark');
|
||||
assert.deepEqual({row: 0, column: 1}, editor.getCursorPosition(), print(editor.getCursorPosition()));
|
||||
},
|
||||
|
||||
"test: exchangePointAndMark with mark set": function() {
|
||||
initEditor('foo');
|
||||
editor.pushEmacsMark({row: 0, column: 1});
|
||||
editor.pushEmacsMark({row: 0, column: 2});
|
||||
editor.execCommand('exchangePointAndMark', {count: 4});
|
||||
assert.deepEqual({row: 0, column: 2}, editor.getCursorPosition(), print(editor.getCursorPosition()));
|
||||
assert.deepEqual([{row: 0, column: 1}, {row: 0, column: 0}], editor.session.$emacsMarkRing, print(editor.session.$emacsMarkRing));
|
||||
},
|
||||
|
||||
"test: exchangePointAndMark with selection": function() {
|
||||
initEditor('foo');
|
||||
editor.pushEmacsMark({row: 0, column: 1});
|
||||
editor.pushEmacsMark({row: 0, column: 2});
|
||||
sel.setRange(Range.fromPoints({row: 0, column: 0}, {row: 0, column: 1}), true);
|
||||
editor.execCommand('exchangePointAndMark');
|
||||
assert.deepEqual({row: 0, column: 1}, editor.getCursorPosition(), print(editor.getCursorPosition()));
|
||||
assert.deepEqual([{row: 0, column: 1}, {row: 0, column: 2}], editor.session.$emacsMarkRing, print(editor.session.$emacsMarkRing));
|
||||
},
|
||||
|
||||
"test: exchangePointAndMark with multi selection": function() {
|
||||
initEditor('foo\nhello world\n123');
|
||||
var ranges = [[{row: 0, column: 0}, {row: 0, column: 3}],
|
||||
[{row: 1, column: 0}, {row: 1, column: 5}],
|
||||
[{row: 1, column: 6}, {row: 1, column: 11}]]
|
||||
ranges.forEach(function(r) {
|
||||
sel.addRange(Range.fromPoints(r[0], r[1]));
|
||||
});
|
||||
assert.equal("foo\nhello\nworld", editor.getSelectedText());
|
||||
editor.execCommand('exchangePointAndMark');
|
||||
assert.equal("foo\nhello\nworld", editor.getSelectedText());
|
||||
assert.deepEqual(pluck(ranges, 0), pluck(sel.getAllRanges(), 'cursor'), "selections dir not inverted");
|
||||
},
|
||||
|
||||
"test: exchangePointAndMark with multi cursors": function() {
|
||||
initEditor('foo\nhello world\n123');
|
||||
var ranges = [[{row: 0, column: 0}, {row: 0, column: 3}],
|
||||
[{row: 1, column: 0}, {row: 1, column: 5}],
|
||||
[{row: 1, column: 6}, {row: 1, column: 11}]];
|
||||
// move cursors to the start of each range and set a mark to its end
|
||||
// without selecting anything
|
||||
ranges.forEach(function(r) {
|
||||
editor.pushEmacsMark(r[1]);
|
||||
sel.addRange(Range.fromPoints(r[0], r[0]));
|
||||
});
|
||||
assert.deepEqual(pluck(ranges, 0), pluck(sel.getAllRanges(), 'cursor'), print(sel.getAllRanges()));
|
||||
editor.execCommand('exchangePointAndMark');
|
||||
assert.deepEqual(pluck(ranges, 1), pluck(sel.getAllRanges(), 'cursor'), "not inverted: " + print(sel.getAllRanges()));
|
||||
},
|
||||
|
||||
"test: setMark with multi cursors": function() {
|
||||
initEditor('foo\nhello world\n123');
|
||||
var positions = [{row: 0, column: 0},
|
||||
{row: 1, column: 0},
|
||||
{row: 1, column: 6}];
|
||||
positions.forEach(function(p) { sel.addRange(Range.fromPoints(p,p)); });
|
||||
editor.execCommand('setMark');
|
||||
assert.deepEqual(positions, editor.session.$emacsMarkRing, print(editor.session.$emacsMarkRing));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -32,17 +32,27 @@ define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keyUtil = require("../lib/keys");
|
||||
var useragent = require("../lib/useragent");
|
||||
var KEY_MODS = keyUtil.KEY_MODS;
|
||||
|
||||
function HashHandler(config, platform) {
|
||||
this.platform = platform;
|
||||
this.platform = platform || (useragent.isMac ? "mac" : "win");
|
||||
this.commands = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
this.commandKeyBinding = {};
|
||||
this.addCommands(config);
|
||||
};
|
||||
this.$singleCommand = true;
|
||||
}
|
||||
|
||||
function MultiHashHandler(config, platform) {
|
||||
HashHandler.call(this, config, platform);
|
||||
this.$singleCommand = false;
|
||||
}
|
||||
|
||||
MultiHashHandler.prototype = HashHandler.prototype;
|
||||
|
||||
(function() {
|
||||
|
||||
|
||||
this.addCommand = function(command) {
|
||||
if (this.commands[command.name])
|
||||
this.removeCommand(command);
|
||||
@@ -53,47 +63,92 @@ function HashHandler(config, platform) {
|
||||
this._buildKeyHash(command);
|
||||
};
|
||||
|
||||
this.removeCommand = function(command) {
|
||||
var name = (typeof command === 'string' ? command : command.name);
|
||||
this.removeCommand = function(command, keepCommand) {
|
||||
var name = command && (typeof command === 'string' ? command : command.name);
|
||||
command = this.commands[name];
|
||||
if (!keepCommand)
|
||||
delete this.commands[name];
|
||||
|
||||
// exhaustive search is brute force but since removeCommand is
|
||||
// not a performance critical operation this should be OK
|
||||
var ckb = this.commmandKeyBinding;
|
||||
for (var hashId in ckb) {
|
||||
for (var key in ckb[hashId]) {
|
||||
if (ckb[hashId][key] == command)
|
||||
delete ckb[hashId][key];
|
||||
var ckb = this.commandKeyBinding;
|
||||
for (var keyId in ckb) {
|
||||
var cmdGroup = ckb[keyId];
|
||||
if (cmdGroup == command) {
|
||||
delete ckb[keyId];
|
||||
} else if (Array.isArray(cmdGroup)) {
|
||||
var i = cmdGroup.indexOf(command);
|
||||
if (i != -1) {
|
||||
cmdGroup.splice(i, 1);
|
||||
if (cmdGroup.length == 1)
|
||||
ckb[keyId] = cmdGroup[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.bindKey = function(key, command) {
|
||||
if(!key)
|
||||
return;
|
||||
if (typeof command == "function") {
|
||||
this.addCommand({exec: command, bindKey: key, name: key});
|
||||
this.bindKey = function(key, command, asDefault) {
|
||||
if (typeof key == "object")
|
||||
key = key[this.platform];
|
||||
if (!key)
|
||||
return;
|
||||
if (typeof command == "function")
|
||||
return this.addCommand({exec: command, bindKey: key, name: command.name || key});
|
||||
|
||||
key.split("|").forEach(function(keyPart) {
|
||||
var chain = "";
|
||||
if (keyPart.indexOf(" ") != -1) {
|
||||
var parts = keyPart.split(/\s+/);
|
||||
keyPart = parts.pop();
|
||||
parts.forEach(function(keyPart) {
|
||||
var binding = this.parseKeys(keyPart);
|
||||
var id = KEY_MODS[binding.hashId] + binding.key;
|
||||
chain += (chain ? " " : "") + id;
|
||||
this._addCommandToBinding(chain, "chainKeys");
|
||||
}, this);
|
||||
chain += " ";
|
||||
}
|
||||
var binding = this.parseKeys(keyPart);
|
||||
var id = KEY_MODS[binding.hashId] + binding.key;
|
||||
this._addCommandToBinding(chain + id, command, asDefault);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this._addCommandToBinding = function(keyId, command, asDefault) {
|
||||
var ckb = this.commandKeyBinding, i;
|
||||
if (!command) {
|
||||
delete ckb[keyId];
|
||||
} else if (!ckb[keyId] || this.$singleCommand) {
|
||||
ckb[keyId] = command;
|
||||
} else {
|
||||
if (!Array.isArray(ckb[keyId])) {
|
||||
ckb[keyId] = [ckb[keyId]];
|
||||
} else if ((i = ckb[keyId].indexOf(command)) != -1) {
|
||||
ckb[keyId].splice(i, 1);
|
||||
}
|
||||
|
||||
var ckb = this.commmandKeyBinding;
|
||||
key.split("|").forEach(function(keyPart) {
|
||||
var binding = this.parseKeys(keyPart, command);
|
||||
var hashId = binding.hashId;
|
||||
(ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command;
|
||||
}, this);
|
||||
if (asDefault || command.isDefault)
|
||||
ckb[keyId].unshift(command);
|
||||
else
|
||||
ckb[keyId].push(command);
|
||||
}
|
||||
};
|
||||
|
||||
this.addCommands = function(commands) {
|
||||
commands && Object.keys(commands).forEach(function(name) {
|
||||
var command = commands[name];
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
if (typeof command === "string")
|
||||
return this.bindKey(command, name);
|
||||
|
||||
if (typeof command === "function")
|
||||
command = { exec: command };
|
||||
|
||||
if (typeof command !== "object")
|
||||
return;
|
||||
|
||||
if (!command.name)
|
||||
command.name = name;
|
||||
|
||||
@@ -114,12 +169,7 @@ function HashHandler(config, platform) {
|
||||
};
|
||||
|
||||
this._buildKeyHash = function(command) {
|
||||
var binding = command.bindKey;
|
||||
if (!binding)
|
||||
return;
|
||||
|
||||
var key = typeof binding == "string" ? binding: binding[this.platform];
|
||||
this.bindKey(key, command);
|
||||
this.bindKey(command.bindKey, command);
|
||||
};
|
||||
|
||||
// accepts keys in the form ctrl+Enter or ctrl-Enter
|
||||
@@ -139,25 +189,43 @@ function HashHandler(config, platform) {
|
||||
var hashId = 0;
|
||||
for (var i = parts.length; i--;) {
|
||||
var modifier = keyUtil.KEY_MODS[parts[i]];
|
||||
if (modifier == null)
|
||||
throw "invalid modifier " + parts[i] + " in " + keys;
|
||||
if (modifier == null) {
|
||||
if (typeof console != "undefined")
|
||||
console.error("invalid modifier " + parts[i] + " in " + keys);
|
||||
return false;
|
||||
}
|
||||
hashId |= modifier;
|
||||
}
|
||||
return {key: key, hashId: hashId};
|
||||
};
|
||||
|
||||
this.findKeyCommand = function findKeyCommand(hashId, keyString) {
|
||||
var ckbr = this.commmandKeyBinding;
|
||||
return ckbr[hashId] && ckbr[hashId][keyString];
|
||||
var key = KEY_MODS[hashId] + keyString;
|
||||
return this.commandKeyBinding[key];
|
||||
};
|
||||
|
||||
this.handleKeyboard = function(data, hashId, keyString, keyCode) {
|
||||
return {
|
||||
command: this.findKeyCommand(hashId, keyString)
|
||||
};
|
||||
var key = KEY_MODS[hashId] + keyString;
|
||||
var command = this.commandKeyBinding[key];
|
||||
if (data.$keyChain) {
|
||||
data.$keyChain += " " + key;
|
||||
command = this.commandKeyBinding[data.$keyChain] || command;
|
||||
}
|
||||
|
||||
if (command) {
|
||||
if (command == "chainKeys" || command[command.length - 1] == "chainKeys") {
|
||||
data.$keyChain = data.$keyChain || key;
|
||||
return {command: "null"};
|
||||
}
|
||||
}
|
||||
|
||||
if (data.$keyChain && keyCode > 0)
|
||||
data.$keyChain = "";
|
||||
return {command: command};
|
||||
};
|
||||
|
||||
}).call(HashHandler.prototype)
|
||||
}).call(HashHandler.prototype);
|
||||
|
||||
exports.HashHandler = HashHandler;
|
||||
exports.MultiHashHandler = MultiHashHandler;
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ var event = require("../lib/event");
|
||||
|
||||
var KeyBinding = function(editor) {
|
||||
this.$editor = editor;
|
||||
this.$data = { };
|
||||
this.$data = {editor: editor};
|
||||
this.$handlers = [];
|
||||
this.setDefaultHandler(editor.commands);
|
||||
};
|
||||
@@ -46,15 +46,15 @@ var KeyBinding = function(editor) {
|
||||
this.removeKeyboardHandler(this.$defaultHandler);
|
||||
this.$defaultHandler = kb;
|
||||
this.addKeyboardHandler(kb, 0);
|
||||
this.$data = {editor: this.$editor};
|
||||
};
|
||||
|
||||
this.setKeyboardHandler = function(kb) {
|
||||
if (this.$handlers[this.$handlers.length - 1] == kb)
|
||||
var h = this.$handlers;
|
||||
if (h[h.length - 1] == kb)
|
||||
return;
|
||||
|
||||
while (this.$handlers[1])
|
||||
this.removeKeyboardHandler(this.$handlers[1]);
|
||||
while (h[h.length - 1] && h[h.length - 1] != this.$defaultHandler)
|
||||
this.removeKeyboardHandler(h[h.length - 1]);
|
||||
|
||||
this.addKeyboardHandler(kb, 1);
|
||||
};
|
||||
@@ -62,6 +62,8 @@ var KeyBinding = function(editor) {
|
||||
this.addKeyboardHandler = function(kb, pos) {
|
||||
if (!kb)
|
||||
return;
|
||||
if (typeof kb == "function" && !kb.handleKeyboard)
|
||||
kb.handleKeyboard = kb;
|
||||
var i = this.$handlers.indexOf(kb);
|
||||
if (i != -1)
|
||||
this.$handlers.splice(i, 1);
|
||||
@@ -88,32 +90,41 @@ var KeyBinding = function(editor) {
|
||||
return this.$handlers[this.$handlers.length - 1];
|
||||
};
|
||||
|
||||
this.$callKeyboardHandlers = function (hashId, keyString, keyCode, e) {
|
||||
this.getStatusText = function() {
|
||||
var data = this.$data;
|
||||
var editor = data.editor;
|
||||
return this.$handlers.map(function(h) {
|
||||
return h.getStatusText && h.getStatusText(editor, data) || "";
|
||||
}).filter(Boolean).join(" ");
|
||||
};
|
||||
|
||||
this.$callKeyboardHandlers = function(hashId, keyString, keyCode, e) {
|
||||
var toExecute;
|
||||
var success = false;
|
||||
var commands = this.$editor.commands;
|
||||
|
||||
for (var i = this.$handlers.length; i--;) {
|
||||
toExecute = this.$handlers[i].handleKeyboard(
|
||||
this.$data, hashId, keyString, keyCode, e
|
||||
);
|
||||
if (toExecute && toExecute.command)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!toExecute || !toExecute.command)
|
||||
return false;
|
||||
|
||||
var success = false;
|
||||
var commands = this.$editor.commands;
|
||||
continue;
|
||||
|
||||
// allow keyboardHandler to consume keys
|
||||
if (toExecute.command != "null")
|
||||
if (toExecute.command == "null") {
|
||||
success = true;
|
||||
} else {
|
||||
success = commands.exec(toExecute.command, this.$editor, toExecute.args, e);
|
||||
else
|
||||
success = toExecute.passEvent != true;
|
||||
|
||||
}
|
||||
// do not stop input events to not break repeating
|
||||
if (success && e && hashId != -1)
|
||||
if (success && e && hashId != -1 &&
|
||||
toExecute.passEvent != true && toExecute.command.passEvent != true
|
||||
) {
|
||||
event.stopEvent(e);
|
||||
|
||||
}
|
||||
if (success)
|
||||
break;
|
||||
}
|
||||
return success;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./../edit_session").EditSession,
|
||||
Editor = require("./../editor").Editor,
|
||||
MockRenderer = require("./../test/mockrenderer").MockRenderer,
|
||||
assert = require("./../test/assertions"),
|
||||
HashHandler = require('./hash_handler').HashHandler,
|
||||
keys = require('../lib/keys'),
|
||||
editor;
|
||||
|
||||
function initEditor(docString) {
|
||||
var doc = new EditSession(docString.split("\n"));
|
||||
editor = new Editor(new MockRenderer(), doc);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test: adding a new keyboard handler does not remove the default handler": function() {
|
||||
initEditor('abc');
|
||||
var handler = new HashHandler({'del': 'f1'});
|
||||
editor.keyBinding.setKeyboardHandler(handler);
|
||||
editor.onCommandKey({}, 0, keys['f1']);
|
||||
assert.equal('bc', editor.getValue(), "binding of new handler");
|
||||
editor.onCommandKey({}, 0, keys['delete']);
|
||||
assert.equal('c', editor.getValue(), "bindings of the old handler should still work");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -223,8 +223,7 @@ StateHandler.prototype = {
|
||||
* This is a useful matching function and therefore is defined here so that
|
||||
* users of KeyboardStateMapper can use it.
|
||||
*
|
||||
* @return boolean
|
||||
* If no command key (Command|Option|Shift|Ctrl) is pressed, it
|
||||
* @return {Boolean} If no command key (Command|Option|Shift|Ctrl) is pressed, it
|
||||
* returns true. If the only the Shift key is pressed + a character
|
||||
* true is returned as well. Otherwise, false is returned.
|
||||
* Summing up, the function returns true whenever the user typed
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var HashHandler = require("./hash_handler").HashHandler;
|
||||
exports.handler = new HashHandler();
|
||||
|
||||
[{
|
||||
bindKey: "Shift-Tab|Tab",
|
||||
command: "passKeysToBrowser"
|
||||
}, {
|
||||
bindKey: {win: "Ctrl-L", mac: "Cmd-L"},
|
||||
command: "passKeysToBrowser"
|
||||
}, {
|
||||
bindKey: {win: "Ctrl-G", mac: "Cmd-G"},
|
||||
command: "gotoline"
|
||||
}, {
|
||||
bindKey: {win: "Ctrl-T|Ctrl-Shift-T", mac: "Cmd-T|Cmd-Shift-T"},
|
||||
command: "passKeysToBrowser"
|
||||
}, {
|
||||
bindKey: {win: "Ctrl-G", mac: "Cmd-G"},
|
||||
command: "passKeysToBrowser"
|
||||
}, {
|
||||
bindKey: {win: "Ctrl-G", mac: "Cmd-G"},
|
||||
command: "passKeysToBrowser"
|
||||
}, {
|
||||
name: "golineup",
|
||||
bindKey: {win: null, mac: "Ctrl-P"},
|
||||
}, {
|
||||
name: "golinedown",
|
||||
bindKey: {win: null, mac: "Ctrl-N"},
|
||||
}, {
|
||||
name: "gotoleft",
|
||||
bindKey: {win: null, mac: "Ctrl-B"},
|
||||
}, {
|
||||
name: "gotoright",
|
||||
bindKey: {win: null, mac: "Ctrl-F"},
|
||||
}, {
|
||||
name: "gotolineend",
|
||||
bindKey: {win: null, mac: "Ctrl-E"},
|
||||
}, {
|
||||
name: "gotolinestart",
|
||||
bindKey: {win: null, mac: "Ctrl-A"},
|
||||
}
|
||||
].forEach(function(k) {
|
||||
var bindKey = k.bindKey;
|
||||
if (typeof bindKey == "object")
|
||||
bindKey = bindKey[exports.handler.platform];
|
||||
exports.handler.bindKey(bindKey, k.command);
|
||||
});
|
||||
exports.handler.$id = "ace/keyboard/textarea";
|
||||
|
||||
});
|
||||
@@ -34,189 +34,253 @@ define(function(require, exports, module) {
|
||||
var event = require("../lib/event");
|
||||
var useragent = require("../lib/useragent");
|
||||
var dom = require("../lib/dom");
|
||||
var lang = require("../lib/lang");
|
||||
var BROKEN_SETDATA = useragent.isChrome < 18;
|
||||
var USE_IE_MIME_TYPE = useragent.isIE;
|
||||
|
||||
var TextInput = function(parentNode, host) {
|
||||
var text = dom.createElement("textarea");
|
||||
text.className = "ace_text-input";
|
||||
/*/ debug
|
||||
text.style.opacity = 1
|
||||
text.style.background = "rgba(0, 250, 0, 0.3)"
|
||||
text.style.outline = "rgba(0, 250, 0, 0.8) solid 1px"
|
||||
text.style.outlineOffset = "3px"
|
||||
/**/
|
||||
|
||||
if (useragent.isTouchPad)
|
||||
text.setAttribute("x-palm-disable-auto-cap", true);
|
||||
|
||||
text.wrap = "off";
|
||||
text.spellcheck = false;
|
||||
text.setAttribute("wrap", "off");
|
||||
text.setAttribute("autocorrect", "off");
|
||||
text.setAttribute("autocapitalize", "off");
|
||||
text.setAttribute("spellcheck", false);
|
||||
|
||||
text.style.top = "-2em";
|
||||
text.style.opacity = "0";
|
||||
if (useragent.isOldIE) text.style.top = "-100px";
|
||||
parentNode.insertBefore(text, parentNode.firstChild);
|
||||
|
||||
var PLACEHOLDER = useragent.isIE || useragent.isOpera ? "\x01\x01" : "\x00\x00";
|
||||
var PLACEHOLDER = "\x01\x01";
|
||||
|
||||
resetValue();
|
||||
|
||||
if (isFocused())
|
||||
host.onFocus();
|
||||
|
||||
// Somehow fixes problem with firing onpropertychange on first typed char
|
||||
if (useragent.isOldIE) {
|
||||
resetSelection();
|
||||
resetValue();
|
||||
setTimeout(resetSelection);
|
||||
}
|
||||
|
||||
var cut = false
|
||||
var copied = false;
|
||||
var pasted = false;
|
||||
|
||||
var inCompostion = false;
|
||||
|
||||
var resetTimeout = null;
|
||||
|
||||
var inComposition = false;
|
||||
var tempStyle = '';
|
||||
var isSelectionEmpty = true;
|
||||
|
||||
function resetValue() {
|
||||
text.value = PLACEHOLDER;
|
||||
//http://code.google.com/p/chromium/issues/detail?id=76516
|
||||
if (useragent.isWebKit && !resetTimeout)
|
||||
resetTimeout = setTimeout(function(){
|
||||
text.value = PLACEHOLDER;
|
||||
resetSelection();
|
||||
resetTimeout = null;
|
||||
// FOCUS
|
||||
// ie9 throws error if document.activeElement is accessed too soon
|
||||
try { var isFocused = document.activeElement === text; } catch(e) {}
|
||||
|
||||
event.addListener(text, "blur", function(e) {
|
||||
host.onBlur(e);
|
||||
isFocused = false;
|
||||
});
|
||||
event.addListener(text, "focus", function(e) {
|
||||
isFocused = true;
|
||||
host.onFocus(e);
|
||||
resetSelection();
|
||||
});
|
||||
this.focus = function() {
|
||||
text.style.position = "fixed";
|
||||
text.style.top = "-10000000px";
|
||||
text.focus();
|
||||
setTimeout(function() {
|
||||
text.style.position = "";
|
||||
}, 0);
|
||||
};
|
||||
this.blur = function() { text.blur(); };
|
||||
this.isFocused = function() {
|
||||
return isFocused;
|
||||
};
|
||||
|
||||
// modifying selection of blured textarea can focus it (chrome mac/linux)
|
||||
var syncSelection = lang.delayedCall(function() {
|
||||
isFocused && resetSelection(isSelectionEmpty);
|
||||
});
|
||||
var syncValue = lang.delayedCall(function() {
|
||||
if (!inComposition) {
|
||||
text.value = PLACEHOLDER;
|
||||
isFocused && resetSelection();
|
||||
}
|
||||
});
|
||||
|
||||
function resetSelection(isEmpty) {
|
||||
if (inComposition)
|
||||
return;
|
||||
|
||||
// this prevents infinite recursion on safari 8
|
||||
// see https://github.com/ajaxorg/ace/issues/2114
|
||||
inComposition = true;
|
||||
|
||||
if (inputHandler) {
|
||||
selectionStart = 0;
|
||||
selectionEnd = isEmpty ? 0 : text.value.length - 1;
|
||||
} else {
|
||||
var selectionStart = isEmpty ? 2 : 1;
|
||||
var selectionEnd = 2;
|
||||
}
|
||||
// on firefox this throws if textarea is hidden
|
||||
try {
|
||||
if (text.setSelectionRange) {
|
||||
text.setSelectionRange(selectionStart, selectionEnd);
|
||||
}
|
||||
// IE8 does not support setSelectionRange
|
||||
else if (text.createTextRange) {
|
||||
var range = text.createTextRange();
|
||||
range.collapse(true);
|
||||
range.moveEnd('character', selectionEnd);
|
||||
range.moveStart('character', selectionStart);
|
||||
range.select();
|
||||
}
|
||||
} catch(e){}
|
||||
|
||||
inComposition = false;
|
||||
}
|
||||
|
||||
function resetValue() {
|
||||
if (inComposition)
|
||||
return;
|
||||
text.value = PLACEHOLDER;
|
||||
//http://code.google.com/p/chromium/issues/detail?id=76516
|
||||
if (useragent.isWebKit)
|
||||
syncValue.schedule();
|
||||
}
|
||||
|
||||
useragent.isWebKit || host.addEventListener('changeSelection', function() {
|
||||
if (host.selection.isEmpty() != isSelectionEmpty) {
|
||||
isSelectionEmpty = !isSelectionEmpty;
|
||||
syncSelection.schedule();
|
||||
}
|
||||
});
|
||||
|
||||
resetValue();
|
||||
if (isFocused)
|
||||
host.onFocus();
|
||||
|
||||
|
||||
var isAllSelected = function(text) {
|
||||
return text.selectionStart === 0 && text.selectionEnd === text.value.length;
|
||||
};
|
||||
// IE8 does not support setSelectionRange
|
||||
if (!text.setSelectionRange && text.createTextRange) {
|
||||
text.setSelectionRange = function(selectionStart, selectionEnd) {
|
||||
var range = this.createTextRange();
|
||||
range.collapse(true);
|
||||
range.moveStart('character', selectionStart);
|
||||
range.moveEnd('character', selectionEnd);
|
||||
range.select();
|
||||
};
|
||||
isAllSelected = function(text) {
|
||||
try {
|
||||
var range = text.ownerDocument.selection.createRange();
|
||||
}catch(e) {}
|
||||
if (!range || range.parentElement() != text) return false;
|
||||
return range.text == text.value;
|
||||
}
|
||||
}
|
||||
if (useragent.isOldIE) {
|
||||
var inPropertyChange = false;
|
||||
var onPropertyChange = function(e){
|
||||
if (inPropertyChange)
|
||||
return;
|
||||
var data = text.value;
|
||||
if (inComposition || !data || data == PLACEHOLDER)
|
||||
return;
|
||||
// can happen either after delete or during insert operation
|
||||
if (e && data == PLACEHOLDER[0])
|
||||
return syncProperty.schedule();
|
||||
|
||||
sendText(data);
|
||||
// ie8 calls propertychange handlers synchronously!
|
||||
inPropertyChange = true;
|
||||
resetValue();
|
||||
inPropertyChange = false;
|
||||
};
|
||||
var syncProperty = lang.delayedCall(onPropertyChange);
|
||||
event.addListener(text, "propertychange", onPropertyChange);
|
||||
|
||||
var keytable = { 13:1, 27:1 };
|
||||
event.addListener(text, "keyup", function (e) {
|
||||
if (inComposition && (!text.value || keytable[e.keyCode]))
|
||||
setTimeout(onCompositionEnd, 0);
|
||||
if ((text.value.charCodeAt(0)||0) < 129) {
|
||||
return syncProperty.call();
|
||||
}
|
||||
inComposition ? onCompositionUpdate() : onCompositionStart();
|
||||
});
|
||||
// when user presses backspace after focusing the editor
|
||||
// propertychange isn't called for the next character
|
||||
event.addListener(text, "keydown", function (e) {
|
||||
syncProperty.schedule(50);
|
||||
});
|
||||
}
|
||||
|
||||
var onSelect = function(e) {
|
||||
if (cut) {
|
||||
cut = false;
|
||||
return;
|
||||
}
|
||||
if (copied) {
|
||||
copied = false;
|
||||
return;
|
||||
}
|
||||
if (text.selectionStart === 0 && text.selectionEnd === text.value.length) {
|
||||
} else if (isAllSelected(text)) {
|
||||
host.selectAll();
|
||||
resetSelection();
|
||||
} else if (inputHandler) {
|
||||
resetSelection(host.selection.isEmpty());
|
||||
}
|
||||
};
|
||||
|
||||
var onInput = function(e) {
|
||||
if (inCompostion)
|
||||
return;
|
||||
var inputHandler = null;
|
||||
this.setInputHandler = function(cb) {inputHandler = cb};
|
||||
this.getInputHandler = function() {return inputHandler};
|
||||
var afterContextMenu = false;
|
||||
|
||||
var sendText = function(data) {
|
||||
if (inputHandler) {
|
||||
data = inputHandler(data);
|
||||
inputHandler = null;
|
||||
}
|
||||
if (pasted) {
|
||||
var data = text.value;
|
||||
resetValue();
|
||||
resetSelection();
|
||||
if (data)
|
||||
host.onPaste(data);
|
||||
pasted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var data = text.value;
|
||||
} else if (data == PLACEHOLDER.charAt(0)) {
|
||||
if (afterContextMenu)
|
||||
host.execCommand("del", {source: "ace"});
|
||||
else // some versions of android do not fire keydown when pressing backspace
|
||||
host.execCommand("backspace", {source: "ace"});
|
||||
} else {
|
||||
if (data.substring(0, 2) == PLACEHOLDER)
|
||||
data = data.substr(2);
|
||||
else
|
||||
else if (data.charAt(0) == PLACEHOLDER.charAt(0))
|
||||
data = data.substr(1);
|
||||
|
||||
resetValue();
|
||||
if (data) {
|
||||
// can happen if undo in textarea isn't stopped
|
||||
if (data[data.length - 1] == PLACEHOLDER[0])
|
||||
else if (data.charAt(data.length - 1) == PLACEHOLDER.charAt(0))
|
||||
data = data.slice(0, -1);
|
||||
// can happen if undo in textarea isn't stopped
|
||||
if (data.charAt(data.length - 1) == PLACEHOLDER.charAt(0))
|
||||
data = data.slice(0, -1);
|
||||
|
||||
if (data)
|
||||
host.onTextInput(data);
|
||||
} else
|
||||
host.onDelete();
|
||||
}
|
||||
if (afterContextMenu)
|
||||
afterContextMenu = false;
|
||||
};
|
||||
|
||||
var onCompositionStart = function(e) {
|
||||
inCompostion = true;
|
||||
host.onCompositionStart();
|
||||
setTimeout(onCompositionUpdate, 0);
|
||||
};
|
||||
|
||||
var onCompositionUpdate = function() {
|
||||
if (!inCompostion) return;
|
||||
host.onCompositionUpdate(text.value);
|
||||
};
|
||||
|
||||
var onCompositionEnd = function(e) {
|
||||
inCompostion = false;
|
||||
host.onCompositionEnd();
|
||||
};
|
||||
|
||||
var onCut = function(e) {
|
||||
var data = host.getCopyText();
|
||||
if (!data) {
|
||||
event.preventDefault(e);
|
||||
var onInput = function(e) {
|
||||
// console.log("onInput", inComposition)
|
||||
if (inComposition)
|
||||
return;
|
||||
}
|
||||
|
||||
var clipboardData = e.clipboardData || window.clipboardData;
|
||||
|
||||
if (clipboardData) {
|
||||
// Safari 5 has clipboardData object, but does not handle setData()
|
||||
var supported = clipboardData.setData("Text", data);
|
||||
if (supported) {
|
||||
host.onCut();
|
||||
event.preventDefault(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!supported) {
|
||||
cut = true;
|
||||
text.value = data;
|
||||
text.select();
|
||||
setTimeout(function(){
|
||||
cut = false;
|
||||
var data = text.value;
|
||||
sendText(data);
|
||||
resetValue();
|
||||
resetSelection();
|
||||
host.onCut();
|
||||
});
|
||||
};
|
||||
|
||||
var handleClipboardData = function(e, data) {
|
||||
var clipboardData = e.clipboardData || window.clipboardData;
|
||||
if (!clipboardData || BROKEN_SETDATA)
|
||||
return;
|
||||
// using "Text" doesn't work on old webkit but ie needs it
|
||||
// TODO are there other browsers that require "Text"?
|
||||
var mime = USE_IE_MIME_TYPE ? "Text" : "text/plain";
|
||||
if (data) {
|
||||
// Safari 5 has clipboardData object, but does not handle setData()
|
||||
return clipboardData.setData(mime, data) !== false;
|
||||
} else {
|
||||
return clipboardData.getData(mime);
|
||||
}
|
||||
};
|
||||
|
||||
var onCopy = function(e) {
|
||||
var doCopy = function(e, isCut) {
|
||||
var data = host.getCopyText();
|
||||
if (!data) {
|
||||
event.preventDefault(e);
|
||||
return;
|
||||
}
|
||||
if (!data)
|
||||
return event.preventDefault(e);
|
||||
|
||||
var clipboardData = e.clipboardData || window.clipboardData;
|
||||
|
||||
if (clipboardData) {
|
||||
// Safari 5 has clipboardData object, but does not handle setData()
|
||||
var supported = clipboardData.setData("Text", data);
|
||||
if (supported) {
|
||||
host.onCopy();
|
||||
if (handleClipboardData(e, data)) {
|
||||
isCut ? host.onCut() : host.onCopy();
|
||||
event.preventDefault(e);
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
} else {
|
||||
copied = true;
|
||||
text.value = data;
|
||||
text.select();
|
||||
@@ -224,20 +288,26 @@ var TextInput = function(parentNode, host) {
|
||||
copied = false;
|
||||
resetValue();
|
||||
resetSelection();
|
||||
host.onCopy();
|
||||
isCut ? host.onCut() : host.onCopy();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var onCut = function(e) {
|
||||
doCopy(e, true);
|
||||
};
|
||||
|
||||
var onCopy = function(e) {
|
||||
doCopy(e, false);
|
||||
};
|
||||
|
||||
var onPaste = function(e) {
|
||||
var clipboardData = e.clipboardData || window.clipboardData;
|
||||
|
||||
if (clipboardData) {
|
||||
var data = clipboardData.getData("Text");
|
||||
var data = handleClipboardData(e);
|
||||
if (typeof data == "string") {
|
||||
if (data)
|
||||
host.onPaste(data);
|
||||
if (useragent.isIE)
|
||||
setTimeout(resetSelection);
|
||||
event.preventDefault(e);
|
||||
}
|
||||
else {
|
||||
@@ -277,68 +347,128 @@ var TextInput = function(parentNode, host) {
|
||||
});
|
||||
}
|
||||
|
||||
if (useragent.isOldIE) {
|
||||
event.addListener(text, "propertychange", function(e){
|
||||
if (text.value != "" && text.value != PLACEHOLDER)
|
||||
onInput(e);
|
||||
});
|
||||
|
||||
var keytable = { 13:1, 27:1 };
|
||||
event.addListener(text, "keyup", function (e) {
|
||||
if (inCompostion && (!text.value || keytable[e.keyCode]))
|
||||
setTimeout(onCompositionEnd, 0);
|
||||
if ((text.value.charCodeAt(0)|0) < 129) {
|
||||
// COMPOSITION
|
||||
var onCompositionStart = function(e) {
|
||||
if (inComposition || !host.onCompositionStart || host.$readOnly)
|
||||
return;
|
||||
// console.log("onCompositionStart", inComposition)
|
||||
inComposition = {};
|
||||
host.onCompositionStart();
|
||||
setTimeout(onCompositionUpdate, 0);
|
||||
host.on("mousedown", onCompositionEnd);
|
||||
if (!host.selection.isEmpty()) {
|
||||
host.insert("");
|
||||
host.session.markUndoGroup();
|
||||
host.selection.clearSelection();
|
||||
}
|
||||
host.session.markUndoGroup();
|
||||
};
|
||||
|
||||
var onCompositionUpdate = function() {
|
||||
// console.log("onCompositionUpdate", inComposition && JSON.stringify(text.value))
|
||||
if (!inComposition || !host.onCompositionUpdate || host.$readOnly)
|
||||
return;
|
||||
var val = text.value.replace(/\x01/g, "");
|
||||
if (inComposition.lastValue === val) return;
|
||||
|
||||
host.onCompositionUpdate(val);
|
||||
if (inComposition.lastValue)
|
||||
host.undo();
|
||||
inComposition.lastValue = val;
|
||||
if (inComposition.lastValue) {
|
||||
var r = host.selection.getRange();
|
||||
host.insert(inComposition.lastValue);
|
||||
host.session.markUndoGroup();
|
||||
inComposition.range = host.selection.getRange();
|
||||
host.selection.setRange(r);
|
||||
host.selection.clearSelection();
|
||||
}
|
||||
};
|
||||
|
||||
var onCompositionEnd = function(e) {
|
||||
if (!host.onCompositionEnd || host.$readOnly) return;
|
||||
// console.log("onCompositionEnd", inComposition &&inComposition.lastValue)
|
||||
var c = inComposition;
|
||||
inComposition = false;
|
||||
var timer = setTimeout(function() {
|
||||
timer = null;
|
||||
var str = text.value.replace(/\x01/g, "");
|
||||
// console.log(str, c.lastValue)
|
||||
if (inComposition)
|
||||
return;
|
||||
else if (str == c.lastValue)
|
||||
resetValue();
|
||||
else if (!c.lastValue && str) {
|
||||
resetValue();
|
||||
sendText(str);
|
||||
}
|
||||
inCompostion ? onCompositionUpdate() : onCompositionStart();
|
||||
});
|
||||
inputHandler = function compositionInputHandler(str) {
|
||||
// console.log("onCompositionEnd", str, c.lastValue)
|
||||
if (timer)
|
||||
clearTimeout(timer);
|
||||
str = str.replace(/\x01/g, "");
|
||||
if (str == c.lastValue)
|
||||
return "";
|
||||
if (c.lastValue && timer)
|
||||
host.undo();
|
||||
return str;
|
||||
};
|
||||
host.onCompositionEnd();
|
||||
host.removeListener("mousedown", onCompositionEnd);
|
||||
if (e.type == "compositionend" && c.range) {
|
||||
host.selection.setRange(c.range);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
var syncComposition = lang.delayedCall(onCompositionUpdate, 50);
|
||||
|
||||
event.addListener(text, "compositionstart", onCompositionStart);
|
||||
if (useragent.isGecko) {
|
||||
event.addListener(text, "text", onCompositionUpdate);
|
||||
}
|
||||
if (useragent.isWebKit) {
|
||||
event.addListener(text, "keyup", onCompositionUpdate);
|
||||
event.addListener(text, "text", function(){syncComposition.schedule()});
|
||||
} else {
|
||||
event.addListener(text, "keyup", function(){syncComposition.schedule()});
|
||||
event.addListener(text, "keydown", function(){syncComposition.schedule()});
|
||||
}
|
||||
event.addListener(text, "compositionend", onCompositionEnd);
|
||||
|
||||
event.addListener(text, "blur", function() {
|
||||
host.onBlur();
|
||||
});
|
||||
|
||||
event.addListener(text, "focus", function() {
|
||||
host.onFocus();
|
||||
resetSelection();
|
||||
});
|
||||
|
||||
this.focus = function() {
|
||||
text.focus();
|
||||
};
|
||||
|
||||
this.blur = function() {
|
||||
text.blur();
|
||||
};
|
||||
|
||||
function isFocused() {
|
||||
return document.activeElement === text;
|
||||
}
|
||||
this.isFocused = isFocused;
|
||||
|
||||
this.getElement = function() {
|
||||
return text;
|
||||
};
|
||||
|
||||
this.setReadOnly = function(readOnly) {
|
||||
text.readOnly = readOnly;
|
||||
};
|
||||
|
||||
this.onContextMenu = function(e) {
|
||||
afterContextMenu = true;
|
||||
resetSelection(host.selection.isEmpty());
|
||||
host._emit("nativecontextmenu", {target: host, domEvent: e});
|
||||
this.moveToMouse(e, true);
|
||||
};
|
||||
|
||||
this.moveToMouse = function(e, bringToFront) {
|
||||
if (!bringToFront && useragent.isOldIE)
|
||||
return;
|
||||
if (!tempStyle)
|
||||
tempStyle = text.style.cssText;
|
||||
text.style.cssText = (bringToFront ? "z-index:100000;" : "")
|
||||
+ "height:" + text.style.height + ";"
|
||||
+ (useragent.isIE ? "opacity:0.1;" : "");
|
||||
|
||||
text.style.cssText =
|
||||
"position:fixed; z-index:100000;" +
|
||||
(useragent.isIE ? "background:rgba(0, 0, 0, 0.03); opacity:0.1;" : "") + //"background:rgba(250, 0, 0, 0.3); opacity:1;" +
|
||||
"left:" + (e.clientX - 2) + "px; top:" + (e.clientY - 2) + "px;";
|
||||
|
||||
resetSelection(host.selection.isEmpty());
|
||||
var rect = host.container.getBoundingClientRect();
|
||||
var style = dom.computedStyle(host.container);
|
||||
var top = rect.top + (parseInt(style.borderTopWidth) || 0);
|
||||
var left = rect.left + (parseInt(rect.borderLeftWidth) || 0);
|
||||
var maxTop = rect.bottom - top - text.clientHeight -2;
|
||||
var move = function(e) {
|
||||
text.style.left = e.clientX - left - 2 + "px";
|
||||
text.style.top = Math.min(e.clientY - top - 2, maxTop) + "px";
|
||||
};
|
||||
move(e);
|
||||
|
||||
if (e.type != "mousedown")
|
||||
return;
|
||||
@@ -347,15 +477,15 @@ var TextInput = function(parentNode, host) {
|
||||
host.renderer.$keepTextAreaAtCursor = null;
|
||||
|
||||
// on windows context menu is opened after mouseup
|
||||
if (useragent.isWin)
|
||||
event.capture(host.container, function(e) {
|
||||
text.style.left = e.clientX - 2 + "px";
|
||||
text.style.top = e.clientY - 2 + "px";
|
||||
}, onContextMenuClose);
|
||||
if (useragent.isWin && !useragent.isOldIE)
|
||||
event.capture(host.container, move, onContextMenuClose);
|
||||
};
|
||||
|
||||
this.onContextMenuClose = onContextMenuClose;
|
||||
var closeTimeout;
|
||||
function onContextMenuClose() {
|
||||
setTimeout(function () {
|
||||
clearTimeout(closeTimeout)
|
||||
closeTimeout = setTimeout(function () {
|
||||
if (tempStyle) {
|
||||
text.style.cssText = tempStyle;
|
||||
tempStyle = '';
|
||||
@@ -364,16 +494,15 @@ var TextInput = function(parentNode, host) {
|
||||
host.renderer.$keepTextAreaAtCursor = true;
|
||||
host.renderer.$moveTextAreaToCursor();
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
this.onContextMenuClose = onContextMenuClose;
|
||||
}, useragent.isOldIE ? 200 : 0);
|
||||
}
|
||||
|
||||
// firefox fires contextmenu event after opening it
|
||||
if (!useragent.isGecko)
|
||||
event.addListener(text, "contextmenu", function(e) {
|
||||
var onContextMenu = function(e) {
|
||||
host.textInput.onContextMenu(e);
|
||||
onContextMenuClose();
|
||||
});
|
||||
};
|
||||
event.addListener(host.renderer.scroller, "contextmenu", onContextMenu);
|
||||
event.addListener(text, "contextmenu", onContextMenu);
|
||||
};
|
||||
|
||||
exports.TextInput = TextInput;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,561 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
"never use strict";
|
||||
|
||||
var util = require("./maps/util");
|
||||
var motions = require("./maps/motions");
|
||||
var operators = require("./maps/operators");
|
||||
var alias = require("./maps/aliases");
|
||||
var registers = require("./registers");
|
||||
|
||||
var NUMBER = 1;
|
||||
var OPERATOR = 2;
|
||||
var MOTION = 3;
|
||||
var ACTION = 4;
|
||||
var HMARGIN = 8; // Minimum amount of line separation between margins;
|
||||
|
||||
var repeat = function repeat(fn, count, args) {
|
||||
while (0 < count--)
|
||||
fn.apply(this, args);
|
||||
};
|
||||
|
||||
var ensureScrollMargin = function(editor) {
|
||||
var renderer = editor.renderer;
|
||||
var pos = renderer.$cursorLayer.getPixelPosition();
|
||||
|
||||
var top = pos.top;
|
||||
|
||||
var margin = HMARGIN * renderer.layerConfig.lineHeight;
|
||||
if (2 * margin > renderer.$size.scrollerHeight)
|
||||
margin = renderer.$size.scrollerHeight / 2;
|
||||
|
||||
if (renderer.scrollTop > top - margin) {
|
||||
renderer.session.setScrollTop(top - margin);
|
||||
}
|
||||
|
||||
if (renderer.scrollTop + renderer.$size.scrollerHeight < top + margin + renderer.lineHeight) {
|
||||
renderer.session.setScrollTop(top + margin + renderer.lineHeight - renderer.$size.scrollerHeight);
|
||||
}
|
||||
};
|
||||
|
||||
var actions = exports.actions = {
|
||||
"z": {
|
||||
param: true,
|
||||
fn: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "z":
|
||||
editor.renderer.alignCursor(null, 0.5);
|
||||
break;
|
||||
case "t":
|
||||
editor.renderer.alignCursor(null, 0);
|
||||
break;
|
||||
case "b":
|
||||
editor.renderer.alignCursor(null, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"r": {
|
||||
param: true,
|
||||
fn: function(editor, range, count, param) {
|
||||
if (param && param.length) {
|
||||
repeat(function() { editor.insert(param); }, count || 1);
|
||||
editor.navigateLeft();
|
||||
}
|
||||
}
|
||||
},
|
||||
"R": {
|
||||
fn: function(editor, range, count, param) {
|
||||
util.insertMode(editor);
|
||||
editor.setOverwrite(true);
|
||||
}
|
||||
},
|
||||
"~": {
|
||||
fn: function(editor, range, count) {
|
||||
repeat(function() {
|
||||
var range = editor.selection.getRange();
|
||||
if (range.isEmpty())
|
||||
range.end.column++;
|
||||
var text = editor.session.getTextRange(range);
|
||||
var toggled = text.toUpperCase();
|
||||
if (toggled == text)
|
||||
editor.navigateRight();
|
||||
else
|
||||
editor.session.replace(range, toggled);
|
||||
}, count || 1);
|
||||
}
|
||||
},
|
||||
"*": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectWord();
|
||||
editor.findNext();
|
||||
ensureScrollMargin(editor);
|
||||
var r = editor.selection.getRange();
|
||||
editor.selection.setSelectionRange(r, true);
|
||||
}
|
||||
},
|
||||
"#": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectWord();
|
||||
editor.findPrevious();
|
||||
ensureScrollMargin(editor);
|
||||
var r = editor.selection.getRange();
|
||||
editor.selection.setSelectionRange(r, true);
|
||||
}
|
||||
},
|
||||
"n": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var options = editor.getLastSearchOptions();
|
||||
options.backwards = false;
|
||||
|
||||
editor.selection.moveCursorRight();
|
||||
editor.selection.clearSelection();
|
||||
editor.findNext(options);
|
||||
|
||||
ensureScrollMargin(editor);
|
||||
var r = editor.selection.getRange();
|
||||
r.end.row = r.start.row;
|
||||
r.end.column = r.start.column;
|
||||
editor.selection.setSelectionRange(r, true);
|
||||
}
|
||||
},
|
||||
"N": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var options = editor.getLastSearchOptions();
|
||||
options.backwards = true;
|
||||
|
||||
editor.findPrevious(options);
|
||||
ensureScrollMargin(editor);
|
||||
var r = editor.selection.getRange();
|
||||
r.end.row = r.start.row;
|
||||
r.end.column = r.start.column;
|
||||
editor.selection.setSelectionRange(r, true);
|
||||
}
|
||||
},
|
||||
"v": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectRight();
|
||||
util.visualMode(editor, false);
|
||||
},
|
||||
acceptsMotion: true
|
||||
},
|
||||
"V": {
|
||||
fn: function(editor, range, count, param) {
|
||||
//editor.selection.selectLine();
|
||||
//editor.selection.selectLeft();
|
||||
var row = editor.getCursorPosition().row;
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(row, 0);
|
||||
editor.selection.selectLineEnd();
|
||||
editor.selection.visualLineStart = row;
|
||||
|
||||
util.visualMode(editor, true);
|
||||
},
|
||||
acceptsMotion: true
|
||||
},
|
||||
"Y": {
|
||||
fn: function(editor, range, count, param) {
|
||||
util.copyLine(editor);
|
||||
}
|
||||
},
|
||||
"p": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var defaultReg = registers._default;
|
||||
|
||||
editor.setOverwrite(false);
|
||||
if (defaultReg.isLine) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lines = defaultReg.text.split("\n");
|
||||
editor.session.getDocument().insertLines(pos.row + 1, lines);
|
||||
editor.moveCursorTo(pos.row + 1, 0);
|
||||
}
|
||||
else {
|
||||
editor.navigateRight();
|
||||
editor.insert(defaultReg.text);
|
||||
editor.navigateLeft();
|
||||
}
|
||||
editor.setOverwrite(true);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"P": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var defaultReg = registers._default;
|
||||
editor.setOverwrite(false);
|
||||
|
||||
if (defaultReg.isLine) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lines = defaultReg.text.split("\n");
|
||||
editor.session.getDocument().insertLines(pos.row, lines);
|
||||
editor.moveCursorTo(pos.row, 0);
|
||||
}
|
||||
else {
|
||||
editor.insert(defaultReg.text);
|
||||
}
|
||||
editor.setOverwrite(true);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"J": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var session = editor.session;
|
||||
range = editor.getSelectionRange();
|
||||
var pos = {row: range.start.row, column: range.start.column};
|
||||
count = count || range.end.row - range.start.row;
|
||||
var maxRow = Math.min(pos.row + (count || 1), session.getLength() - 1);
|
||||
|
||||
range.start.column = session.getLine(pos.row).length;
|
||||
range.end.column = session.getLine(maxRow).length;
|
||||
range.end.row = maxRow;
|
||||
|
||||
var text = "";
|
||||
for (var i = pos.row; i < maxRow; i++) {
|
||||
var nextLine = session.getLine(i + 1);
|
||||
text += " " + /^\s*(.*)$/.exec(nextLine)[1] || "";
|
||||
}
|
||||
|
||||
session.replace(range, text);
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.undo();
|
||||
}
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"ctrl-r": {
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.redo();
|
||||
}
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
":": {
|
||||
fn: function(editor, range, count, param) {
|
||||
// not implemented
|
||||
}
|
||||
},
|
||||
"/": {
|
||||
fn: function(editor, range, count, param) {
|
||||
// not implemented
|
||||
}
|
||||
},
|
||||
"?": {
|
||||
fn: function(editor, range, count, param) {
|
||||
// not implemented
|
||||
}
|
||||
},
|
||||
".": {
|
||||
fn: function(editor, range, count, param) {
|
||||
util.onInsertReplaySequence = inputBuffer.lastInsertCommands;
|
||||
var previous = inputBuffer.previous;
|
||||
if (previous) // If there is a previous action
|
||||
inputBuffer.exec(editor, previous.action, previous.param);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var inputBuffer = exports.inputBuffer = {
|
||||
accepting: [NUMBER, OPERATOR, MOTION, ACTION],
|
||||
currentCmd: null,
|
||||
//currentMode: 0,
|
||||
currentCount: "",
|
||||
status: "",
|
||||
|
||||
// Types
|
||||
operator: null,
|
||||
motion: null,
|
||||
|
||||
lastInsertCommands: [],
|
||||
|
||||
push: function(editor, ch, keyId) {
|
||||
this.idle = false;
|
||||
var wObj = this.waitingForParam;
|
||||
if (wObj) {
|
||||
this.exec(editor, wObj, ch);
|
||||
}
|
||||
// If input is a number (that doesn't start with 0)
|
||||
else if (!(ch === "0" && !this.currentCount.length) &&
|
||||
(ch.match(/^\d+$/) && this.isAccepting(NUMBER))) {
|
||||
// Assuming that ch is always of type String, and not Number
|
||||
this.currentCount += ch;
|
||||
this.currentCmd = NUMBER;
|
||||
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
|
||||
}
|
||||
else if (!this.operator && this.isAccepting(OPERATOR) && operators[ch]) {
|
||||
this.operator = {
|
||||
ch: ch,
|
||||
count: this.getCount()
|
||||
};
|
||||
this.currentCmd = OPERATOR;
|
||||
this.accepting = [NUMBER, MOTION, ACTION];
|
||||
this.exec(editor, { operator: this.operator });
|
||||
}
|
||||
else if (motions[ch] && this.isAccepting(MOTION)) {
|
||||
this.currentCmd = MOTION;
|
||||
|
||||
var ctx = {
|
||||
operator: this.operator,
|
||||
motion: {
|
||||
ch: ch,
|
||||
count: this.getCount()
|
||||
}
|
||||
};
|
||||
|
||||
if (motions[ch].param)
|
||||
this.waitForParam(ctx);
|
||||
else
|
||||
this.exec(editor, ctx);
|
||||
}
|
||||
else if (alias[ch] && this.isAccepting(MOTION)) {
|
||||
alias[ch].operator.count = this.getCount();
|
||||
this.exec(editor, alias[ch]);
|
||||
}
|
||||
else if (actions[ch] && this.isAccepting(ACTION)) {
|
||||
var actionObj = {
|
||||
action: {
|
||||
fn: actions[ch].fn,
|
||||
count: this.getCount()
|
||||
}
|
||||
};
|
||||
|
||||
if (actions[ch].param) {
|
||||
this.waitForParam(actionObj);
|
||||
}
|
||||
else {
|
||||
this.exec(editor, actionObj);
|
||||
}
|
||||
|
||||
if (actions[ch].acceptsMotion)
|
||||
this.idle = false;
|
||||
}
|
||||
else if (this.operator) {
|
||||
this.exec(editor, { operator: this.operator }, ch);
|
||||
}
|
||||
else {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
if (this.waitingForParam || this.motion || this.operator) {
|
||||
this.status += ch;
|
||||
} else if (this.currentCount) {
|
||||
this.status = this.currentCount;
|
||||
} else if (this.status) {
|
||||
this.status = "";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
editor._emit("changeStatus");
|
||||
},
|
||||
|
||||
waitForParam: function(cmd) {
|
||||
this.waitingForParam = cmd;
|
||||
},
|
||||
|
||||
getCount: function() {
|
||||
var count = this.currentCount;
|
||||
this.currentCount = "";
|
||||
return count && parseInt(count, 10);
|
||||
},
|
||||
|
||||
exec: function(editor, action, param) {
|
||||
var m = action.motion;
|
||||
var o = action.operator;
|
||||
var a = action.action;
|
||||
|
||||
if (!param)
|
||||
param = action.param;
|
||||
|
||||
if (o) {
|
||||
this.previous = {
|
||||
action: action,
|
||||
param: param
|
||||
};
|
||||
}
|
||||
|
||||
if (o && !editor.selection.isEmpty()) {
|
||||
if (operators[o.ch].selFn) {
|
||||
operators[o.ch].selFn(editor, editor.getSelectionRange(), o.count, param);
|
||||
this.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// There is an operator, but no motion or action. We try to pass the
|
||||
// current ch to the operator to see if it responds to it (an example
|
||||
// of this is the 'dd' operator).
|
||||
else if (!m && !a && o && param) {
|
||||
operators[o.ch].fn(editor, null, o.count, param);
|
||||
this.reset();
|
||||
}
|
||||
else if (m) {
|
||||
var run = function(fn) {
|
||||
if (fn && typeof fn === "function") { // There should always be a motion
|
||||
if (m.count && !motionObj.handlesCount)
|
||||
repeat(fn, m.count, [editor, null, m.count, param]);
|
||||
else
|
||||
fn(editor, null, m.count, param);
|
||||
}
|
||||
};
|
||||
|
||||
var motionObj = motions[m.ch];
|
||||
var selectable = motionObj.sel;
|
||||
|
||||
if (!o) {
|
||||
if ((util.onVisualMode || util.onVisualLineMode) && selectable)
|
||||
run(motionObj.sel);
|
||||
else
|
||||
run(motionObj.nav);
|
||||
}
|
||||
else if (selectable) {
|
||||
repeat(function() {
|
||||
run(motionObj.sel);
|
||||
operators[o.ch].fn(editor, editor.getSelectionRange(), o.count, param);
|
||||
}, o.count || 1);
|
||||
}
|
||||
this.reset();
|
||||
}
|
||||
else if (a) {
|
||||
a.fn(editor, editor.getSelectionRange(), a.count, param);
|
||||
this.reset();
|
||||
}
|
||||
handleCursorMove(editor);
|
||||
},
|
||||
|
||||
isAccepting: function(type) {
|
||||
return this.accepting.indexOf(type) !== -1;
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.operator = null;
|
||||
this.motion = null;
|
||||
this.currentCount = "";
|
||||
this.status = "";
|
||||
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
|
||||
this.idle = true;
|
||||
this.waitingForParam = null;
|
||||
}
|
||||
};
|
||||
|
||||
function setPreviousCommand(fn) {
|
||||
inputBuffer.previous = { action: { action: { fn: fn } } };
|
||||
}
|
||||
|
||||
exports.coreCommands = {
|
||||
start: {
|
||||
exec: function start(editor) {
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(start);
|
||||
}
|
||||
},
|
||||
startBeginning: {
|
||||
exec: function startBeginning(editor) {
|
||||
editor.navigateLineStart();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(startBeginning);
|
||||
}
|
||||
},
|
||||
// Stop Insert mode as soon as possible. Works like typing <Esc> in
|
||||
// insert mode.
|
||||
stop: {
|
||||
exec: function stop(editor) {
|
||||
inputBuffer.reset();
|
||||
util.onVisualMode = false;
|
||||
util.onVisualLineMode = false;
|
||||
inputBuffer.lastInsertCommands = util.normalMode(editor);
|
||||
}
|
||||
},
|
||||
append: {
|
||||
exec: function append(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
if (lineLen)
|
||||
editor.navigateRight();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(append);
|
||||
}
|
||||
},
|
||||
appendEnd: {
|
||||
exec: function appendEnd(editor) {
|
||||
editor.navigateLineEnd();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(appendEnd);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var handleCursorMove = exports.onCursorMove = function(editor, e) {
|
||||
if (util.currentMode === 'insert' || handleCursorMove.running)
|
||||
return;
|
||||
else if(!editor.selection.isEmpty()) {
|
||||
handleCursorMove.running = true;
|
||||
if (util.onVisualLineMode) {
|
||||
var originRow = editor.selection.visualLineStart;
|
||||
var cursorRow = editor.getCursorPosition().row;
|
||||
if(originRow <= cursorRow) {
|
||||
var endLine = editor.session.getLine(cursorRow);
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(originRow, 0);
|
||||
editor.selection.selectTo(cursorRow, endLine.length);
|
||||
} else {
|
||||
var endLine = editor.session.getLine(originRow);
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(originRow, endLine.length);
|
||||
editor.selection.selectTo(cursorRow, 0);
|
||||
}
|
||||
}
|
||||
handleCursorMove.running = false;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (e && (util.onVisualLineMode || util.onVisualMode)) {
|
||||
editor.selection.clearSelection();
|
||||
util.normalMode(editor);
|
||||
}
|
||||
|
||||
handleCursorMove.running = true;
|
||||
var pos = editor.getCursorPosition();
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
|
||||
if (lineLen && pos.column === lineLen)
|
||||
editor.navigateLeft();
|
||||
handleCursorMove.running = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,593 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var util = require("./util");
|
||||
|
||||
var keepScrollPosition = function(editor, fn) {
|
||||
var scrollTopRow = editor.renderer.getScrollTopRow();
|
||||
var initialRow = editor.getCursorPosition().row;
|
||||
var diff = initialRow - scrollTopRow;
|
||||
fn && fn.call(editor);
|
||||
editor.renderer.scrollToRow(editor.getCursorPosition().row - diff);
|
||||
};
|
||||
|
||||
function Motion(m) {
|
||||
if (typeof m == "function") {
|
||||
var getPos = m;
|
||||
m = this;
|
||||
} else {
|
||||
var getPos = m.getPos;
|
||||
}
|
||||
m.nav = function(editor, range, count, param) {
|
||||
var a = getPos(editor, range, count, param, false);
|
||||
if (!a)
|
||||
return;
|
||||
editor.clearSelection();
|
||||
editor.moveCursorTo(a.row, a.column);
|
||||
};
|
||||
m.sel = function(editor, range, count, param) {
|
||||
var a = getPos(editor, range, count, param, true);
|
||||
if (!a)
|
||||
return;
|
||||
editor.selection.selectTo(a.row, a.column);
|
||||
};
|
||||
return m;
|
||||
}
|
||||
|
||||
var nonWordRe = /[\s.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/;
|
||||
var wordSeparatorRe = /[.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/;
|
||||
var whiteRe = /\s/;
|
||||
var StringStream = function(editor, cursor) {
|
||||
var sel = editor.selection;
|
||||
this.range = sel.getRange();
|
||||
cursor = cursor || sel.selectionLead;
|
||||
this.row = cursor.row;
|
||||
this.col = cursor.column;
|
||||
var line = editor.session.getLine(this.row);
|
||||
var maxRow = editor.session.getLength();
|
||||
this.ch = line[this.col] || '\n';
|
||||
this.skippedLines = 0;
|
||||
|
||||
this.next = function() {
|
||||
this.ch = line[++this.col] || this.handleNewLine(1);
|
||||
//this.debug()
|
||||
return this.ch;
|
||||
};
|
||||
this.prev = function() {
|
||||
this.ch = line[--this.col] || this.handleNewLine(-1);
|
||||
//this.debug()
|
||||
return this.ch;
|
||||
};
|
||||
this.peek = function(dir) {
|
||||
var ch = line[this.col + dir];
|
||||
if (ch)
|
||||
return ch;
|
||||
if (dir == -1)
|
||||
return '\n';
|
||||
if (this.col == line.length - 1)
|
||||
return '\n';
|
||||
return editor.session.getLine(this.row + 1)[0] || '\n';
|
||||
};
|
||||
|
||||
this.handleNewLine = function(dir) {
|
||||
if (dir == 1){
|
||||
if (this.col == line.length)
|
||||
return '\n';
|
||||
if (this.row == maxRow - 1)
|
||||
return '';
|
||||
this.col = 0;
|
||||
this.row ++;
|
||||
line = editor.session.getLine(this.row);
|
||||
this.skippedLines++;
|
||||
return line[0] || '\n';
|
||||
}
|
||||
if (dir == -1) {
|
||||
if (this.row === 0)
|
||||
return '';
|
||||
this.row --;
|
||||
line = editor.session.getLine(this.row);
|
||||
this.col = line.length;
|
||||
this.skippedLines--;
|
||||
return '\n';
|
||||
}
|
||||
};
|
||||
this.debug = function() {
|
||||
console.log(line.substring(0, this.col)+'|'+this.ch+'\''+this.col+'\''+line.substr(this.col+1));
|
||||
};
|
||||
};
|
||||
|
||||
var Search = require("../../../search").Search;
|
||||
var search = new Search();
|
||||
|
||||
function find(editor, needle, dir) {
|
||||
search.$options.needle = needle;
|
||||
search.$options.backwards = dir == -1;
|
||||
return search.find(editor.session);
|
||||
}
|
||||
|
||||
var Range = require("../../../range").Range;
|
||||
|
||||
module.exports = {
|
||||
"w": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
|
||||
if (str.ch && wordSeparatorRe.test(str.ch)) {
|
||||
while (str.ch && wordSeparatorRe.test(str.ch))
|
||||
str.next();
|
||||
} else {
|
||||
while (str.ch && !nonWordRe.test(str.ch))
|
||||
str.next();
|
||||
}
|
||||
while (str.ch && whiteRe.test(str.ch) && str.skippedLines < 2)
|
||||
str.next();
|
||||
|
||||
str.skippedLines == 2 && str.prev();
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
"W": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
while(str.ch && !(whiteRe.test(str.ch) && !whiteRe.test(str.peek(1))) && str.skippedLines < 2)
|
||||
str.next();
|
||||
if (str.skippedLines == 2)
|
||||
str.prev();
|
||||
else
|
||||
str.next();
|
||||
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
"b": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
|
||||
str.prev();
|
||||
while (str.ch && whiteRe.test(str.ch) && str.skippedLines > -2)
|
||||
str.prev();
|
||||
|
||||
if (str.ch && wordSeparatorRe.test(str.ch)) {
|
||||
while (str.ch && wordSeparatorRe.test(str.ch))
|
||||
str.prev();
|
||||
} else {
|
||||
while (str.ch && !nonWordRe.test(str.ch))
|
||||
str.prev();
|
||||
}
|
||||
str.ch && str.next();
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
"B": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
str.prev();
|
||||
while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(-1))) && str.skippedLines > -2)
|
||||
str.prev();
|
||||
|
||||
if (str.skippedLines == -2)
|
||||
str.next();
|
||||
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
"e": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
|
||||
str.next();
|
||||
while (str.ch && whiteRe.test(str.ch))
|
||||
str.next();
|
||||
|
||||
if (str.ch && wordSeparatorRe.test(str.ch)) {
|
||||
while (str.ch && wordSeparatorRe.test(str.ch))
|
||||
str.next();
|
||||
} else {
|
||||
while (str.ch && !nonWordRe.test(str.ch))
|
||||
str.next();
|
||||
}
|
||||
str.ch && str.prev();
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
"E": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
str.next();
|
||||
while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(1))))
|
||||
str.next();
|
||||
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
|
||||
"l": {
|
||||
nav: function(editor) {
|
||||
editor.navigateRight();
|
||||
},
|
||||
sel: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var col = pos.column;
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
|
||||
// Solving the behavior at the end of the line due to the
|
||||
// different 0 index-based colum positions in ACE.
|
||||
if (lineLen && col !== lineLen) //In selection mode you can select the newline
|
||||
editor.selection.selectRight();
|
||||
}
|
||||
},
|
||||
"h": {
|
||||
nav: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
if (pos.column > 0)
|
||||
editor.navigateLeft();
|
||||
},
|
||||
sel: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
if (pos.column > 0)
|
||||
editor.selection.selectLeft();
|
||||
}
|
||||
},
|
||||
"H": {
|
||||
nav: function(editor) {
|
||||
var row = editor.renderer.getScrollTopRow();
|
||||
editor.moveCursorTo(row);
|
||||
},
|
||||
sel: function(editor) {
|
||||
var row = editor.renderer.getScrollTopRow();
|
||||
editor.selection.selectTo(row);
|
||||
}
|
||||
},
|
||||
"M": {
|
||||
nav: function(editor) {
|
||||
var topRow = editor.renderer.getScrollTopRow();
|
||||
var bottomRow = editor.renderer.getScrollBottomRow();
|
||||
var row = topRow + ((bottomRow - topRow) / 2);
|
||||
editor.moveCursorTo(row);
|
||||
},
|
||||
sel: function(editor) {
|
||||
var topRow = editor.renderer.getScrollTopRow();
|
||||
var bottomRow = editor.renderer.getScrollBottomRow();
|
||||
var row = topRow + ((bottomRow - topRow) / 2);
|
||||
editor.selection.selectTo(row);
|
||||
}
|
||||
},
|
||||
"L": {
|
||||
nav: function(editor) {
|
||||
var row = editor.renderer.getScrollBottomRow();
|
||||
editor.moveCursorTo(row);
|
||||
},
|
||||
sel: function(editor) {
|
||||
var row = editor.renderer.getScrollBottomRow();
|
||||
editor.selection.selectTo(row);
|
||||
}
|
||||
},
|
||||
"k": {
|
||||
nav: function(editor) {
|
||||
editor.navigateUp();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectUp();
|
||||
}
|
||||
},
|
||||
"j": {
|
||||
nav: function(editor) {
|
||||
editor.navigateDown();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectDown();
|
||||
}
|
||||
},
|
||||
|
||||
"i": {
|
||||
param: true,
|
||||
sel: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "w":
|
||||
editor.selection.selectWord();
|
||||
break;
|
||||
case "W":
|
||||
editor.selection.selectAWord();
|
||||
break;
|
||||
case "(":
|
||||
case "{":
|
||||
case "[":
|
||||
var cursor = editor.getCursorPosition();
|
||||
var end = editor.session.$findClosingBracket(param, cursor, /paren/);
|
||||
if (!end)
|
||||
return;
|
||||
var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/);
|
||||
if (!start)
|
||||
return;
|
||||
start.column ++;
|
||||
editor.selection.setSelectionRange(Range.fromPoints(start, end));
|
||||
break;
|
||||
case "'":
|
||||
case '"':
|
||||
case "/":
|
||||
var end = find(editor, param, 1);
|
||||
if (!end)
|
||||
return;
|
||||
var start = find(editor, param, -1);
|
||||
if (!start)
|
||||
return;
|
||||
editor.selection.setSelectionRange(Range.fromPoints(start.end, end.start));
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"a": {
|
||||
param: true,
|
||||
sel: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "w":
|
||||
editor.selection.selectAWord();
|
||||
break;
|
||||
case "W":
|
||||
editor.selection.selectAWord();
|
||||
break;
|
||||
case "(":
|
||||
case "{":
|
||||
case "[":
|
||||
var cursor = editor.getCursorPosition();
|
||||
var end = editor.session.$findClosingBracket(param, cursor, /paren/);
|
||||
if (!end)
|
||||
return;
|
||||
var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/);
|
||||
if (!start)
|
||||
return;
|
||||
end.column ++;
|
||||
editor.selection.setSelectionRange(Range.fromPoints(start, end));
|
||||
break;
|
||||
case "'":
|
||||
case "\"":
|
||||
case "/":
|
||||
var end = find(editor, param, 1);
|
||||
if (!end)
|
||||
return;
|
||||
var start = find(editor, param, -1);
|
||||
if (!start)
|
||||
return;
|
||||
end.column ++;
|
||||
editor.selection.setSelectionRange(Range.fromPoints(start.start, end.end));
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"f": new Motion({
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
getPos: function(editor, range, count, param, isSel) {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
cursor.column += column + (isSel ? 2 : 1);
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
}),
|
||||
"F": new Motion({
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
getPos: function(editor, range, count, param, isSel) {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
cursor.column -= column + 1;
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
}),
|
||||
"t": new Motion({
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
getPos: function(editor, range, count, param, isSel) {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
cursor.column += column + (isSel ? 1 : 0);
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
}),
|
||||
"T": new Motion({
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
getPos: function(editor, range, count, param, isSel) {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
cursor.column -= column;
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
"^": {
|
||||
nav: function(editor) {
|
||||
editor.navigateLineStart();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectLineStart();
|
||||
}
|
||||
},
|
||||
"$": {
|
||||
nav: function(editor) {
|
||||
editor.navigateLineEnd();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectLineEnd();
|
||||
}
|
||||
},
|
||||
"0": new Motion(function(ed) {
|
||||
return {row: ed.selection.lead.row, column: 0};
|
||||
}),
|
||||
"G": {
|
||||
nav: function(editor, range, count, param) {
|
||||
if (!count && count !== 0) { // Stupid JS
|
||||
count = editor.session.getLength();
|
||||
}
|
||||
editor.gotoLine(count);
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
if (!count && count !== 0) { // Stupid JS
|
||||
count = editor.session.getLength();
|
||||
}
|
||||
editor.selection.selectTo(count, 0);
|
||||
}
|
||||
},
|
||||
"g": {
|
||||
param: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
switch(param) {
|
||||
case "m":
|
||||
console.log("Middle line");
|
||||
break;
|
||||
case "e":
|
||||
console.log("End of prev word");
|
||||
break;
|
||||
case "g":
|
||||
editor.gotoLine(count || 0);
|
||||
case "u":
|
||||
editor.gotoLine(count || 0);
|
||||
case "U":
|
||||
editor.gotoLine(count || 0);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
switch(param) {
|
||||
case "m":
|
||||
console.log("Middle line");
|
||||
break;
|
||||
case "e":
|
||||
console.log("End of prev word");
|
||||
break;
|
||||
case "g":
|
||||
editor.selection.selectTo(count || 0, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
"o": {
|
||||
nav: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
var content = "";
|
||||
while (0 < count--)
|
||||
content += "\n";
|
||||
|
||||
if (content.length) {
|
||||
editor.navigateLineEnd()
|
||||
editor.insert(content);
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
},
|
||||
"O": {
|
||||
nav: function(editor, range, count, param) {
|
||||
var row = editor.getCursorPosition().row;
|
||||
count = count || 1;
|
||||
var content = "";
|
||||
while (0 < count--)
|
||||
content += "\n";
|
||||
|
||||
if (content.length) {
|
||||
if(row > 0) {
|
||||
editor.navigateUp();
|
||||
editor.navigateLineEnd()
|
||||
editor.insert(content);
|
||||
} else {
|
||||
editor.session.insert({row: 0, column: 0}, content);
|
||||
editor.navigateUp();
|
||||
}
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
},
|
||||
"%": new Motion(function(editor){
|
||||
var brRe = /[\[\]{}()]/g;
|
||||
var cursor = editor.getCursorPosition();
|
||||
var ch = editor.session.getLine(cursor.row)[cursor.column];
|
||||
if (!brRe.test(ch)) {
|
||||
var range = find(editor, brRe);
|
||||
if (!range)
|
||||
return;
|
||||
cursor = range.start;
|
||||
}
|
||||
var match = editor.session.findMatchingBracket({
|
||||
row: cursor.row,
|
||||
column: cursor.column + 1
|
||||
});
|
||||
|
||||
return match;
|
||||
}),
|
||||
"{": new Motion(function(ed) {
|
||||
var session = ed.session;
|
||||
var row = session.selection.lead.row;
|
||||
while(row > 0 && !/\S/.test(session.getLine(row)))
|
||||
row--;
|
||||
while(/\S/.test(session.getLine(row)))
|
||||
row--;
|
||||
return {column: 0, row: row};
|
||||
}),
|
||||
"}": new Motion(function(ed) {
|
||||
var session = ed.session;
|
||||
var l = session.getLength();
|
||||
var row = session.selection.lead.row;
|
||||
while(row < l && !/\S/.test(session.getLine(row)))
|
||||
row++;
|
||||
while(/\S/.test(session.getLine(row)))
|
||||
row++;
|
||||
return {column: 0, row: row};
|
||||
}),
|
||||
"ctrl-d": {
|
||||
nav: function(editor, range, count, param) {
|
||||
editor.selection.clearSelection();
|
||||
keepScrollPosition(editor, editor.gotoPageDown);
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
keepScrollPosition(editor, editor.selectPageDown);
|
||||
}
|
||||
},
|
||||
"ctrl-u": {
|
||||
nav: function(editor, range, count, param) {
|
||||
editor.selection.clearSelection();
|
||||
keepScrollPosition(editor, editor.gotoPageUp);
|
||||
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
keepScrollPosition(editor, editor.selectPageUp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.backspace = module.exports.left = module.exports.h;
|
||||
module.exports.right = module.exports.l;
|
||||
module.exports.up = module.exports.k;
|
||||
module.exports.down = module.exports.j;
|
||||
module.exports.pagedown = module.exports["ctrl-d"];
|
||||
module.exports.pageup = module.exports["ctrl-u"];
|
||||
|
||||
});
|
||||
@@ -1,196 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
"never use strict";
|
||||
|
||||
var util = require("./util");
|
||||
var registers = require("../registers");
|
||||
|
||||
module.exports = {
|
||||
"d": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = util.onVisualLineMode;
|
||||
if(util.onVisualLineMode)
|
||||
editor.removeLines();
|
||||
else
|
||||
editor.session.remove(range);
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
switch (param) {
|
||||
case "d":
|
||||
registers._default.text = "";
|
||||
registers._default.isLine = true;
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.selection.selectLine();
|
||||
registers._default.text += editor.getCopyText();
|
||||
var selRange = editor.getSelectionRange();
|
||||
// check if end of the document was reached
|
||||
if (!selRange.isMultiLine()) {
|
||||
lastLineReached = true
|
||||
var row = selRange.start.row - 1;
|
||||
var col = editor.session.getLine(row).length
|
||||
selRange.setStart(row, col);
|
||||
editor.session.remove(selRange);
|
||||
editor.selection.clearSelection();
|
||||
break;
|
||||
}
|
||||
editor.session.remove(selRange);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
registers._default.text = registers._default.text.replace(/\n$/, "");
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
editor.selection.setSelectionRange(range);
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = false;
|
||||
editor.session.remove(range);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"c": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
editor.session.remove(range);
|
||||
util.insertMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
switch (param) {
|
||||
case "c":
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.removeLines();
|
||||
util.insertMode(editor);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
|
||||
// range.end.column ++;
|
||||
editor.session.remove(range);
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"y": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = util.onVisualLineMode;
|
||||
editor.selection.clearSelection();
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
switch (param) {
|
||||
case "y":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
registers._default.text = editor.getCopyText().replace(/\n$/, "");
|
||||
editor.selection.clearSelection();
|
||||
registers._default.isLine = true;
|
||||
editor.moveCursorToPosition(pos);
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.setSelectionRange(range);
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = false;
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
">": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.indent();
|
||||
}
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
switch (param) {
|
||||
case ">":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
editor.indent();
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorToPosition(pos);
|
||||
editor.navigateLineEnd();
|
||||
editor.navigateLineStart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"<": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.blockOutdent();
|
||||
}
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
switch (param) {
|
||||
case "<":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
editor.blockOutdent();
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorToPosition(pos);
|
||||
editor.navigateLineEnd();
|
||||
editor.navigateLineStart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,134 +0,0 @@
|
||||
define(function(require, exports, module) {
|
||||
var registers = require("../registers");
|
||||
|
||||
var dom = require("../../../lib/dom");
|
||||
dom.importCssString('.insert-mode .ace_cursor{\
|
||||
border-left: 2px solid #333333;\
|
||||
}\
|
||||
.ace_dark.insert-mode .ace_cursor{\
|
||||
border-left: 2px solid #eeeeee;\
|
||||
}\
|
||||
.normal-mode .ace_cursor{\
|
||||
border: 0!important;\
|
||||
background-color: red;\
|
||||
opacity: 0.5;\
|
||||
}', 'vimMode');
|
||||
|
||||
module.exports = {
|
||||
onVisualMode: false,
|
||||
onVisualLineMode: false,
|
||||
currentMode: 'normal',
|
||||
noMode: function(editor) {
|
||||
editor.unsetStyle('insert-mode');
|
||||
editor.unsetStyle('normal-mode');
|
||||
if (editor.commands.recording)
|
||||
editor.commands.toggleRecording(editor);
|
||||
editor.setOverwrite(false);
|
||||
},
|
||||
insertMode: function(editor) {
|
||||
this.currentMode = 'insert';
|
||||
// Switch editor to insert mode
|
||||
editor.setStyle('insert-mode');
|
||||
editor.unsetStyle('normal-mode');
|
||||
|
||||
editor.setOverwrite(false);
|
||||
editor.keyBinding.$data.buffer = "";
|
||||
editor.keyBinding.$data.state = "insertMode";
|
||||
this.onVisualMode = false;
|
||||
this.onVisualLineMode = false;
|
||||
if(this.onInsertReplaySequence) {
|
||||
// Ok, we're apparently replaying ("."), so let's do it
|
||||
editor.commands.macro = this.onInsertReplaySequence;
|
||||
editor.commands.replay(editor);
|
||||
this.onInsertReplaySequence = null;
|
||||
this.normalMode(editor);
|
||||
} else {
|
||||
editor._emit("changeStatus");
|
||||
// Record any movements, insertions in insert mode
|
||||
if(!editor.commands.recording)
|
||||
editor.commands.toggleRecording(editor);
|
||||
}
|
||||
},
|
||||
normalMode: function(editor) {
|
||||
// Switch editor to normal mode
|
||||
this.currentMode = 'normal';
|
||||
|
||||
editor.unsetStyle('insert-mode');
|
||||
editor.setStyle('normal-mode');
|
||||
editor.clearSelection();
|
||||
|
||||
var pos;
|
||||
if (!editor.getOverwrite()) {
|
||||
pos = editor.getCursorPosition();
|
||||
if (pos.column > 0)
|
||||
editor.navigateLeft();
|
||||
}
|
||||
|
||||
editor.setOverwrite(true);
|
||||
editor.keyBinding.$data.buffer = "";
|
||||
editor.keyBinding.$data.state = "start";
|
||||
this.onVisualMode = false;
|
||||
this.onVisualLineMode = false;
|
||||
editor._emit("changeStatus");
|
||||
// Save recorded keystrokes
|
||||
if (editor.commands.recording) {
|
||||
editor.commands.toggleRecording(editor);
|
||||
return editor.commands.macro;
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
visualMode: function(editor, lineMode) {
|
||||
if (
|
||||
(this.onVisualLineMode && lineMode)
|
||||
|| (this.onVisualMode && !lineMode)
|
||||
) {
|
||||
this.normalMode(editor);
|
||||
return;
|
||||
}
|
||||
|
||||
editor.setStyle('insert-mode');
|
||||
editor.unsetStyle('normal-mode');
|
||||
|
||||
editor._emit("changeStatus");
|
||||
if (lineMode) {
|
||||
this.onVisualLineMode = true;
|
||||
} else {
|
||||
this.onVisualMode = true;
|
||||
this.onVisualLineMode = false;
|
||||
}
|
||||
},
|
||||
getRightNthChar: function(editor, cursor, ch, n) {
|
||||
var line = editor.getSession().getLine(cursor.row);
|
||||
var matches = line.substr(cursor.column + 1).split(ch);
|
||||
|
||||
return n < matches.length ? matches.slice(0, n).join(ch).length : null;
|
||||
},
|
||||
getLeftNthChar: function(editor, cursor, ch, n) {
|
||||
var line = editor.getSession().getLine(cursor.row);
|
||||
var matches = line.substr(0, cursor.column).split(ch);
|
||||
|
||||
return n < matches.length ? matches.slice(-1 * n).join(ch).length : null;
|
||||
},
|
||||
toRealChar: function(ch) {
|
||||
if (ch.length === 1)
|
||||
return ch;
|
||||
|
||||
if (/^shift-./.test(ch))
|
||||
return ch[ch.length - 1].toUpperCase();
|
||||
else
|
||||
return "";
|
||||
},
|
||||
copyLine: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
editor.selection.selectLine();
|
||||
registers._default.isLine = true;
|
||||
registers._default.text = editor.getCopyText().replace(/\n$/, "");
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
}
|
||||
};
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,12 +32,16 @@ define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
var IE8;
|
||||
|
||||
var Cursor = function(parentEl) {
|
||||
this.element = dom.createElement("div");
|
||||
this.element.className = "ace_layer ace_cursor-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
|
||||
if (IE8 === undefined)
|
||||
IE8 = "opacity" in this.element;
|
||||
|
||||
this.isVisible = false;
|
||||
this.isBlinking = true;
|
||||
this.blinkInterval = 1000;
|
||||
@@ -46,10 +50,23 @@ var Cursor = function(parentEl) {
|
||||
this.cursors = [];
|
||||
this.cursor = this.addCursor();
|
||||
dom.addCssClass(this.element, "ace_hidden-cursors");
|
||||
this.$updateCursors = this.$updateVisibility.bind(this);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.$updateVisibility = function(val) {
|
||||
var cursors = this.cursors;
|
||||
for (var i = cursors.length; i--; )
|
||||
cursors[i].style.visibility = val ? "" : "hidden";
|
||||
};
|
||||
this.$updateOpacity = function(val) {
|
||||
var cursors = this.cursors;
|
||||
for (var i = cursors.length; i--; )
|
||||
cursors[i].style.opacity = val ? "" : "0";
|
||||
};
|
||||
|
||||
|
||||
this.$padding = 0;
|
||||
this.setPadding = function(padding) {
|
||||
this.$padding = padding;
|
||||
@@ -74,12 +91,13 @@ var Cursor = function(parentEl) {
|
||||
};
|
||||
|
||||
this.setSmoothBlinking = function(smoothBlinking) {
|
||||
if (smoothBlinking != this.smoothBlinking) {
|
||||
if (smoothBlinking != this.smoothBlinking && !IE8) {
|
||||
this.smoothBlinking = smoothBlinking;
|
||||
if (smoothBlinking)
|
||||
dom.addCssClass(this.element, "ace_smooth-blinking");
|
||||
else
|
||||
dom.removeCssClass(this.element, "ace_smooth-blinking");
|
||||
dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking);
|
||||
this.$updateCursors(true);
|
||||
this.$updateCursors = (smoothBlinking
|
||||
? this.$updateOpacity
|
||||
: this.$updateVisibility).bind(this);
|
||||
this.restartTimer();
|
||||
}
|
||||
};
|
||||
@@ -113,35 +131,34 @@ var Cursor = function(parentEl) {
|
||||
};
|
||||
|
||||
this.restartTimer = function() {
|
||||
var update = this.$updateCursors;
|
||||
clearInterval(this.intervalId);
|
||||
clearTimeout(this.timeoutId);
|
||||
if (this.smoothBlinking)
|
||||
if (this.smoothBlinking) {
|
||||
dom.removeCssClass(this.element, "ace_smooth-blinking");
|
||||
for (var i = this.cursors.length; i--; )
|
||||
this.cursors[i].style.opacity = "";
|
||||
}
|
||||
|
||||
update(true);
|
||||
|
||||
if (!this.isBlinking || !this.blinkInterval || !this.isVisible)
|
||||
return;
|
||||
|
||||
if (this.smoothBlinking)
|
||||
if (this.smoothBlinking) {
|
||||
setTimeout(function(){
|
||||
dom.addCssClass(this.element, "ace_smooth-blinking");
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
var blink = function(){
|
||||
this.timeoutId = setTimeout(function() {
|
||||
for (var i = this.cursors.length; i--; ) {
|
||||
this.cursors[i].style.opacity = 0;
|
||||
}
|
||||
}.bind(this), 0.6 * this.blinkInterval);
|
||||
update(false);
|
||||
}, 0.6 * this.blinkInterval);
|
||||
}.bind(this);
|
||||
|
||||
this.intervalId = setInterval(function() {
|
||||
for (var i = this.cursors.length; i--; ) {
|
||||
this.cursors[i].style.opacity = "";
|
||||
}
|
||||
update(true);
|
||||
blink();
|
||||
}.bind(this), this.blinkInterval);
|
||||
}, this.blinkInterval);
|
||||
|
||||
blink();
|
||||
};
|
||||
@@ -170,19 +187,23 @@ var Cursor = function(parentEl) {
|
||||
selections = [{cursor: null}];
|
||||
}
|
||||
|
||||
for (var i = selections.length; i--; ) {
|
||||
for (var i = 0, n = selections.length; i < n; i++) {
|
||||
var pixelPos = this.getPixelPosition(selections[i].cursor, true);
|
||||
if ((pixelPos.top > config.height + config.offset ||
|
||||
pixelPos.top < -config.offset) && i > 1) {
|
||||
pixelPos.top < 0) && i > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var style = (this.cursors[cursorIndex++] || this.addCursor()).style;
|
||||
|
||||
if (!this.drawCursor) {
|
||||
style.left = pixelPos.left + "px";
|
||||
style.top = pixelPos.top + "px";
|
||||
style.width = config.characterWidth + "px";
|
||||
style.height = config.lineHeight + "px";
|
||||
} else {
|
||||
this.drawCursor(style, pixelPos, config, selections[i], this.session);
|
||||
}
|
||||
}
|
||||
while (this.cursors.length > cursorIndex)
|
||||
this.removeCursor();
|
||||
@@ -195,6 +216,8 @@ var Cursor = function(parentEl) {
|
||||
this.restartTimer();
|
||||
};
|
||||
|
||||
this.drawCursor = null;
|
||||
|
||||
this.$setOverwrite = function(overwrite) {
|
||||
if (overwrite != this.overwrite) {
|
||||
this.overwrite = overwrite;
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var dom = require("../lib/dom");
|
||||
var lang = require("../lib/lang");
|
||||
var useragent = require("../lib/useragent");
|
||||
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
||||
|
||||
var CHAR_COUNT = 0;
|
||||
|
||||
var FontMetrics = exports.FontMetrics = function(parentEl, interval) {
|
||||
this.el = dom.createElement("div");
|
||||
this.$setMeasureNodeStyles(this.el.style, true);
|
||||
|
||||
this.$main = dom.createElement("div");
|
||||
this.$setMeasureNodeStyles(this.$main.style);
|
||||
|
||||
this.$measureNode = dom.createElement("div");
|
||||
this.$setMeasureNodeStyles(this.$measureNode.style);
|
||||
|
||||
|
||||
this.el.appendChild(this.$main);
|
||||
this.el.appendChild(this.$measureNode);
|
||||
parentEl.appendChild(this.el);
|
||||
|
||||
if (!CHAR_COUNT)
|
||||
this.$testFractionalRect();
|
||||
this.$measureNode.innerHTML = lang.stringRepeat("X", CHAR_COUNT);
|
||||
|
||||
this.$characterSize = {width: 0, height: 0};
|
||||
this.checkForSizeChanges();
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.$characterSize = {width: 0, height: 0};
|
||||
|
||||
this.$testFractionalRect = function() {
|
||||
var el = dom.createElement("div");
|
||||
this.$setMeasureNodeStyles(el.style);
|
||||
el.style.width = "0.2px";
|
||||
document.documentElement.appendChild(el);
|
||||
var w = el.getBoundingClientRect().width;
|
||||
if (w > 0 && w < 1)
|
||||
CHAR_COUNT = 50;
|
||||
else
|
||||
CHAR_COUNT = 100;
|
||||
el.parentNode.removeChild(el);
|
||||
};
|
||||
|
||||
this.$setMeasureNodeStyles = function(style, isRoot) {
|
||||
style.width = style.height = "auto";
|
||||
style.left = style.top = "0px";
|
||||
style.visibility = "hidden";
|
||||
style.position = "absolute";
|
||||
style.whiteSpace = "pre";
|
||||
|
||||
if (useragent.isIE < 8) {
|
||||
style["font-family"] = "inherit";
|
||||
} else {
|
||||
style.font = "inherit";
|
||||
}
|
||||
style.overflow = isRoot ? "hidden" : "visible";
|
||||
};
|
||||
|
||||
this.checkForSizeChanges = function() {
|
||||
var size = this.$measureSizes();
|
||||
if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) {
|
||||
this.$measureNode.style.fontWeight = "bold";
|
||||
var boldSize = this.$measureSizes();
|
||||
this.$measureNode.style.fontWeight = "";
|
||||
this.$characterSize = size;
|
||||
this.charSizes = Object.create(null);
|
||||
this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height;
|
||||
this._emit("changeCharacterSize", {data: size});
|
||||
}
|
||||
};
|
||||
|
||||
this.$pollSizeChanges = function() {
|
||||
if (this.$pollSizeChangesTimer)
|
||||
return this.$pollSizeChangesTimer;
|
||||
var self = this;
|
||||
return this.$pollSizeChangesTimer = setInterval(function() {
|
||||
self.checkForSizeChanges();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
this.setPolling = function(val) {
|
||||
if (val) {
|
||||
this.$pollSizeChanges();
|
||||
} else {
|
||||
if (this.$pollSizeChangesTimer)
|
||||
this.$pollSizeChangesTimer;
|
||||
}
|
||||
};
|
||||
|
||||
this.$measureSizes = function() {
|
||||
if (CHAR_COUNT === 50) {
|
||||
var rect = null;
|
||||
try {
|
||||
rect = this.$measureNode.getBoundingClientRect();
|
||||
} catch(e) {
|
||||
rect = {width: 0, height:0 };
|
||||
};
|
||||
var size = {
|
||||
height: rect.height,
|
||||
width: rect.width / CHAR_COUNT
|
||||
};
|
||||
} else {
|
||||
var size = {
|
||||
height: this.$measureNode.clientHeight,
|
||||
width: this.$measureNode.clientWidth / CHAR_COUNT
|
||||
};
|
||||
}
|
||||
// Size and width can be null if the editor is not visible or
|
||||
// detached from the document
|
||||
if (size.width === 0 || size.height === 0)
|
||||
return null;
|
||||
return size;
|
||||
};
|
||||
|
||||
this.$measureCharWidth = function(ch) {
|
||||
this.$main.innerHTML = lang.stringRepeat(ch, CHAR_COUNT);
|
||||
var rect = this.$main.getBoundingClientRect();
|
||||
return rect.width / CHAR_COUNT;
|
||||
};
|
||||
|
||||
this.getCharacterWidth = function(ch) {
|
||||
var w = this.charSizes[ch];
|
||||
if (w === undefined) {
|
||||
this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width;
|
||||
}
|
||||
return w;
|
||||
};
|
||||
|
||||
this.destroy = function() {
|
||||
clearInterval(this.$pollSizeChangesTimer);
|
||||
if (this.el && this.el.parentNode)
|
||||
this.el.parentNode.removeChild(this.el);
|
||||
};
|
||||
|
||||
}).call(FontMetrics.prototype);
|
||||
|
||||
});
|
||||
@@ -46,6 +46,8 @@ var Gutter = function(parentEl) {
|
||||
|
||||
this.$annotations = [];
|
||||
this.$updateAnnotations = this.$updateAnnotations.bind(this);
|
||||
|
||||
this.$cells = [];
|
||||
};
|
||||
|
||||
(function() {
|
||||
@@ -56,6 +58,7 @@ var Gutter = function(parentEl) {
|
||||
if (this.session)
|
||||
this.session.removeEventListener("change", this.$updateAnnotations);
|
||||
this.session = session;
|
||||
if (session)
|
||||
session.on("change", this.$updateAnnotations);
|
||||
};
|
||||
|
||||
@@ -73,8 +76,7 @@ var Gutter = function(parentEl) {
|
||||
|
||||
this.setAnnotations = function(annotations) {
|
||||
// iterate over sparse array
|
||||
this.$annotations = []
|
||||
var rowInfo, row;
|
||||
this.$annotations = [];
|
||||
for (var i = 0; i < annotations.length; i++) {
|
||||
var annotation = annotations[i];
|
||||
var row = annotation.row;
|
||||
@@ -110,76 +112,140 @@ var Gutter = function(parentEl) {
|
||||
} else if (delta.action == "removeText" || delta.action == "removeLines") {
|
||||
this.$annotations.splice(firstRow, len + 1, null);
|
||||
} else {
|
||||
var args = Array(len + 1);
|
||||
var args = new Array(len + 1);
|
||||
args.unshift(firstRow, 1);
|
||||
this.$annotations.splice.apply(this.$annotations, args);
|
||||
}
|
||||
};
|
||||
|
||||
this.update = function(config) {
|
||||
var emptyAnno = {className: ""};
|
||||
var html = [];
|
||||
var i = config.firstRow;
|
||||
var lastRow = config.lastRow;
|
||||
var fold = this.session.getNextFoldLine(i);
|
||||
var session = this.session;
|
||||
var firstRow = config.firstRow;
|
||||
var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar
|
||||
session.getLength() - 1);
|
||||
var fold = session.getNextFoldLine(firstRow);
|
||||
var foldStart = fold ? fold.start.row : Infinity;
|
||||
var foldWidgets = this.$showFoldWidgets && this.session.foldWidgets;
|
||||
var breakpoints = this.session.$breakpoints;
|
||||
var decorations = this.session.$decorations;
|
||||
var foldWidgets = this.$showFoldWidgets && session.foldWidgets;
|
||||
var breakpoints = session.$breakpoints;
|
||||
var decorations = session.$decorations;
|
||||
var firstLineNumber = session.$firstLineNumber;
|
||||
var lastLineNumber = 0;
|
||||
|
||||
while (true) {
|
||||
if(i > foldStart) {
|
||||
i = fold.end.row + 1;
|
||||
fold = this.session.getNextFoldLine(i, fold);
|
||||
foldStart = fold ?fold.start.row :Infinity;
|
||||
}
|
||||
if(i > lastRow)
|
||||
break;
|
||||
var gutterRenderer = session.gutterRenderer || this.$renderer;
|
||||
|
||||
var annotation = this.$annotations[i] || emptyAnno;
|
||||
html.push(
|
||||
"<div class='ace_gutter-cell ",
|
||||
breakpoints[i] || "", decorations[i] || "", annotation.className,
|
||||
"' style='height:", this.session.getRowLength(i) * config.lineHeight, "px;'>",
|
||||
lastLineNumber = i + 1
|
||||
);
|
||||
var cell = null;
|
||||
var index = -1;
|
||||
var row = firstRow;
|
||||
while (true) {
|
||||
if (row > foldStart) {
|
||||
row = fold.end.row + 1;
|
||||
fold = session.getNextFoldLine(row, fold);
|
||||
foldStart = fold ? fold.start.row : Infinity;
|
||||
}
|
||||
if (row > lastRow) {
|
||||
while (this.$cells.length > index + 1) {
|
||||
cell = this.$cells.pop();
|
||||
this.element.removeChild(cell.element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cell = this.$cells[++index];
|
||||
if (!cell) {
|
||||
cell = {element: null, textNode: null, foldWidget: null};
|
||||
cell.element = dom.createElement("div");
|
||||
cell.textNode = document.createTextNode('');
|
||||
cell.element.appendChild(cell.textNode);
|
||||
this.element.appendChild(cell.element);
|
||||
this.$cells[index] = cell;
|
||||
}
|
||||
|
||||
var className = "ace_gutter-cell ";
|
||||
if (breakpoints[row])
|
||||
className += breakpoints[row];
|
||||
if (decorations[row])
|
||||
className += decorations[row];
|
||||
if (this.$annotations[row])
|
||||
className += this.$annotations[row].className;
|
||||
if (cell.element.className != className)
|
||||
cell.element.className = className;
|
||||
|
||||
var height = session.getRowLength(row) * config.lineHeight + "px";
|
||||
if (height != cell.element.style.height)
|
||||
cell.element.style.height = height;
|
||||
|
||||
if (foldWidgets) {
|
||||
var c = foldWidgets[i];
|
||||
var c = foldWidgets[row];
|
||||
// check if cached value is invalidated and we need to recompute
|
||||
if (c == null)
|
||||
c = foldWidgets[i] = this.session.getFoldWidget(i);
|
||||
if (c)
|
||||
html.push(
|
||||
"<span class='ace_fold-widget ace_", c,
|
||||
c == "start" && i == foldStart && i < fold.end.row ? " ace_closed" : " ace_open",
|
||||
"' style='height:", config.lineHeight, "px",
|
||||
"'></span>"
|
||||
);
|
||||
c = foldWidgets[row] = session.getFoldWidget(row);
|
||||
}
|
||||
|
||||
html.push("</div>");
|
||||
if (c) {
|
||||
if (!cell.foldWidget) {
|
||||
cell.foldWidget = dom.createElement("span");
|
||||
cell.element.appendChild(cell.foldWidget);
|
||||
}
|
||||
var className = "ace_fold-widget ace_" + c;
|
||||
if (c == "start" && row == foldStart && row < fold.end.row)
|
||||
className += " ace_closed";
|
||||
else
|
||||
className += " ace_open";
|
||||
if (cell.foldWidget.className != className)
|
||||
cell.foldWidget.className = className;
|
||||
|
||||
i++;
|
||||
var height = config.lineHeight + "px";
|
||||
if (cell.foldWidget.style.height != height)
|
||||
cell.foldWidget.style.height = height;
|
||||
} else {
|
||||
if (cell.foldWidget) {
|
||||
cell.element.removeChild(cell.foldWidget);
|
||||
cell.foldWidget = null;
|
||||
}
|
||||
}
|
||||
|
||||
var text = lastLineNumber = gutterRenderer
|
||||
? gutterRenderer.getText(session, row)
|
||||
: row + firstLineNumber;
|
||||
if (text != cell.textNode.data)
|
||||
cell.textNode.data = text;
|
||||
|
||||
row++;
|
||||
}
|
||||
|
||||
this.element = dom.setInnerHtml(this.element, html.join(""));
|
||||
this.element.style.height = config.minHeight + "px";
|
||||
|
||||
if (this.session.$useWrapMode)
|
||||
lastLineNumber = this.session.getLength();
|
||||
if (this.$fixedWidth || session.$useWrapMode)
|
||||
lastLineNumber = session.getLength() + firstLineNumber;
|
||||
|
||||
var gutterWidth = gutterRenderer
|
||||
? gutterRenderer.getWidth(session, lastLineNumber, config)
|
||||
: lastLineNumber.toString().length * config.characterWidth;
|
||||
|
||||
var gutterWidth = ("" + lastLineNumber).length * config.characterWidth;
|
||||
var padding = this.$padding || this.$computePadding();
|
||||
gutterWidth += padding.left + padding.right;
|
||||
if (gutterWidth !== this.gutterWidth) {
|
||||
if (gutterWidth !== this.gutterWidth && !isNaN(gutterWidth)) {
|
||||
this.gutterWidth = gutterWidth;
|
||||
this.element.style.width = Math.ceil(this.gutterWidth) + "px";
|
||||
this._emit("changeGutterWidth", gutterWidth);
|
||||
}
|
||||
};
|
||||
|
||||
this.$fixedWidth = false;
|
||||
|
||||
this.$showLineNumbers = true;
|
||||
this.$renderer = "";
|
||||
this.setShowLineNumbers = function(show) {
|
||||
this.$renderer = !show && {
|
||||
getWidth: function() {return ""},
|
||||
getText: function() {return ""}
|
||||
};
|
||||
};
|
||||
|
||||
this.getShowLineNumbers = function() {
|
||||
return this.$showLineNumbers;
|
||||
};
|
||||
|
||||
this.$showFoldWidgets = true;
|
||||
this.setShowFoldWidgets = function(show) {
|
||||
if (show)
|
||||
@@ -199,9 +265,9 @@ var Gutter = function(parentEl) {
|
||||
if (!this.element.firstChild)
|
||||
return {left: 0, right: 0};
|
||||
var style = dom.computedStyle(this.element.firstChild);
|
||||
this.$padding = {}
|
||||
this.$padding.left = parseInt(style.paddingLeft) + 1;
|
||||
this.$padding.right = parseInt(style.paddingRight);
|
||||
this.$padding = {};
|
||||
this.$padding.left = parseInt(style.paddingLeft) + 1 || 0;
|
||||
this.$padding.right = parseInt(style.paddingRight) || 0;
|
||||
return this.$padding;
|
||||
};
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ var Marker = function(parentEl) {
|
||||
marker.renderer(html, range, left, top, config);
|
||||
} else if (marker.type == "fullLine") {
|
||||
this.drawFullLineMarker(html, range, marker.clazz, config);
|
||||
} else if (marker.type == "screenLine") {
|
||||
this.drawScreenLineMarker(html, range, marker.clazz, config);
|
||||
} else if (range.isMultiLine()) {
|
||||
if (marker.type == "text")
|
||||
this.drawTextMarker(html, range, marker.clazz, config);
|
||||
@@ -91,7 +93,7 @@ var Marker = function(parentEl) {
|
||||
this.drawSingleLineMarker(html, range, marker.clazz + " ace_start", config);
|
||||
}
|
||||
}
|
||||
this.element = dom.setInnerHtml(this.element, html.join(""));
|
||||
this.element.innerHTML = html.join("");
|
||||
};
|
||||
|
||||
this.$getTop = function(row, layerConfig) {
|
||||
@@ -99,7 +101,7 @@ var Marker = function(parentEl) {
|
||||
};
|
||||
|
||||
// Draws a marker, which spans a range of text on multiple lines
|
||||
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig) {
|
||||
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) {
|
||||
// selection start
|
||||
var row = range.start.row;
|
||||
|
||||
@@ -107,35 +109,36 @@ var Marker = function(parentEl) {
|
||||
row, range.start.column,
|
||||
row, this.session.getScreenLastRowColumn(row)
|
||||
);
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " ace_start", layerConfig, 1, "text");
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " ace_start", layerConfig, 1, extraStyle);
|
||||
|
||||
// selection end
|
||||
row = range.end.row;
|
||||
lineRange = new Range(row, 0, row, range.end.column);
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, "text");
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, extraStyle);
|
||||
|
||||
for (row = range.start.row + 1; row < range.end.row; row++) {
|
||||
lineRange.start.row = row;
|
||||
lineRange.end.row = row;
|
||||
lineRange.end.column = this.session.getScreenLastRowColumn(row);
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, "text");
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, extraStyle);
|
||||
}
|
||||
};
|
||||
|
||||
// Draws a multi line marker, where lines span the full width
|
||||
this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, type) {
|
||||
this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
||||
// from selection start to the end of the line
|
||||
var padding = this.$padding;
|
||||
var height = config.lineHeight;
|
||||
var top = this.$getTop(range.start.row, config);
|
||||
var left = padding + range.start.column * config.characterWidth;
|
||||
extraStyle = extraStyle || "";
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, " ace_start' style='",
|
||||
"height:", height, "px;",
|
||||
"right:0;",
|
||||
"top:", top, "px;",
|
||||
"left:", left, "px;'></div>"
|
||||
"left:", left, "px;", extraStyle, "'></div>"
|
||||
);
|
||||
|
||||
// from start of the last line to the selection end
|
||||
@@ -147,7 +150,7 @@ var Marker = function(parentEl) {
|
||||
"height:", height, "px;",
|
||||
"width:", width, "px;",
|
||||
"top:", top, "px;",
|
||||
"left:", padding, "px;'></div>"
|
||||
"left:", padding, "px;", extraStyle, "'></div>"
|
||||
);
|
||||
|
||||
// all the complete lines
|
||||
@@ -161,12 +164,12 @@ var Marker = function(parentEl) {
|
||||
"height:", height, "px;",
|
||||
"right:0;",
|
||||
"top:", top, "px;",
|
||||
"left:", padding, "px;'></div>"
|
||||
"left:", padding, "px;", extraStyle, "'></div>"
|
||||
);
|
||||
};
|
||||
|
||||
// Draws a marker which covers part or whole width of a single screen line
|
||||
this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength) {
|
||||
this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) {
|
||||
var height = config.lineHeight;
|
||||
var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth;
|
||||
|
||||
@@ -178,11 +181,11 @@ var Marker = function(parentEl) {
|
||||
"height:", height, "px;",
|
||||
"width:", width, "px;",
|
||||
"top:", top, "px;",
|
||||
"left:", left,"px;'></div>"
|
||||
"left:", left, "px;", extraStyle || "", "'></div>"
|
||||
);
|
||||
};
|
||||
|
||||
this.drawFullLineMarker = function(stringBuilder, range, clazz, config) {
|
||||
this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
||||
var top = this.$getTop(range.start.row, config);
|
||||
var height = config.lineHeight;
|
||||
if (range.start.row != range.end.row)
|
||||
@@ -192,9 +195,21 @@ var Marker = function(parentEl) {
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"top:", top, "px;",
|
||||
"left:0;right:0;'></div>"
|
||||
"left:0;right:0;", extraStyle || "", "'></div>"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) {
|
||||
var top = this.$getTop(range.start.row, config);
|
||||
var height = config.lineHeight;
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"top:", top, "px;",
|
||||
"left:0;right:0;", extraStyle || "", "'></div>"
|
||||
);
|
||||
};
|
||||
|
||||
}).call(Marker.prototype);
|
||||
|
||||
|
||||
@@ -41,155 +41,61 @@ var Text = function(parentEl) {
|
||||
this.element = dom.createElement("div");
|
||||
this.element.className = "ace_layer ace_text-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
|
||||
this.$characterSize = {width: 0, height: 0};
|
||||
this.checkForSizeChanges();
|
||||
this.$pollSizeChanges();
|
||||
this.$updateEolChar = this.$updateEolChar.bind(this);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.EOF_CHAR = "\xB6"; //"¶";
|
||||
this.EOL_CHAR = "\xAC"; //"¬";
|
||||
this.TAB_CHAR = "\u2192"; //"→" "\u21E5";
|
||||
this.SPACE_CHAR = "\xB7"; //"·";
|
||||
this.EOF_CHAR = "\xB6";
|
||||
this.EOL_CHAR_LF = "\xAC";
|
||||
this.EOL_CHAR_CRLF = "\xa4";
|
||||
this.EOL_CHAR = this.EOL_CHAR_LF;
|
||||
this.TAB_CHAR = "\u2192"; //"\u21E5";
|
||||
this.SPACE_CHAR = "\xB7";
|
||||
this.$padding = 0;
|
||||
|
||||
this.$updateEolChar = function() {
|
||||
var EOL_CHAR = this.session.doc.getNewLineCharacter() == "\n"
|
||||
? this.EOL_CHAR_LF
|
||||
: this.EOL_CHAR_CRLF;
|
||||
if (this.EOL_CHAR != EOL_CHAR) {
|
||||
this.EOL_CHAR = EOL_CHAR;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
this.setPadding = function(padding) {
|
||||
this.$padding = padding;
|
||||
this.element.style.padding = "0 " + padding + "px";
|
||||
};
|
||||
|
||||
this.getLineHeight = function() {
|
||||
return this.$characterSize.height || 1;
|
||||
return this.$fontMetrics.$characterSize.height || 0;
|
||||
};
|
||||
|
||||
this.getCharacterWidth = function() {
|
||||
return this.$characterSize.width || 1;
|
||||
return this.$fontMetrics.$characterSize.width || 0;
|
||||
};
|
||||
|
||||
this.$setFontMetrics = function(measure) {
|
||||
this.$fontMetrics = measure;
|
||||
this.$fontMetrics.on("changeCharacterSize", function(e) {
|
||||
this._signal("changeCharacterSize", e);
|
||||
}.bind(this));
|
||||
this.$pollSizeChanges();
|
||||
}
|
||||
|
||||
this.checkForSizeChanges = function() {
|
||||
var size = this.$measureSizes();
|
||||
if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) {
|
||||
this.$measureNode.style.fontWeight = "bold";
|
||||
var boldSize = this.$measureSizes();
|
||||
this.$measureNode.style.fontWeight = "";
|
||||
this.$characterSize = size;
|
||||
this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height;
|
||||
this._emit("changeCharacterSize", {data: size});
|
||||
}
|
||||
this.$fontMetrics.checkForSizeChanges();
|
||||
};
|
||||
|
||||
this.$pollSizeChanges = function() {
|
||||
var self = this;
|
||||
this.$pollSizeChangesTimer = setInterval(function() {
|
||||
self.checkForSizeChanges();
|
||||
}, 500);
|
||||
return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges();
|
||||
};
|
||||
|
||||
this.$fontStyles = {
|
||||
fontFamily : 1,
|
||||
fontSize : 1,
|
||||
fontWeight : 1,
|
||||
fontStyle : 1,
|
||||
lineHeight : 1
|
||||
};
|
||||
|
||||
this.$measureSizes = useragent.isIE || useragent.isOldGecko ? function() {
|
||||
var n = 1000;
|
||||
if (!this.$measureNode) {
|
||||
var measureNode = this.$measureNode = dom.createElement("div");
|
||||
var style = measureNode.style;
|
||||
|
||||
style.width = style.height = "auto";
|
||||
style.left = style.top = (-n * 40) + "px";
|
||||
|
||||
style.visibility = "hidden";
|
||||
style.position = "fixed";
|
||||
style.overflow = "visible";
|
||||
style.whiteSpace = "nowrap";
|
||||
|
||||
// in FF 3.6 monospace fonts can have a fixed sub pixel width.
|
||||
// that's why we have to measure many characters
|
||||
// Note: characterWidth can be a float!
|
||||
measureNode.innerHTML = lang.stringRepeat("Xy", n);
|
||||
|
||||
if (this.element.ownerDocument.body) {
|
||||
this.element.ownerDocument.body.appendChild(measureNode);
|
||||
} else {
|
||||
var container = this.element.parentNode;
|
||||
while (!dom.hasCssClass(container, "ace_editor"))
|
||||
container = container.parentNode;
|
||||
container.appendChild(measureNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Size and width can be null if the editor is not visible or
|
||||
// detached from the document
|
||||
if (!this.element.offsetWidth)
|
||||
return null;
|
||||
|
||||
var style = this.$measureNode.style;
|
||||
var computedStyle = dom.computedStyle(this.element);
|
||||
for (var prop in this.$fontStyles)
|
||||
style[prop] = computedStyle[prop];
|
||||
|
||||
var size = {
|
||||
height: this.$measureNode.offsetHeight,
|
||||
width: this.$measureNode.offsetWidth / (n * 2)
|
||||
};
|
||||
|
||||
// Size and width can be null if the editor is not visible or
|
||||
// detached from the document
|
||||
if (size.width == 0 || size.height == 0)
|
||||
return null;
|
||||
|
||||
return size;
|
||||
}
|
||||
: function() {
|
||||
if (!this.$measureNode) {
|
||||
var measureNode = this.$measureNode = dom.createElement("div");
|
||||
var style = measureNode.style;
|
||||
|
||||
style.width = style.height = "auto";
|
||||
style.left = style.top = -100 + "px";
|
||||
|
||||
style.visibility = "hidden";
|
||||
style.position = "fixed";
|
||||
style.overflow = "visible";
|
||||
style.whiteSpace = "nowrap";
|
||||
|
||||
measureNode.innerHTML = "X";
|
||||
|
||||
var container = this.element.parentNode;
|
||||
while (container && !dom.hasCssClass(container, "ace_editor"))
|
||||
container = container.parentNode;
|
||||
|
||||
if (!container)
|
||||
return this.$measureNode = null;
|
||||
|
||||
container.appendChild(measureNode);
|
||||
}
|
||||
|
||||
var rect = this.$measureNode.getBoundingClientRect();
|
||||
|
||||
var size = {
|
||||
height: rect.height,
|
||||
width: rect.width
|
||||
};
|
||||
|
||||
// Size and width can be null if the editor is not visible or
|
||||
// detached from the document
|
||||
if (size.width == 0 || size.height == 0)
|
||||
return null;
|
||||
|
||||
return size;
|
||||
};
|
||||
|
||||
this.setSession = function(session) {
|
||||
this.session = session;
|
||||
if (session)
|
||||
this.$computeTabString();
|
||||
};
|
||||
|
||||
@@ -221,26 +127,32 @@ var Text = function(parentEl) {
|
||||
var tabStr = this.$tabStrings = [0];
|
||||
for (var i = 1; i < tabSize + 1; i++) {
|
||||
if (this.showInvisibles) {
|
||||
tabStr.push("<span class='ace_invisible'>"
|
||||
tabStr.push("<span class='ace_invisible ace_invisible_tab'>"
|
||||
+ this.TAB_CHAR
|
||||
+ Array(i).join(" ")
|
||||
+ lang.stringRepeat("\xa0", i - 1)
|
||||
+ "</span>");
|
||||
} else {
|
||||
tabStr.push(new Array(i+1).join(" "));
|
||||
tabStr.push(lang.stringRepeat("\xa0", i));
|
||||
}
|
||||
}
|
||||
if (this.displayIndentGuides) {
|
||||
this.$indentGuideRe = /\s\S| \t|\t |\s$/;
|
||||
var className = "ace_indent-guide";
|
||||
var content = Array(this.tabSize + 1).join(" ");
|
||||
var tabContent = content;
|
||||
var spaceClass = "";
|
||||
var tabClass = "";
|
||||
if (this.showInvisibles) {
|
||||
className += " ace_invisible";
|
||||
tabContent = this.TAB_CHAR + content.substr(6);
|
||||
spaceClass = " ace_invisible_space";
|
||||
tabClass = " ace_invisible_tab";
|
||||
var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize);
|
||||
var tabContent = this.TAB_CHAR + lang.stringRepeat("\xa0", this.tabSize - 1);
|
||||
} else{
|
||||
var spaceContent = lang.stringRepeat("\xa0", this.tabSize);
|
||||
var tabContent = spaceContent;
|
||||
}
|
||||
|
||||
this.$tabStrings[" "] = "<span class='" + className + "'>" + content + "</span>";
|
||||
this.$tabStrings["\t"] = "<span class='" + className + "'>" + tabContent + "</span>";
|
||||
this.$tabStrings[" "] = "<span class='" + className + spaceClass + "'>" + spaceContent + "</span>";
|
||||
this.$tabStrings["\t"] = "<span class='" + className + tabClass + "'>" + tabContent + "</span>";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -291,7 +203,8 @@ var Text = function(parentEl) {
|
||||
this.$renderLine(
|
||||
html, row, !this.$useLineGroups(), row == foldStart ? foldLine : false
|
||||
);
|
||||
dom.setInnerHtml(lineElement, html.join(""));
|
||||
lineElement.style.height = config.lineHeight * this.session.getRowLength(row) + "px";
|
||||
lineElement.innerHTML = html.join("");
|
||||
}
|
||||
row++;
|
||||
}
|
||||
@@ -357,10 +270,11 @@ var Text = function(parentEl) {
|
||||
if (this.$useLineGroups()) {
|
||||
container.className = 'ace_line_group';
|
||||
fragment.appendChild(container);
|
||||
container.style.height = config.lineHeight * this.session.getRowLength(row) + "px";
|
||||
|
||||
} else {
|
||||
var lines = container.childNodes
|
||||
while(lines.length)
|
||||
fragment.appendChild(lines[0]);
|
||||
while(container.firstChild)
|
||||
fragment.appendChild(container.firstChild);
|
||||
}
|
||||
|
||||
row++;
|
||||
@@ -388,7 +302,7 @@ var Text = function(parentEl) {
|
||||
break;
|
||||
|
||||
if (this.$useLineGroups())
|
||||
html.push("<div class='ace_line_group'>")
|
||||
html.push("<div class='ace_line_group' style='height:", config.lineHeight*this.session.getRowLength(row), "px'>")
|
||||
|
||||
this.$renderLine(html, row, false, row == foldStart ? foldLine : false);
|
||||
|
||||
@@ -397,7 +311,7 @@ var Text = function(parentEl) {
|
||||
|
||||
row++;
|
||||
}
|
||||
this.element = dom.setInnerHtml(this.element, html.join(""));
|
||||
this.element.innerHTML = html.join("");
|
||||
};
|
||||
|
||||
this.$textToken = {
|
||||
@@ -408,10 +322,12 @@ var Text = function(parentEl) {
|
||||
|
||||
this.$renderToken = function(stringBuilder, screenColumn, token, value) {
|
||||
var self = this;
|
||||
var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g;
|
||||
var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g;
|
||||
var replaceFunc = function(c, a, b, tabIdx, idx4) {
|
||||
if (a) {
|
||||
return new Array(c.length+1).join(" ");
|
||||
return self.showInvisibles ?
|
||||
"<span class='ace_invisible ace_invisible_space'>" + lang.stringRepeat(self.SPACE_CHAR, c.length) + "</span>" :
|
||||
lang.stringRepeat("\xa0", c.length);
|
||||
} else if (c == "&") {
|
||||
return "&";
|
||||
} else if (c == "<") {
|
||||
@@ -422,14 +338,14 @@ var Text = function(parentEl) {
|
||||
return self.$tabStrings[tabSize];
|
||||
} else if (c == "\u3000") {
|
||||
// U+3000 is both invisible AND full-width, so must be handled uniquely
|
||||
var classToUse = self.showInvisibles ? "ace_cjk ace_invisible" : "ace_cjk";
|
||||
var classToUse = self.showInvisibles ? "ace_cjk ace_invisible ace_invisible_space" : "ace_cjk";
|
||||
var space = self.showInvisibles ? self.SPACE_CHAR : "";
|
||||
screenColumn += 1;
|
||||
return "<span class='" + classToUse + "' style='width:" +
|
||||
(self.config.characterWidth * 2) +
|
||||
"px'>" + space + "</span>";
|
||||
} else if (b) {
|
||||
return "<span class='ace_invisible ace_invalid'>" + self.SPACE_CHAR + "</span>";
|
||||
return "<span class='ace_invisible ace_invisible_space ace_invalid'>" + self.SPACE_CHAR + "</span>";
|
||||
} else {
|
||||
screenColumn += 1;
|
||||
return "<span class='ace_cjk' style='width:" +
|
||||
@@ -453,16 +369,16 @@ var Text = function(parentEl) {
|
||||
return screenColumn + value.length;
|
||||
};
|
||||
|
||||
this.renderIndentGuide = function(stringBuilder, value) {
|
||||
this.renderIndentGuide = function(stringBuilder, value, max) {
|
||||
var cols = value.search(this.$indentGuideRe);
|
||||
if (cols <= 0)
|
||||
if (cols <= 0 || cols >= max)
|
||||
return value;
|
||||
if (value[0] == " ") {
|
||||
cols -= cols % this.tabSize;
|
||||
stringBuilder.push(Array(cols/this.tabSize + 1).join(this.$tabStrings[" "]));
|
||||
stringBuilder.push(lang.stringRepeat(this.$tabStrings[" "], cols/this.tabSize));
|
||||
return value.substr(cols);
|
||||
} else if (value[0] == "\t") {
|
||||
stringBuilder.push(Array(cols + 1).join(this.$tabStrings["\t"]));
|
||||
stringBuilder.push(lang.stringRepeat(this.$tabStrings["\t"], cols));
|
||||
return value.substr(cols);
|
||||
}
|
||||
return value;
|
||||
@@ -479,7 +395,7 @@ var Text = function(parentEl) {
|
||||
var value = token.value;
|
||||
if (i == 0 && this.displayIndentGuides) {
|
||||
chars = value.length;
|
||||
value = this.renderIndentGuide(stringBuilder, value);
|
||||
value = this.renderIndentGuide(stringBuilder, value, splitChars);
|
||||
if (!value)
|
||||
continue;
|
||||
chars -= value.length;
|
||||
@@ -546,7 +462,10 @@ var Text = function(parentEl) {
|
||||
|
||||
if (!onlyContents) {
|
||||
stringBuilder.push(
|
||||
"<div class='ace_line' style='height:", this.config.lineHeight, "px'>"
|
||||
"<div class='ace_line' style='height:",
|
||||
this.config.lineHeight * (
|
||||
this.$useLineGroups() ? 1 :this.session.getRowLength(row)
|
||||
), "px'>"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -563,7 +482,7 @@ var Text = function(parentEl) {
|
||||
row = foldLine.end.row
|
||||
|
||||
stringBuilder.push(
|
||||
"<span class='ace_invisible'>",
|
||||
"<span class='ace_invisible ace_invisible_eol'>",
|
||||
row == this.session.getLength() - 1 ? this.EOF_CHAR : this.EOL_CHAR,
|
||||
"</span>"
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user