Compare commits
445 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ce6b0ac095 | |||
| 420bb06988 | |||
| 20566f8acf | |||
| 1d5f69704a | |||
| 0da664299e | |||
| 6e8fb2b457 | |||
| d1c72a4ff3 | |||
| 0bf05392e4 | |||
| 7ecef0c045 | |||
| 33ca329253 | |||
| 01fa4770cb | |||
| b76257c49c | |||
| e2fbf22f38 | |||
| 134432d029 | |||
| 8d4d6e80b8 | |||
| 85e6ef3dca | |||
| 60f1467229 | |||
| 1757242382 | |||
| 55df7bb9c4 | |||
| 686b8acd38 | |||
| a5f9df6170 | |||
| 27f61a870a | |||
| a48e8d1c5c | |||
| b80f74bccd | |||
| 1e768734ef | |||
| 11c9cabeb3 | |||
| 3a14ab92f0 | |||
| 62d5f52398 | |||
| 2b4848566c | |||
| 7c825e877c | |||
| 8417c277e6 | |||
| 9cef423908 | |||
| e73c84490e | |||
| 6cfc807db0 | |||
| be366f8103 | |||
| 2d13bd796f | |||
| 523f8f80ca | |||
| b76fef9143 | |||
| e935af83d5 | |||
| d4e019ef42 | |||
| 2e738828c6 | |||
| fd7dc93778 | |||
| 3df407d9ee | |||
| 6fbba84725 | |||
| 37d20fa9cc | |||
| 410cd912ac | |||
| d234bbd861 | |||
| 3f68d96815 | |||
| 015cd895d2 | |||
| 5fa4b48d85 | |||
| 88a3783bbc | |||
| ea2254b9bd | |||
| 9a0c1f2605 | |||
| 008f26bb7d | |||
| 69e453ea0b | |||
| 88b0b608f4 | |||
| 19e3987ae3 | |||
| c72e91ddaf | |||
| c789dd5067 | |||
| 551949de29 | |||
| 80730ee87a | |||
| 71028adc9e | |||
| a2efebc06c | |||
| a4e277a86b | |||
| 494c80d8b1 | |||
| 02539bfdd3 | |||
| a0f05eaf67 | |||
| 72e26fc90b | |||
| 2261cfabf3 | |||
| c1afa2a0e3 | |||
| d28f454c6e | |||
| f471c80ac0 | |||
| be086d94b5 | |||
| ff719510b6 | |||
| 7b16116b67 | |||
| 8422b71204 | |||
| c9bc2a89f6 | |||
| 387a52a7ba | |||
| 96842d9742 | |||
| 8fcef5401b | |||
| 804c4c678d | |||
| 8558777ece | |||
| 77bb608878 | |||
| 2f574261a7 | |||
| 28c4a2c39e | |||
| bd36cb59b1 | |||
| 998358ada8 | |||
| 75a00e8821 | |||
| b5653464d2 | |||
| 0269cd0b3b | |||
| 88ed662fd4 | |||
| 7c180c86a4 | |||
| f811ac510e | |||
| 3e5054f357 | |||
| 3424a424a7 | |||
| 8eb8af8ef8 | |||
| 8eaf7fc497 | |||
| 3255709399 | |||
| 2dbea36b81 | |||
| e0b7009bff | |||
| 77fb5ec3cb | |||
| 7392bce5dc | |||
| 8188bbd35d | |||
| 80fdea7bfb | |||
| dc9f6ac709 | |||
| ba796bc23d | |||
| e0ecb4c44f | |||
| d4c05304e9 | |||
| ccdbd71517 | |||
| 454fce09c6 | |||
| be4b12b4c8 | |||
| 9fa629de31 | |||
| 78dd5774b3 | |||
| bb9a9cd0db | |||
| ab9d8fb3db | |||
| 6ce76af2be | |||
| 3199a4b2cb | |||
| 6a2d153c3d | |||
| bfd4ad9255 | |||
| 30224515fd | |||
| d7f3acfd05 | |||
| a9e9eeeb54 | |||
| 76fa52b313 | |||
| 67de8e6a3a | |||
| ff78998829 | |||
| 55786e2d29 | |||
| 20534a71b9 | |||
| 316b6feccb | |||
| 6c7417e0a2 | |||
| af89dc881e | |||
| 5714cef3de | |||
| 3d2c8e7cc5 | |||
| 772ffcc5e8 | |||
| 8c30bb3a9f | |||
| 89bc121d3f | |||
| 1cc9d7b647 | |||
| 50e494e8e9 | |||
| 19325930a2 | |||
| ac97f7e9a2 | |||
| 33f133b8b2 | |||
| 2e9995e80a | |||
| 53f676bf2e | |||
| 874d658d2a | |||
| d27c455ab7 | |||
| 9291431c61 | |||
| 2e5f51e9ae | |||
| 2aa7e466ed | |||
| 8c8b72d482 | |||
| bb9effa282 | |||
| 52e96bfa0f | |||
| 00ded65b7f | |||
| f738aa4234 | |||
| 6ff939451c | |||
| 32930cee01 | |||
| 3f45c76f48 | |||
| 1511baf12d | |||
| 20dd0816a6 | |||
| 41cd43ebc6 | |||
| 4a63899722 | |||
| c31ead493a | |||
| 7485733fba | |||
| e930b5d07b | |||
| 4543781153 | |||
| 1d5bfbb162 | |||
| 7045f7f92d | |||
| 5e7974f30b | |||
| 1079a888d3 | |||
| b1837abbc2 | |||
| 611e1a536c | |||
| c152ae1557 | |||
| de3020c1aa | |||
| f12c3fe06f | |||
| 754485c306 | |||
| 088448a8a1 | |||
| 6e35a09abd | |||
| 8fd11e8fdb | |||
| 40855103ad | |||
| 02041dbdb7 | |||
| 18ccc01501 | |||
| 1ff3f9c0da | |||
| 7a251248f1 | |||
| 971cbb94f6 | |||
| b53c961db2 | |||
| 9c40cbea76 | |||
| a8ce7e93cd | |||
| 4b02b74d6f | |||
| 67dd3afd92 | |||
| 7aca7fa0ec | |||
| c0564a1467 | |||
| b0a8984d3b | |||
| 0f451d6833 | |||
| c704d1f3b3 | |||
| e6d568fd49 | |||
| ee56509302 | |||
| bc5896b51f | |||
| 3224f5f422 | |||
| f9cd97edaa | |||
| e1ce3d46de | |||
| 294a8e9642 | |||
| 44fb6d9648 | |||
| 74c1ba1653 | |||
| 0cb39f049f | |||
| f7a3a8aa55 | |||
| cbc37eb006 | |||
| 097f45eeb3 | |||
| 4c5b3dd76f | |||
| ccf70590a4 | |||
| 3c709a27ac | |||
| 8554654ee9 | |||
| 59ac86cf6e | |||
| a4ecc9a187 | |||
| cc67c8b68e | |||
| b41f660fec | |||
| 00edcbbf64 | |||
| c530c70575 | |||
| 21840bb344 | |||
| 57bc23779d | |||
| 78e649f30a | |||
| eaa7a61f71 | |||
| 150a019b8d | |||
| 5dd1158025 | |||
| c60ca4a8d2 | |||
| e1b28f0805 | |||
| aeeaeb1eae | |||
| 76f87f9094 | |||
| 01e1c92813 | |||
| 22c0206451 | |||
| 5173c258b7 | |||
| ff8b892ebe | |||
| 7b0988cc19 | |||
| a4c79f09f8 | |||
| 7ec3d92215 | |||
| ac9fef784a | |||
| 4822bad4fb | |||
| d7dd90f073 | |||
| bbc19d1800 | |||
| 9ee9e61312 | |||
| f765137f3f | |||
| e160822b0f | |||
| c0e35b0126 | |||
| ac41ed629e | |||
| 8b5dfff2a1 | |||
| e77154bf7a | |||
| 5f5187e05c | |||
| 5db1728a3f | |||
| c7984ceed1 | |||
| 5d3571b7a3 | |||
| c1082b4474 | |||
| 14f16349c0 | |||
| aa7e01a085 | |||
| 484629734e | |||
| 444fca2250 | |||
| 7f17102c86 | |||
| e480998a4c | |||
| 5c642997fe | |||
| 5be5cd5ba5 | |||
| 1d55ed0599 | |||
| 4380aa9803 | |||
| 66e7f240da | |||
| f3e5816547 | |||
| 3d5931c259 | |||
| d510c74456 | |||
| 7154220d0b | |||
| d5155273df | |||
| 60dbe9d0a7 | |||
| f7d3f6b3f0 | |||
| 40fdd2aa74 | |||
| f39ed93ca0 | |||
| 541b2fabb4 | |||
| 067ad72f34 | |||
| 6c137e39c9 | |||
| f8c6cdb207 | |||
| f5de6a809d | |||
| e36b96fca6 | |||
| cd1738bdf6 | |||
| ebcd30fadc | |||
| 3c10a6bf94 | |||
| dc80fd9b15 | |||
| 5d21df9ac7 | |||
| 019e912d7f | |||
| 3479dca0d0 | |||
| 32e5cc4a5a | |||
| 268a9f18fa | |||
| 16a6186570 | |||
| 4b2fb6dd11 | |||
| 67d21bcd64 | |||
| 9b87126f0f | |||
| 1043b4de70 | |||
| 4bc5e7b8ff | |||
| 423b5205bf | |||
| fde288d9e8 | |||
| f2a2d85008 | |||
| 3a91b076e1 | |||
| 27bd608b53 | |||
| 966ba29084 | |||
| 3ea5b0193c | |||
| 97dd1b3b00 | |||
| fe0088d1ae | |||
| 342e1e22f8 | |||
| c9203047fc | |||
| a3a946ccd6 | |||
| 22564f34a9 | |||
| f939c24aa4 | |||
| be93fa747b | |||
| d7f4eeea2c | |||
| 6191f60025 | |||
| 82ccb0cedb | |||
| eb92e4413a | |||
| b0ba205532 | |||
| 4fa2cdf8d9 | |||
| ae30b23d34 | |||
| 1d3905bb71 | |||
| aa1e845f9a | |||
| fbcc69ec67 | |||
| 68b2de6dd7 | |||
| 20389babbc | |||
| f9899033aa | |||
| eb37b17486 | |||
| c428cad286 | |||
| 26486da27b | |||
| cabd0ed85e | |||
| f53e1a60d5 | |||
| ec694e4a99 | |||
| 81e076c924 | |||
| 04070ffc23 | |||
| 6941d6b863 | |||
| 3c88f68f16 | |||
| 82461da704 | |||
| 8e5d17c907 | |||
| 43d2143506 | |||
| 28b729acda | |||
| 584641236b | |||
| ca74897569 | |||
| 61987c85d2 | |||
| cfb75abeed | |||
| fd32706f0b | |||
| d1f90b7d44 | |||
| f09bc4a81a | |||
| 31b3aea282 | |||
| 2e1d236e8e | |||
| 065d06a98f | |||
| 63107566ec | |||
| 4f1dcea806 | |||
| 5da1a2c611 | |||
| 180a214e1f | |||
| bb417c6975 | |||
| 75c02475be | |||
| 2fd07211d9 | |||
| 128f3be596 | |||
| 810333dbb7 | |||
| e465358ec0 | |||
| 2954ed84a0 | |||
| b36cd8a68e | |||
| 8435daa598 | |||
| 38c943d564 | |||
| 8e89ec504f | |||
| a692ec1124 | |||
| 4e5f2c9587 | |||
| 1cc263acfb | |||
| 49c6534da6 | |||
| 02d3a3d7ec | |||
| 1dbe49243c | |||
| 2c12fb7ae8 | |||
| 829c6debbd | |||
| f2d3ed322e | |||
| d90e7db497 | |||
| 26f372a36a | |||
| b037777f83 | |||
| 35ce35b1e0 | |||
| e1517c2907 | |||
| ed5f88daa0 | |||
| 4afda646f0 | |||
| e782538777 | |||
| 4e86be86d9 | |||
| 6c8cfcd7c2 | |||
| 9fc7929665 | |||
| d590bf7d64 | |||
| c0f653340e | |||
| ac2bef083b | |||
| 42c7d0ca44 | |||
| 8a8afcfb24 | |||
| 5d259bb5aa | |||
| d2a24ed4bc | |||
| efd2f49484 | |||
| 9d4d6ccca5 | |||
| 218c894b5a | |||
| 0dec522542 | |||
| 7fa6708483 | |||
| 33af47c282 | |||
| 6b971e9e1b | |||
| 50107504a6 | |||
| 2cb0c9fea6 | |||
| dd7c2cc7f6 | |||
| 857ca14499 | |||
| f022b3fcde | |||
| 9470ff2dcc | |||
| d817a4fdb6 | |||
| 19635b06cf | |||
| 872776660b | |||
| 9644d4b00e | |||
| 04579d7ae6 | |||
| e9a9eb1779 | |||
| 9a1dddaccf | |||
| 4110ab5a82 | |||
| 5d1844e491 | |||
| 6a126d46ee | |||
| f834a0c84f | |||
| 9dfeb237e7 | |||
| b769ba2974 | |||
| fc1feb280f | |||
| bface83af7 | |||
| 9a89a16388 | |||
| 7649abf86a | |||
| b6ad97745d | |||
| 92028e191d | |||
| 7d4427a5d3 | |||
| 2bea800a37 | |||
| 4c1ff7deb7 | |||
| 347260f17b | |||
| 1086fba7da | |||
| 5a7cb129bb | |||
| b29d22e99b | |||
| 12cf102543 | |||
| 3d95730880 | |||
| c5d807dd58 | |||
| d40df79dce | |||
| 3cfa297b49 | |||
| e435769345 | |||
| 9a73877b3e | |||
| e2cd8d93f4 | |||
| afc6ec468f | |||
| 391838cfc3 | |||
| 36a11ded4f | |||
| f540ef2e06 | |||
| b061e0f859 | |||
| 4972fbbc7b | |||
| 1f318de812 | |||
| 0ceeadd75b | |||
| b9dad32707 | |||
| d1cf698b45 | |||
| 9dba3f9c58 | |||
| 8fbbe40300 | |||
| f73c925ad9 | |||
| b7fb4c5950 | |||
| fed49bb98b |
@@ -1,6 +1,8 @@
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- 1.9.2
|
||||
- rbx-2.0
|
||||
- 1.9.3
|
||||
notifications:
|
||||
disabled: true
|
||||
before_install:
|
||||
- gem uninstall ffi -a
|
||||
- sudo apt-get install -y asciidoc
|
||||
@@ -1,6 +1,8 @@
|
||||
gollum -- A wiki built on top of Git
|
||||
====================================
|
||||
|
||||
[](http://travis-ci.org/github/gollum)
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Gollum is a simple wiki system built on top of Git that powers GitHub Wikis.
|
||||
@@ -32,7 +34,7 @@ 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`
|
||||
* [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`
|
||||
* [Markdown](http://daringfireball.net/projects/markdown/) -- `gem install redcarpet`
|
||||
* [GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/) -- `gem install github-markdown`
|
||||
@@ -59,6 +61,7 @@ utility, you can run it like so:
|
||||
|
||||
$ gollum --help
|
||||
|
||||
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).
|
||||
|
||||
## REPO STRUCTURE
|
||||
|
||||
@@ -106,6 +109,13 @@ are named `_Sidebar.ext` where the extension is one of the supported formats.
|
||||
Sidebars affect all pages in their directory and any subdirectories that do not
|
||||
have a sidebar file of their own.
|
||||
|
||||
## HEADER FILES
|
||||
|
||||
Header files allow you to add a simple header to your wiki. Header files must
|
||||
be named `_Header.ext` where the extension is one of the supported formats.
|
||||
Like sidebars, headers affect all pages in their directory and any
|
||||
subdirectories that do not have a header file of their own.
|
||||
|
||||
## FOOTER FILES
|
||||
|
||||
Footer files allow you to add a simple footer to your wiki. Footer files must
|
||||
@@ -113,7 +123,6 @@ be named `_Footer.ext` where the extension is one of the supported formats.
|
||||
Like sidebars, footers affect all pages in their directory and any
|
||||
subdirectories that do not have a footer file of their own.
|
||||
|
||||
|
||||
## HTML SANITIZATION
|
||||
|
||||
For security and compatibility reasons Gollum wikis may not contain custom CSS
|
||||
@@ -282,6 +291,22 @@ wiki page, simply preface the link with a single quote (like in LISP):
|
||||
|
||||
This is useful for writing about the link syntax in your wiki pages.
|
||||
|
||||
## TABLE OF CONTENTS
|
||||
|
||||
Gollum has a special tag to insert a table of contents (new in v2.1)
|
||||
|
||||
'[[_TOC_]]
|
||||
|
||||
This tag is case sensitive, use all upper case. The TOC tag can be inserted
|
||||
into the `_Header`, `_Footer` or `_Sidebar` files too.
|
||||
|
||||
There is also a wiki option `:universal_toc` which will display a
|
||||
table of contents at the top of all your wiki pages if it is enabled.
|
||||
The `:universal_toc` is not enabled by default. To set the option,
|
||||
add the option to the `:wiki_options` hash before starting the
|
||||
frontend app:
|
||||
|
||||
Precious::App.set(:wiki_options, {:universal_toc => true})
|
||||
|
||||
## SYNTAX HIGHLIGHTING
|
||||
|
||||
@@ -311,6 +336,7 @@ backticks.
|
||||
|
||||
## MATHEMATICAL EQUATIONS
|
||||
|
||||
|
||||
Page files may contain mathematic equations in TeX syntax that will be nicely
|
||||
typeset into the expected output. A block-style equation is delimited by `\[`
|
||||
and `\]`. For example:
|
||||
@@ -322,6 +348,13 @@ inline with regular text. For example:
|
||||
|
||||
The Pythagorean theorem is \( a^2 + b^2 = c^2 \).
|
||||
|
||||
### INSTALLATION REQUIREMENTS
|
||||
|
||||
In order to get the mathematical equations rendering to work, you need the following binaries:
|
||||
|
||||
* LaTex, TeTex or MacTex/BasicTeX (pdflatex)
|
||||
* Netpbm (pnmcrop, pnmpad, pnmscale, ppmtopgm, pnmgamma, pnmtopng)
|
||||
* Ghostscript (gs)
|
||||
|
||||
## SEQUENCE DIAGRAMS
|
||||
|
||||
@@ -383,6 +416,11 @@ Get the footer (if any) for a given page:
|
||||
|
||||
page.footer
|
||||
# => <Gollum::Page>
|
||||
|
||||
Get the header (if any) for a given page:
|
||||
|
||||
page.header
|
||||
# => <Gollum::Page>
|
||||
|
||||
Get a list of versions for a given page:
|
||||
|
||||
@@ -454,9 +492,14 @@ like Rack::Auth, OmniAuth, etc.
|
||||
require 'gollum/frontend/app'
|
||||
|
||||
gollum_path = File.expand_path(File.dirname(__FILE__)) # CHANGE THIS TO POINT TO YOUR OWN WIKI REPO
|
||||
Precious::App.set(:gollum_path, gollum_path)
|
||||
Precious::App.set(:default_markup, :markdown) # set your favorite markup language
|
||||
Precious::App.set(:wiki_options, {:universal_toc => false})
|
||||
run Precious::App
|
||||
|
||||
## Windows Filename Validation
|
||||
Note that filenames on windows must not contain any of the following characters `\ / : * ? " < > |`. See [this support article](http://support.microsoft.com/kb/177506) for details.
|
||||
|
||||
## CONTRIBUTE
|
||||
|
||||
If you'd like to hack on Gollum, start by forking my repo on GitHub:
|
||||
@@ -477,7 +520,16 @@ your changes merged back into core is as follows:
|
||||
1. Send a pull request to the github/gollum project.
|
||||
|
||||
## RELEASING
|
||||
|
||||
Update VERSION in lib/gollum.rb
|
||||
$ rake gemspec
|
||||
$ git tag vX.Y.Z
|
||||
$ git push origin vX.Y.Z
|
||||
$ gem build gollum.gemspec
|
||||
$ gem push gollum-X.Y.Z.gem
|
||||
|
||||
## BUILDING THE GEM FROM MASTER
|
||||
$ gem uninstall -aix gollum
|
||||
$ git clone https://github.com/github/gollum.git
|
||||
$ cd gollum
|
||||
gollum$ rake build
|
||||
gollum$ gem install pkg/gollum*.gem
|
||||
|
||||
@@ -99,7 +99,7 @@ task :build => :gemspec do
|
||||
sh "mv #{gem_file} pkg"
|
||||
end
|
||||
|
||||
desc 'Validate gemspec'
|
||||
desc 'Update gemspec'
|
||||
task :gemspec => :validate do
|
||||
# read spec file and split out manifest section
|
||||
spec = File.read(gemspec_file)
|
||||
|
||||
@@ -49,9 +49,25 @@ opts = OptionParser.new do |opts|
|
||||
wiki_options[:page_file_dir] = path
|
||||
end
|
||||
|
||||
opts.on("--base-path [PATH]", "Specify the base path.") do |path|
|
||||
wiki_options[:base_path] = path
|
||||
end
|
||||
|
||||
opts.on("--gollum-path [PATH]", "Specify the gollum path.") do |path|
|
||||
wiki_options[:gollum_path] = path
|
||||
end
|
||||
|
||||
opts.on("--ref [REF]", "Specify the repository ref to use (default: master).") do |ref|
|
||||
wiki_options[:ref] = ref
|
||||
end
|
||||
|
||||
opts.on("--no-live-preview", "Disables livepreview.") do
|
||||
wiki_options[:live_preview] = false
|
||||
end
|
||||
|
||||
opts.on("--mathjax", "Enables mathjax.") do
|
||||
options['mathjax'] = true
|
||||
end
|
||||
end
|
||||
|
||||
# Read command line options into `options` hash
|
||||
@@ -63,7 +79,10 @@ rescue OptionParser::InvalidOption
|
||||
exit
|
||||
end
|
||||
|
||||
gollum_path = ARGV[0] || Dir.pwd
|
||||
# --gollum-path wins over ARGV[0]
|
||||
gollum_path = wiki_options[:gollum_path] ?
|
||||
wiki_options[:gollum_path] :
|
||||
ARGV[0] || Dir.pwd
|
||||
|
||||
if options['irb']
|
||||
require 'irb'
|
||||
|
||||
@@ -2,10 +2,11 @@ Gem::Specification.new do |s|
|
||||
s.specification_version = 2 if s.respond_to? :specification_version=
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.rubygems_version = '1.3.5'
|
||||
s.required_ruby_version = ">= 1.8.7"
|
||||
|
||||
s.name = 'gollum'
|
||||
s.version = '1.4.3'
|
||||
s.date = '2012-04-25'
|
||||
s.version = '2.1.7'
|
||||
s.date = '2012-08-25'
|
||||
s.rubyforge_project = 'gollum'
|
||||
|
||||
s.summary = "A simple, Git-powered wiki."
|
||||
@@ -22,7 +23,7 @@ Gem::Specification.new do |s|
|
||||
s.rdoc_options = ["--charset=UTF-8"]
|
||||
s.extra_rdoc_files = %w[README.md LICENSE]
|
||||
|
||||
s.add_dependency('grit', "~> 2.4.1")
|
||||
s.add_dependency('grit', "~> 2.5.0")
|
||||
s.add_dependency('github-markup', [">= 0.7.0", "< 1.0.0"])
|
||||
s.add_dependency('github-markdown')
|
||||
s.add_dependency('pygments.rb', "~> 0.2.0")
|
||||
@@ -31,13 +32,15 @@ Gem::Specification.new do |s|
|
||||
s.add_dependency('mustache', [">= 0.11.2", "< 1.0.0"])
|
||||
s.add_dependency('sanitize', "~> 2.0.0")
|
||||
s.add_dependency('nokogiri', "~> 1.4")
|
||||
s.add_dependency('useragent', "~> 0.4.9")
|
||||
s.add_dependency('stringex', "~> 1.4.0")
|
||||
|
||||
s.add_development_dependency('RedCloth')
|
||||
s.add_development_dependency('mocha')
|
||||
s.add_development_dependency('org-ruby', '~>0.6.2')
|
||||
s.add_development_dependency('org-ruby', '~> 0.7.0')
|
||||
s.add_development_dependency('shoulda')
|
||||
s.add_development_dependency('rack-test')
|
||||
s.add_development_dependency('wikicloth', '~> 0.6.3')
|
||||
s.add_development_dependency('wikicloth', '~>0.8.0')
|
||||
s.add_development_dependency('rake', '~> 0.9.2')
|
||||
|
||||
# = MANIFEST =
|
||||
@@ -55,13 +58,26 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/blob_entry.rb
|
||||
lib/gollum/committer.rb
|
||||
lib/gollum/file.rb
|
||||
lib/gollum/file_view.rb
|
||||
lib/gollum/frontend/app.rb
|
||||
lib/gollum/frontend/helpers.rb
|
||||
lib/gollum/frontend/public/gollum/css/_styles.css
|
||||
lib/gollum/frontend/public/gollum/css/dialog.css
|
||||
lib/gollum/frontend/public/gollum/css/editor.css
|
||||
lib/gollum/frontend/public/gollum/css/gollum.css
|
||||
lib/gollum/frontend/public/gollum/css/ie7.css
|
||||
lib/gollum/frontend/public/gollum/css/template.css
|
||||
lib/gollum/frontend/public/gollum/images/dirty-shade.png
|
||||
lib/gollum/frontend/public/gollum/images/fileview/document.png
|
||||
lib/gollum/frontend/public/gollum/images/fileview/folder-horizontal.png
|
||||
lib/gollum/frontend/public/gollum/images/fileview/toggle-small-expand.png
|
||||
lib/gollum/frontend/public/gollum/images/fileview/toggle-small.png
|
||||
lib/gollum/frontend/public/gollum/images/icon-sprite.png
|
||||
lib/gollum/frontend/public/gollum/images/para.png
|
||||
lib/gollum/frontend/public/gollum/images/pin-16.png
|
||||
lib/gollum/frontend/public/gollum/images/pin-20.png
|
||||
lib/gollum/frontend/public/gollum/images/pin-24.png
|
||||
lib/gollum/frontend/public/gollum/images/pin-32.png
|
||||
lib/gollum/frontend/public/gollum/javascript/editor/gollum.editor.js
|
||||
lib/gollum/frontend/public/gollum/javascript/editor/langs/asciidoc.js
|
||||
lib/gollum/frontend/public/gollum/javascript/editor/langs/creole.js
|
||||
@@ -73,24 +89,364 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/frontend/public/gollum/javascript/gollum.dialog.js
|
||||
lib/gollum/frontend/public/gollum/javascript/gollum.js
|
||||
lib/gollum/frontend/public/gollum/javascript/gollum.placeholder.js
|
||||
lib/gollum/frontend/public/gollum/javascript/jquery-1.7.2.min.js
|
||||
lib/gollum/frontend/public/gollum/javascript/jquery.color.js
|
||||
lib/gollum/frontend/public/gollum/javascript/jquery.js
|
||||
lib/gollum/frontend/public/gollum/javascript/mousetrap.min.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/css/custom.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/images/cancel_24.png
|
||||
lib/gollum/frontend/public/gollum/livepreview/images/lr_24.png
|
||||
lib/gollum/frontend/public/gollum/livepreview/images/save_24.png
|
||||
lib/gollum/frontend/public/gollum/livepreview/images/savecomment_24.png
|
||||
lib/gollum/frontend/public/gollum/livepreview/index.html
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/ace.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/anchor.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/anchor_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/background_tokenizer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/background_tokenizer_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/commands/command_manager.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/commands/command_manager_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/commands/default_commands.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/commands/multi_select_commands.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/config.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/css/codefolding-fold-button-states.png
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/css/editor.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/css/expand-marker.png
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/document.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/document_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/edit_session.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/edit_session/bracket_match.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/edit_session/fold.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/edit_session/fold_line.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/edit_session/folding.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/edit_session_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/editor.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/editor_change_document_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/editor_highlight_selected_word_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/editor_navigation_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/editor_text_edit_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/ext/static.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/ext/static_highlight.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/ext/static_highlight_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/ext/textarea.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/emacs.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/hash_handler.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/keybinding.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/state_handler.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/textinput.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/commands.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/maps/aliases.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/maps/motions.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/maps/operators.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/maps/util.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/keyboard/vim/registers.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/layer/cursor.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/layer/gutter.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/layer/marker.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/layer/text.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/layer/text_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/browser_focus.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/dom.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/es5-shim.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/event.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/event_emitter.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/event_emitter_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/fixoldbrowsers.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/keys.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/lang.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/net.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/oop.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/regexp.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/lib/useragent.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/cstyle.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/html.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/xml.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/behaviour/xquery.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/c9search.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/c9search_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/c_cpp.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/c_cpp_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/clojure.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/clojure_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/coffee-script.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/helpers.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/lexer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/nodes.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/parser.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/parser_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/rewriter.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee/scope.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee_highlight_rules_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coffee_worker.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coldfusion.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coldfusion_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/coldfusion_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/csharp.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/csharp_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/css.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/css/csslint.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/css_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/css_highlight_rules_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/css_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/css_worker.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/css_worker_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/diff.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/diff_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/doc_comment_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/c9search.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/coffee.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/coffee_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/cstyle.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/cstyle_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/diff.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/fold_mode.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/html.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/html_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/mixed.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/pythonic.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/pythonic_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/xml.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/folding/xml_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/golang.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/golang_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/groovy.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/groovy_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/haxe.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/haxe_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/html.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/html_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/html_highlight_rules_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/html_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/java.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/java_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/javascript.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_highlight_rules_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_worker.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/javascript_worker_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/json.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/json/json_parse.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/json_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/json_worker.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/json_worker_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/jsx.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/jsx_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/latex.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/latex_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/less.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/less_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/liquid.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/liquid_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/liquid_highlight_rules_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/lua.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/lua_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/luapage.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/luapage_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/markdown.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/markdown_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/matching_brace_outdent.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/matching_parens_outdent.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/ocaml.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/ocaml_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/perl.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/perl_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/pgsql.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/pgsql_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/php.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/php_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/powershell.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/powershell_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/python.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/python_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/python_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/ruby.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/ruby_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/ruby_highlight_rules_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/scad.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/scad_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/scala.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/scala_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/scss.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/scss_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/sh.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/sh_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/sql.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/sql_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/svg.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/svg_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/text.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/text_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/text_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/textile.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/textile_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xml.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xml_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xml_highlight_rules_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xml_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xml_util.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/Position.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/Readme.md
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/StringLexer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/XMLLexer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/XQDTLexer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/XQDTParser.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/XQueryLexer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/XQueryParser.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/XQuerySemanticHighlighter.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/antlr3-all.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery/xquery.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/xquery_worker.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/yaml.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mode/yaml_highlight_rules.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/model/editor.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mouse/default_gutter_handler.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mouse/default_handlers.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mouse/dragdrop.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mouse/fold_handler.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mouse/mouse_event.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mouse/mouse_handler.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/mouse/multi_select_handler.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/multi_select.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/multi_select_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/narcissus/definitions.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/narcissus/lexer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/narcissus/options.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/narcissus/parser.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/placeholder.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/placeholder_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/range.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/range_list.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/range_list_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/range_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/renderloop.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/requirejs/text.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/scrollbar.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/search.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/search_highlight.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/search_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/selection.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/selection_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/split.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/all.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/all_browser.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/assertions.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/asyncjs/assert.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/asyncjs/async.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/asyncjs/index.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/asyncjs/test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/asyncjs/utils.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/benchmark.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/mockdom.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/mockrenderer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/test/tests.html
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/chrome.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/chrome.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/clouds.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/clouds.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/clouds_midnight.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/clouds_midnight.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/cobalt.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/cobalt.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/crimson_editor.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/crimson_editor.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/dawn.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/dawn.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/dreamweaver.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/dreamweaver.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/eclipse.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/eclipse.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/github.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/github.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/idle_fingers.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/idle_fingers.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/kr_theme.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/kr_theme.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/merbivore.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/merbivore.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/merbivore_soft.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/merbivore_soft.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/mono_industrial.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/mono_industrial.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/monokai.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/monokai.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/pastel_on_dark.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/pastel_on_dark.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/solarized_dark.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/solarized_dark.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/solarized_light.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/solarized_light.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/textmate.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/textmate.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow_night.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow_night.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow_night_blue.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow_night_blue.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow_night_bright.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow_night_bright.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow_night_eighties.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/tomorrow_night_eighties.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/twilight.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/twilight.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/vibrant_ink.css
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/theme/vibrant_ink.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/token_iterator.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/token_iterator_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/tokenizer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/undomanager.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/unicode.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/virtual_renderer.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/virtual_renderer_test.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/worker/jshint.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/worker/jslint.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/worker/mirror.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/worker/worker.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/worker/worker_client.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/ace/lib/ace/worker/worker_sourcemint.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/jquery.ba-throttle-debounce.min.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/livepreview.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/md_sundown.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/requirejs.min.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/js/sundown.js
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/ace/LICENSE.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/bootstraponline_gollum/LICENSE.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/debounce/LICENSE-MIT.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/gollum/LICENSE.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/jquery/MIT-LICENSE.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/licenses.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/notepages/LICENSE.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/requirejs/LICENSE.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/retina_display_icon_set/by_sa_3.0_unported_legalcode.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/sizzle/LICENSE.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/licenses/sundown/sundown.txt
|
||||
lib/gollum/frontend/public/gollum/livepreview/readme.md
|
||||
lib/gollum/frontend/templates/compare.mustache
|
||||
lib/gollum/frontend/templates/create.mustache
|
||||
lib/gollum/frontend/templates/edit.mustache
|
||||
lib/gollum/frontend/templates/editor.mustache
|
||||
lib/gollum/frontend/templates/error.mustache
|
||||
lib/gollum/frontend/templates/file_view.mustache
|
||||
lib/gollum/frontend/templates/history.mustache
|
||||
lib/gollum/frontend/templates/layout.mustache
|
||||
lib/gollum/frontend/templates/page.mustache
|
||||
lib/gollum/frontend/templates/pages.mustache
|
||||
lib/gollum/frontend/templates/search.mustache
|
||||
lib/gollum/frontend/templates/searchbar.mustache
|
||||
lib/gollum/frontend/uri_encode_component.rb
|
||||
lib/gollum/frontend/views/compare.rb
|
||||
lib/gollum/frontend/views/create.rb
|
||||
lib/gollum/frontend/views/edit.rb
|
||||
lib/gollum/frontend/views/editable.rb
|
||||
lib/gollum/frontend/views/error.rb
|
||||
lib/gollum/frontend/views/file_view.rb
|
||||
lib/gollum/frontend/views/has_page.rb
|
||||
lib/gollum/frontend/views/history.rb
|
||||
lib/gollum/frontend/views/layout.rb
|
||||
lib/gollum/frontend/views/page.rb
|
||||
@@ -104,6 +460,9 @@ Gem::Specification.new do |s|
|
||||
lib/gollum/tex.rb
|
||||
lib/gollum/web_sequence_diagram.rb
|
||||
lib/gollum/wiki.rb
|
||||
licenses/css_tree_menu_thecssninja/license.txt
|
||||
licenses/licenses.txt
|
||||
licenses/unity_asset_pool/COPYRIGHT
|
||||
templates/formatting.html
|
||||
test/examples/empty.git/HEAD
|
||||
test/examples/empty.git/config
|
||||
@@ -133,29 +492,52 @@ Gem::Specification.new do |s|
|
||||
test/examples/lotr.git/logs/refs/heads/master
|
||||
test/examples/lotr.git/objects/06/131480411710c92a82fe2d1e76932c70feb2e5
|
||||
test/examples/lotr.git/objects/0a/de1e2916346d4c1f2fb63b863fd3c16808fe44
|
||||
test/examples/lotr.git/objects/0d/c9016ca928c78d5421a99a53b379b53929221e
|
||||
test/examples/lotr.git/objects/0e/d8cbe0a25235bd867e65193c7d837c66b328ef
|
||||
test/examples/lotr.git/objects/12/629d666c5e3178f82f533f543d61b53dc78c0b
|
||||
test/examples/lotr.git/objects/1c/79ddc69707f7b164bc2ea58beb5d8965ff6bd0
|
||||
test/examples/lotr.git/objects/1d/b89ebba7e2c14d93b94ff98cfa3708a4f0d4e3
|
||||
test/examples/lotr.git/objects/24/49c2681badfd3c189e8ed658dacffe8ba48fe5
|
||||
test/examples/lotr.git/objects/25/4bdc1ba27d8b8a794538a8522d9a2b56ec2dd9
|
||||
test/examples/lotr.git/objects/27/680b0fce1abfbc528e7aa53d92645852d52eb6
|
||||
test/examples/lotr.git/objects/2c/b9156ad383914561a8502fc70f5a1d887e48ad
|
||||
test/examples/lotr.git/objects/45/3b250f979c7bd6dfb62640c944c982ae6721ee
|
||||
test/examples/lotr.git/objects/45/f319ee12f2b551b901b22e72602963c366fff1
|
||||
test/examples/lotr.git/objects/46/a697caf435815bb07bbce947fc2d58be15f087
|
||||
test/examples/lotr.git/objects/4c/45c2b4e297a726c3d3f66886f35373e48fe1c5
|
||||
test/examples/lotr.git/objects/4e/023f460ce466e154ca09d8774c79ad5a53fc15
|
||||
test/examples/lotr.git/objects/5d/cac289a8603188d2c5caf481dcba2985126aaa
|
||||
test/examples/lotr.git/objects/60/f12f4254f58801b9ee7db7bca5fa8aeefaa56b
|
||||
test/examples/lotr.git/objects/62/9aa678272b017a4d136d35e77ac94d80b08dc2
|
||||
test/examples/lotr.git/objects/6e/48abfc56565574859e081ee58eae655d48cf71
|
||||
test/examples/lotr.git/objects/71/4323c104239440a5c66ab12a67ed07a83c404f
|
||||
test/examples/lotr.git/objects/7b/60c5a20a501a70f2317fa0ef763e1e2ce22d6b
|
||||
test/examples/lotr.git/objects/7d/981cd984ad589e3cf00d8122170c6f7d685979
|
||||
test/examples/lotr.git/objects/84/0ec5b1ba1320e8ec443f28f99566f615d5af10
|
||||
test/examples/lotr.git/objects/93/6b83ee0dd8837adb82511e40d5e4ebe59bb675
|
||||
test/examples/lotr.git/objects/94/523d7ae48aeba575099dd12926420d8fd0425d
|
||||
test/examples/lotr.git/objects/94/9a9cc3119b9c98817f375e976d2bb5e2a42809
|
||||
test/examples/lotr.git/objects/96/97dc65e095658bbd1b8e8678e08881e86d32f1
|
||||
test/examples/lotr.git/objects/9b/e95b960ac388d4e7db55f610f828e9c31344e6
|
||||
test/examples/lotr.git/objects/a3/1ca2a7c352c92531a8b99815d15843b259e814
|
||||
test/examples/lotr.git/objects/a6/59b3763b822dd97544621fd0beef162ea37b14
|
||||
test/examples/lotr.git/objects/a8/ad3c09dd842a3517085bfadd37718856dee813
|
||||
test/examples/lotr.git/objects/aa/b61fe89d56f8614c0a8151da34f939dcedfa68
|
||||
test/examples/lotr.git/objects/b0/de6e794dfdc7ef3400e894225bfe23308aae5c
|
||||
test/examples/lotr.git/objects/b1/6b3d9fad9d78e5a669e7f33d94c96da374eccd
|
||||
test/examples/lotr.git/objects/bc/4b5fc0ce2c2ba3acef6647e4f67256ee45ab60
|
||||
test/examples/lotr.git/objects/c3/b43e9f08966b088e7a0192e436b7a884542e05
|
||||
test/examples/lotr.git/objects/c9/6a7645db5d4c76389e77cd103ef3ed77d81e4c
|
||||
test/examples/lotr.git/objects/ca/7355dc497e9729fbaf0c0e3f424b86afef5614
|
||||
test/examples/lotr.git/objects/cf/ea406f5f77afc7fb673a43e97721234385b1bd
|
||||
test/examples/lotr.git/objects/d5/29304506d37f544675244c335d85cab5d29966
|
||||
test/examples/lotr.git/objects/dc/596d6b2dd89ab05c66f4abd7d5eb706bc17f19
|
||||
test/examples/lotr.git/objects/ec/da3205bee14520aab5a7bb307392064b938e83
|
||||
test/examples/lotr.git/objects/f4/84ebb1f40f8eb20d1bcd8d1d71934d2b8ae961
|
||||
test/examples/lotr.git/objects/fa/e7ef5344202bba4129abdc13060d9297d99465
|
||||
test/examples/lotr.git/objects/fb/c5dd7d807707b4a0a97c1182fecfef1eced5df
|
||||
test/examples/lotr.git/objects/fc/3eee516ff72dc9099ba00d4611eb02e5c9e634
|
||||
test/examples/lotr.git/objects/ff/6f7de62644369380ba73b4e4297c1a2d6f0b66
|
||||
test/examples/lotr.git/objects/info/packs
|
||||
test/examples/lotr.git/objects/pack/pack-dcbeaf3f6ff6c5eb08ea2b0a2d83626e8763546b.idx
|
||||
test/examples/lotr.git/objects/pack/pack-dcbeaf3f6ff6c5eb08ea2b0a2d83626e8763546b.pack
|
||||
@@ -184,10 +566,13 @@ Gem::Specification.new do |s|
|
||||
test/examples/revert.git/info/exclude
|
||||
test/examples/revert.git/logs/HEAD
|
||||
test/examples/revert.git/logs/refs/heads/master
|
||||
test/examples/revert.git/objects/10/2685c42018f802557f05db171f44443e8dacab
|
||||
test/examples/revert.git/objects/20/2ced67cea93c7b6bd2928aa1daef8d1d55a20d
|
||||
test/examples/revert.git/objects/41/76394bfa11222363c66ce7e84b5f154095b6d9
|
||||
test/examples/revert.git/objects/6a/69f92020f5df77af6e8813ff1232493383b708
|
||||
test/examples/revert.git/objects/8e/83f898e5e16ae400db59dda1017acad540f3aa
|
||||
test/examples/revert.git/objects/b4/785957bc986dc39c629de9fac9df46972c00fc
|
||||
test/examples/revert.git/objects/ed/6c9f63b98acf73c25b5ffbb38da557d3682023
|
||||
test/examples/revert.git/objects/f4/03b791119f8232b7cb0ba455c624ac6435f433
|
||||
test/examples/revert.git/objects/info/packs
|
||||
test/examples/revert.git/objects/pack/pack-a561f8437234f74d0bacb9e0eebe52d207f5770d.idx
|
||||
@@ -208,14 +593,24 @@ Gem::Specification.new do |s|
|
||||
test/examples/yubiwa.git/objects/ac/e97abf2b177815a1972d7db22f229f58c83309
|
||||
test/examples/yubiwa.git/objects/b1/f443863a4816628807fbf86141ebef055dda34
|
||||
test/examples/yubiwa.git/refs/heads/master
|
||||
test/file_view/1_file.txt
|
||||
test/file_view/1_file_1_folder.txt
|
||||
test/file_view/1_folder.txt
|
||||
test/file_view/2_files_2_folders.txt
|
||||
test/file_view/2_files_2_folders_1_root.txt
|
||||
test/file_view/nested_folders.txt
|
||||
test/helper.rb
|
||||
test/test_app.rb
|
||||
test/test_app_helpers.rb
|
||||
test/test_committer.rb
|
||||
test/test_file.rb
|
||||
test/test_file_view.rb
|
||||
test/test_git_access.rb
|
||||
test/test_markup.rb
|
||||
test/test_page.rb
|
||||
test/test_page_revert.rb
|
||||
test/test_pages_view.rb
|
||||
test/test_unicode.rb
|
||||
test/test_wiki.rb
|
||||
]
|
||||
# = MANIFEST =
|
||||
|
||||
@@ -15,13 +15,14 @@ require File.expand_path('../gollum/blob_entry', __FILE__)
|
||||
require File.expand_path('../gollum/wiki', __FILE__)
|
||||
require File.expand_path('../gollum/page', __FILE__)
|
||||
require File.expand_path('../gollum/file', __FILE__)
|
||||
require File.expand_path('../gollum/file_view', __FILE__)
|
||||
require File.expand_path('../gollum/markup', __FILE__)
|
||||
require File.expand_path('../gollum/sanitization', __FILE__)
|
||||
require File.expand_path('../gollum/tex', __FILE__)
|
||||
require File.expand_path('../gollum/web_sequence_diagram', __FILE__)
|
||||
|
||||
module Gollum
|
||||
VERSION = '1.4.3'
|
||||
VERSION = '2.1.7'
|
||||
|
||||
def self.assets_path
|
||||
::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__))
|
||||
|
||||
@@ -48,6 +48,18 @@ module Gollum
|
||||
page
|
||||
end
|
||||
|
||||
# Gets a File instance for this blob.
|
||||
#
|
||||
# wiki - Gollum::Wiki instance for the Gollum::File
|
||||
#
|
||||
# Returns a Gollum::File instance.
|
||||
def file(wiki, commit)
|
||||
blob = self.blob(wiki.repo)
|
||||
file = wiki.file_class.new(wiki).populate(blob, self.dir)
|
||||
file.version = commit
|
||||
file
|
||||
end
|
||||
|
||||
def inspect
|
||||
%(#<Gollum::BlobEntry #{@sha} #{@path}>)
|
||||
end
|
||||
@@ -75,4 +87,4 @@ module Gollum
|
||||
dir
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -91,7 +91,11 @@ module Gollum
|
||||
fullpath = ::File.join(*[@wiki.page_file_dir, dir, path].compact)
|
||||
fullpath = fullpath[1..-1] if fullpath =~ /^\//
|
||||
|
||||
if index.current_tree && tree = index.current_tree / dir
|
||||
if index.current_tree && tree = index.current_tree / (@wiki.page_file_dir || '/')
|
||||
tree = tree / dir unless tree.nil?
|
||||
end
|
||||
|
||||
if tree
|
||||
downpath = path.downcase.sub(/\.\w+$/, '')
|
||||
|
||||
tree.blobs.each do |blob|
|
||||
@@ -104,6 +108,8 @@ module Gollum
|
||||
end
|
||||
end
|
||||
|
||||
fullpath = fullpath.force_encoding('ascii-8bit') if fullpath.respond_to?(:force_encoding)
|
||||
|
||||
index.add(fullpath, @wiki.normalize(data))
|
||||
end
|
||||
|
||||
@@ -129,6 +135,8 @@ module Gollum
|
||||
::File.join(dir, @wiki.page_file_name(name, format))
|
||||
end
|
||||
|
||||
path = path.force_encoding('ascii-8bit') if path.respond_to?(:force_encoding)
|
||||
|
||||
Dir.chdir(::File.join(@wiki.repo.path, '..')) do
|
||||
if file_path_scheduled_for_deletion?(index.tree, path)
|
||||
@wiki.repo.git.rm({'f' => true}, '--', path)
|
||||
@@ -212,6 +220,7 @@ module Gollum
|
||||
|
||||
# Proxies methods t
|
||||
def method_missing(name, *args)
|
||||
args.map! { |item| item.respond_to?(:force_encoding) ? item.force_encoding('ascii-8bit') : item }
|
||||
index.send(name, *args)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,6 +19,7 @@ module Gollum
|
||||
def name
|
||||
@blob && @blob.name
|
||||
end
|
||||
alias filename name
|
||||
|
||||
# Public: The raw contents of the page.
|
||||
#
|
||||
@@ -28,7 +29,7 @@ module Gollum
|
||||
end
|
||||
|
||||
# Public: The Grit::Commit version of the file.
|
||||
attr_reader :version
|
||||
attr_accessor :version
|
||||
|
||||
# Public: The String path of the file.
|
||||
attr_reader :path
|
||||
@@ -38,6 +39,18 @@ module Gollum
|
||||
@blob.mime_type
|
||||
end
|
||||
|
||||
# Populate the File with information from the Blob.
|
||||
#
|
||||
# blob - The Grit::Blob that contains the info.
|
||||
# path - The String directory path of the file.
|
||||
#
|
||||
# Returns the populated Gollum::File.
|
||||
def populate(blob, path=nil)
|
||||
@blob = blob
|
||||
@path = "#{path}/#{blob.name}"[1..-1]
|
||||
self
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Internal Methods
|
||||
@@ -61,4 +74,4 @@ module Gollum
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
module Gollum
|
||||
=begin
|
||||
FileView requires that:
|
||||
- All files in root dir are processed first
|
||||
- Then all the folders are sorted and processed
|
||||
=end
|
||||
class FileView
|
||||
def initialize pages
|
||||
@pages = pages
|
||||
end
|
||||
|
||||
def enclose_tree string
|
||||
%Q(<ol class="tree">\n) + string + %Q(</ol>)
|
||||
end
|
||||
|
||||
def new_page page
|
||||
name = page.name
|
||||
url = url_for_page page
|
||||
%Q( <li class="file"><a href="#{url}">#{name}</a></li>\n)
|
||||
end
|
||||
|
||||
def new_folder folder_path
|
||||
new_sub_folder folder_path
|
||||
end
|
||||
|
||||
def new_sub_folder path
|
||||
<<-HTML
|
||||
<li>
|
||||
<label>#{path}</label> <input type="checkbox" checked />
|
||||
<ol>
|
||||
HTML
|
||||
end
|
||||
|
||||
def end_folder
|
||||
<<-HTML
|
||||
</ol>
|
||||
</li>
|
||||
HTML
|
||||
end
|
||||
|
||||
def url_for_page page
|
||||
url = ::File.join(::File.dirname(page.path), page.filename_stripped)
|
||||
url = url[2..-1] if url[0,2] == './'
|
||||
url
|
||||
end
|
||||
|
||||
def render_files
|
||||
html = ''
|
||||
count = @pages.size
|
||||
folder_start = -1
|
||||
|
||||
# Process all pages until folders start
|
||||
count.times do | index |
|
||||
page = @pages[ index ]
|
||||
path = page.path
|
||||
|
||||
unless path.include? '/'
|
||||
# Page processed (not contained in a folder)
|
||||
html += new_page page
|
||||
else
|
||||
# Folders start at the next index
|
||||
folder_start = index
|
||||
break # Pages finished, move on to folders
|
||||
end
|
||||
end
|
||||
|
||||
# If there are no folders, then we're done.
|
||||
return enclose_tree(html) if folder_start <= -1
|
||||
|
||||
# Handle special case of only one folder.
|
||||
if (count - folder_start == 1)
|
||||
page = @pages[ folder_start ]
|
||||
name = page.name
|
||||
url = url_for_page page
|
||||
html += <<-HTML
|
||||
<li>
|
||||
<label>#{::File.dirname(page.path)}</label> <input type="checkbox" checked />
|
||||
<ol>
|
||||
<li class="file"><a href="#{url}">#{name}</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
HTML
|
||||
|
||||
return enclose_tree html
|
||||
end
|
||||
|
||||
sorted_folders = []
|
||||
(folder_start).upto count - 1 do | index |
|
||||
sorted_folders += [[ @pages[ index ].path, index ]]
|
||||
end
|
||||
|
||||
# http://stackoverflow.com/questions/3482814/sorting-list-of-string-paths-in-vb-net
|
||||
sorted_folders.sort! do |first,second|
|
||||
a = first[0]
|
||||
b = second[0]
|
||||
|
||||
# use :: operator because gollum defines its own conflicting File class
|
||||
dir_compare = ::File.dirname(a) <=> ::File.dirname(b)
|
||||
|
||||
# Sort based on directory name unless they're equal (0) in
|
||||
# which case sort based on file name.
|
||||
if dir_compare == 0
|
||||
::File.basename(a) <=> ::File.basename(b)
|
||||
else
|
||||
dir_compare
|
||||
end
|
||||
end
|
||||
|
||||
# keep track of folder depth, 0 = at root.
|
||||
cwd_array = []
|
||||
changed = false
|
||||
|
||||
# process rest of folders
|
||||
(0...sorted_folders.size).each do | index |
|
||||
page = @pages[ sorted_folders[ index ][ 1 ] ]
|
||||
path = page.path
|
||||
folder = ::File.dirname path
|
||||
|
||||
tmp_array = folder.split '/'
|
||||
|
||||
(0...tmp_array.size).each do | index |
|
||||
if cwd_array[ index ].nil? || changed
|
||||
html += new_sub_folder tmp_array[ index ]
|
||||
next
|
||||
end
|
||||
|
||||
if cwd_array[ index ] != tmp_array[ index ]
|
||||
changed = true
|
||||
(cwd_array.size - index).times do
|
||||
html += end_folder
|
||||
end
|
||||
html += new_sub_folder tmp_array[ index ]
|
||||
end
|
||||
end
|
||||
|
||||
html += new_page page
|
||||
cwd_array = tmp_array
|
||||
changed = false
|
||||
end
|
||||
|
||||
# return the completed html
|
||||
enclose_tree html
|
||||
end # end render_files
|
||||
end # end FileView class
|
||||
end # end Gollum module
|
||||
@@ -2,16 +2,59 @@ require 'cgi'
|
||||
require 'sinatra'
|
||||
require 'gollum'
|
||||
require 'mustache/sinatra'
|
||||
require 'useragent'
|
||||
require 'stringex'
|
||||
|
||||
require 'gollum/frontend/views/layout'
|
||||
require 'gollum/frontend/views/editable'
|
||||
require 'gollum/frontend/views/has_page'
|
||||
|
||||
require File.expand_path '../uri_encode_component', __FILE__
|
||||
require File.expand_path '../helpers', __FILE__
|
||||
|
||||
# Fix to_url
|
||||
class String
|
||||
alias :upstream_to_url :to_url
|
||||
# _Header => header which causes errors
|
||||
def to_url
|
||||
return nil if self.nil?
|
||||
return self if ['_Header', '_Footer', '_Sidebar'].include? self
|
||||
upstream_to_url
|
||||
end
|
||||
end
|
||||
|
||||
# Run the frontend, based on Sinatra
|
||||
#
|
||||
# There are a number of wiki options that can be set for the frontend
|
||||
#
|
||||
# Example
|
||||
# require 'gollum/frontend/app'
|
||||
# Precious::App.set(:wiki_options, {
|
||||
# :universal_toc => false,
|
||||
# }
|
||||
#
|
||||
# See the wiki.rb file for more details on wiki options
|
||||
module Precious
|
||||
class App < Sinatra::Base
|
||||
register Mustache::Sinatra
|
||||
include Precious::Helpers
|
||||
|
||||
dir = File.dirname(File.expand_path(__FILE__))
|
||||
|
||||
# Detect unsupported browsers.
|
||||
Browser = Struct.new(:browser, :version)
|
||||
|
||||
@@min_ua = [
|
||||
Browser.new('Internet Explorer', '10.0'),
|
||||
Browser.new('Chrome', '7.0'),
|
||||
Browser.new('Firefox', '4.0'),
|
||||
]
|
||||
|
||||
def supported_useragent?(user_agent)
|
||||
ua = UserAgent.parse(user_agent)
|
||||
@@min_ua.detect {|min| ua >= min }
|
||||
end
|
||||
|
||||
# We want to serve public assets for now
|
||||
set :public_folder, "#{dir}/public/gollum"
|
||||
set :static, true
|
||||
@@ -38,47 +81,129 @@ module Precious
|
||||
enable :logging, :raise_errors, :dump_errors
|
||||
end
|
||||
|
||||
before do
|
||||
@base_url = url('/', false).chomp('/')
|
||||
settings.wiki_options.merge!({ :base_path => @base_url }) unless settings.wiki_options.has_key? :base_path
|
||||
end
|
||||
|
||||
get '/' do
|
||||
show_page_or_file('Home')
|
||||
redirect File.join(settings.wiki_options[:base_path].to_s, 'Home')
|
||||
end
|
||||
|
||||
# Removes all slashes from the start of string.
|
||||
def clean_url url
|
||||
return url if url.nil?
|
||||
url.gsub('%2F','/').gsub(/^\/+/,'')
|
||||
end
|
||||
|
||||
# path is set to name if path is nil.
|
||||
# if path is 'a/b' and a and b are dirs, then
|
||||
# path must have a trailing slash 'a/b/' or
|
||||
# extract_path will trim path to 'a'
|
||||
# name, path, version
|
||||
def wiki_page(name, path = nil, version = nil, exact = true)
|
||||
path = name if path.nil?
|
||||
name = extract_name(name)
|
||||
path = extract_path(path)
|
||||
path = '/' if exact && path.nil?
|
||||
|
||||
wiki = wiki_new
|
||||
|
||||
OpenStruct.new(:wiki => wiki, :page => wiki.paged(name, path, exact, version),
|
||||
:name => name, :path => path)
|
||||
end
|
||||
|
||||
def wiki_new
|
||||
Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
end
|
||||
|
||||
get '/data/*' do
|
||||
if page = wiki_page(params[:splat].first).page
|
||||
page.raw_data
|
||||
end
|
||||
end
|
||||
|
||||
get '/edit/*' do
|
||||
@name = params[:splat].first
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
if page = wiki.page(@name)
|
||||
@page = page
|
||||
@content = page.raw_data
|
||||
mustache :edit
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
@name = wikip.name
|
||||
@path = wikip.path
|
||||
wiki = wikip.wiki
|
||||
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)
|
||||
if @path
|
||||
live_preview_url << '&path=' + encodeURIComponent(@path)
|
||||
end
|
||||
redirect to(live_preview_url)
|
||||
else
|
||||
@page = page
|
||||
@page.version = wiki.repo.log(wiki.ref, @page.path).first
|
||||
raw_data = page.raw_data
|
||||
@content = raw_data.respond_to?(:force_encoding) ? raw_data.force_encoding('UTF-8') : raw_data
|
||||
mustache :edit
|
||||
end
|
||||
else
|
||||
redirect to("/create/#{encodeURIComponent(@name)}")
|
||||
end
|
||||
end
|
||||
|
||||
post '/edit/*' do
|
||||
path = '/' + clean_url(sanitize_empty_params(params[:path])).to_s
|
||||
page_name = CGI.unescape(params[:page])
|
||||
wiki = wiki_new
|
||||
page = wiki.paged(page_name, path, exact = true)
|
||||
rename = params[:rename].to_url if params[:rename]
|
||||
name = rename || page.name
|
||||
committer = Gollum::Committer.new(wiki, commit_message)
|
||||
commit = {:committer => committer}
|
||||
|
||||
update_wiki_page(wiki, page, params[:content], commit, name, params[:format])
|
||||
update_wiki_page(wiki, page.header, params[:header], commit) if params[:header]
|
||||
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
|
||||
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
|
||||
committer.commit
|
||||
|
||||
page = wiki.page(rename) if rename
|
||||
|
||||
redirect to("/#{page.escaped_url_path}") unless page.nil?
|
||||
end
|
||||
|
||||
get '/delete/*' do
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
name = wikip.name
|
||||
wiki = wikip.wiki
|
||||
page = wikip.page
|
||||
wiki.delete_page(page, { :message => "Destroyed #{name} (#{page.format})" })
|
||||
|
||||
redirect to('/')
|
||||
end
|
||||
|
||||
get '/create/*' do
|
||||
wikip = wiki_page(params[:splat].first.gsub('+', '-'))
|
||||
@name = wikip.name.to_url
|
||||
@path = wikip.path
|
||||
|
||||
page = wikip.page
|
||||
if page
|
||||
redirect to("/#{page.escaped_url_path}")
|
||||
else
|
||||
mustache :create
|
||||
end
|
||||
end
|
||||
|
||||
post '/edit/*' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
page = wiki.page(params[:splat].first)
|
||||
name = params[:rename] || page.name
|
||||
committer = Gollum::Committer.new(wiki, commit_message)
|
||||
commit = {:committer => committer}
|
||||
|
||||
update_wiki_page(wiki, page, params[:content], commit, name,
|
||||
params[:format])
|
||||
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
|
||||
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
|
||||
committer.commit
|
||||
|
||||
redirect "/#{CGI.escape(Gollum::Page.cname(name))}"
|
||||
end
|
||||
|
||||
post '/create' do
|
||||
name = params[:page]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
name = params[:page].to_url
|
||||
path = sanitize_empty_params(params[:path])
|
||||
path = '' if path.nil?
|
||||
format = params[:format].intern
|
||||
|
||||
format = params[:format].intern
|
||||
# write_page is not directory aware so use wiki_options to emulate dir support.
|
||||
wiki_options = settings.wiki_options.merge({ :page_file_dir => path })
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
|
||||
|
||||
begin
|
||||
wiki.write_page(name, format, params[:content], commit_message)
|
||||
redirect "/#{CGI.escape(Gollum::Page.cname(name))}"
|
||||
redirect to("/#{clean_url(CGI.escape(::File.join(path,name)))}")
|
||||
rescue Gollum::DuplicatePageError => e
|
||||
@message = "Duplicate page: #{e.message}"
|
||||
mustache :error
|
||||
@@ -86,62 +211,75 @@ module Precious
|
||||
end
|
||||
|
||||
post '/revert/:page/*' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@name = params[:page]
|
||||
@page = wiki.page(@name)
|
||||
shas = params[:splat].first.split("/")
|
||||
sha1 = shas.shift
|
||||
sha2 = shas.shift
|
||||
wikip = wiki_page(params[:page])
|
||||
@path = wikip.path
|
||||
@name = wikip.name
|
||||
wiki = wikip.wiki
|
||||
@page = wiki.paged(@name,@path)
|
||||
shas = params[:splat].first.split("/")
|
||||
sha1 = shas.shift
|
||||
sha2 = shas.shift
|
||||
|
||||
if wiki.revert_page(@page, sha1, sha2, commit_message)
|
||||
redirect "/#{CGI.escape(@name)}"
|
||||
redirect to("/#{@page.escaped_url_path}")
|
||||
else
|
||||
sha2, sha1 = sha1, "#{sha1}^" if !sha2
|
||||
@versions = [sha1, sha2]
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
@message = "The patch does not apply."
|
||||
@versions = [sha1, sha2]
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
@message = "The patch does not apply."
|
||||
mustache :compare
|
||||
end
|
||||
end
|
||||
|
||||
post '/preview' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@name = "Preview"
|
||||
@page = wiki.preview_page(@name, params[:content], params[:format])
|
||||
@content = @page.formatted_data
|
||||
wiki = wiki_new
|
||||
@name = params[:page] || "Preview"
|
||||
@page = wiki.preview_page(@name, params[:content], params[:format])
|
||||
@content = @page.formatted_data
|
||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||
@mathjax = wiki.mathjax
|
||||
@editable = false
|
||||
mustache :page
|
||||
end
|
||||
|
||||
get '/history/:name' do
|
||||
@name = params[:name]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@page = wiki.page(@name)
|
||||
@page_num = [params[:page].to_i, 1].max
|
||||
@versions = @page.versions :page => @page_num
|
||||
get '/history/*' do
|
||||
@page = wiki_page(params[:splat].first).page
|
||||
@page_num = [params[:page].to_i, 1].max
|
||||
@versions = @page.versions :page => @page_num
|
||||
mustache :history
|
||||
end
|
||||
|
||||
post '/compare/:name' do
|
||||
post '/compare/*' do
|
||||
@file = params[:splat].first
|
||||
@versions = params[:versions] || []
|
||||
if @versions.size < 2
|
||||
redirect "/history/#{CGI.escape(params[:name])}"
|
||||
redirect to("/history/#{@file}")
|
||||
else
|
||||
redirect "/compare/%s/%s...%s" % [
|
||||
CGI.escape(params[:name]),
|
||||
redirect to("/compare/%s/%s...%s" % [
|
||||
@file,
|
||||
@versions.last,
|
||||
@versions.first]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
get '/compare/:name/:version_list' do
|
||||
@name = params[:name]
|
||||
@versions = params[:version_list].split(/\.{2,3}/)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@page = wiki.page(@name)
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
get %r{
|
||||
/compare/ # match any URL beginning with /compare/
|
||||
(.+) # extract the full path (including any directories)
|
||||
/ # match the final slash
|
||||
([^.]+) # match the first SHA1
|
||||
\.{2,3} # match .. or ...
|
||||
(.+) # match the second SHA1
|
||||
}x do |path, start_version, end_version|
|
||||
wikip = wiki_page(path)
|
||||
@path = wikip.path
|
||||
@name = wikip.name
|
||||
@versions = [start_version, end_version]
|
||||
wiki = wikip.wiki
|
||||
@page = wikip.page
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
mustache :compare
|
||||
end
|
||||
|
||||
@@ -156,9 +294,12 @@ module Precious
|
||||
end
|
||||
|
||||
get %r{/(.+?)/([0-9a-f]{40})} do
|
||||
name = params[:captures][0]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
if page = wiki.page(name, params[:captures][1])
|
||||
file_path = params[:captures][0]
|
||||
version = params[:captures][1]
|
||||
wikip = wiki_page(file_path, file_path, version)
|
||||
name = wikip.name
|
||||
path = wikip.path
|
||||
if page = wikip.page
|
||||
@page = page
|
||||
@name = name
|
||||
@content = page.formatted_data
|
||||
@@ -171,47 +312,68 @@ module Precious
|
||||
|
||||
get '/search' do
|
||||
@query = params[:q]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
wiki = wiki_new
|
||||
@results = wiki.search @query
|
||||
@name = @query
|
||||
mustache :search
|
||||
end
|
||||
|
||||
get '/pages' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@results = wiki.pages
|
||||
@ref = wiki.ref
|
||||
get %r{
|
||||
/pages # match any URL beginning with /pages
|
||||
(?: # begin an optional non-capturing group
|
||||
/(.+) # capture any path after the "/pages" excluding the leading slash
|
||||
)? # end the optional non-capturing group
|
||||
}x do |path|
|
||||
@path = extract_path(path) if path
|
||||
wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
|
||||
@results = wiki.pages
|
||||
@ref = wiki.ref
|
||||
mustache :pages
|
||||
end
|
||||
|
||||
get '/fileview' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@results = Gollum::FileView.new(wiki.pages).render_files
|
||||
@ref = wiki.ref
|
||||
mustache :file_view, { :layout => false }
|
||||
end
|
||||
|
||||
get '/*' do
|
||||
show_page_or_file(params[:splat].first)
|
||||
end
|
||||
|
||||
def show_page_or_file(name)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
if page = wiki.page(name)
|
||||
def show_page_or_file(fullpath)
|
||||
name = extract_name(fullpath)
|
||||
path = extract_path(fullpath)
|
||||
wiki = wiki_new
|
||||
|
||||
path = '/' if path.nil?
|
||||
|
||||
if page = wiki.paged(name, path, exact = true)
|
||||
@page = page
|
||||
@name = name
|
||||
@content = page.formatted_data
|
||||
@editable = true
|
||||
@content = page.formatted_data
|
||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||
@mathjax = wiki.mathjax
|
||||
mustache :page
|
||||
elsif file = wiki.file(name)
|
||||
elsif file = wiki.file(fullpath)
|
||||
content_type file.mime_type
|
||||
file.raw_data
|
||||
else
|
||||
@name = name
|
||||
mustache :create
|
||||
page_path = [path, name].compact.join('/')
|
||||
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
||||
end
|
||||
end
|
||||
|
||||
def update_wiki_page(wiki, page, content, commit_message, name = nil, format = nil)
|
||||
def update_wiki_page(wiki, page, content, commit, name = nil, format = nil)
|
||||
return if !page ||
|
||||
((!content || page.raw_data == content) && page.format == format)
|
||||
name ||= page.name
|
||||
format = (format || page.format).to_sym
|
||||
content ||= page.raw_data
|
||||
wiki.update_page(page, name, format, content.to_s, commit_message)
|
||||
wiki.update_page(page, name, format, content.to_s, commit)
|
||||
end
|
||||
|
||||
def commit_message
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
module Precious
|
||||
module Helpers
|
||||
# Extract the path string that Gollum::Wiki expects
|
||||
def extract_path(file_path)
|
||||
return nil if file_path.nil?
|
||||
last_slash = file_path.rindex("/")
|
||||
if last_slash
|
||||
file_path[0, last_slash]
|
||||
end
|
||||
end
|
||||
|
||||
# Extract the 'page' name from the file_path
|
||||
def extract_name(file_path)
|
||||
::File.basename(file_path)
|
||||
end
|
||||
|
||||
def sanitize_empty_params(param)
|
||||
[nil,''].include?(param) ? nil : CGI.unescape(param)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,121 @@
|
||||
*, html {
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
#results a:hover {
|
||||
background-color: #4c4c4c;
|
||||
}
|
||||
|
||||
#home_button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
#home_button .minibutton {
|
||||
font-size: 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#results {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
body, form, ul, li, p, h1, h2, h3, h4, h5 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #606061;
|
||||
color: #ffffff;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1em;
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
html { font-size: 100%; /* IE hack */ }
|
||||
body { font-size: 1em; /* Sets base font size to 16px */ }
|
||||
table { font-size: 100%; /* IE hack */ }
|
||||
input, select, textarea, th, td { font-size: 1em; }
|
||||
|
||||
/* Prevent wrapping on large file names. */
|
||||
li.file {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* CSS Tree menu styles */
|
||||
ol.tree
|
||||
{
|
||||
padding: 0 0 0 30px;
|
||||
width: 300px;
|
||||
}
|
||||
li
|
||||
{
|
||||
position: relative;
|
||||
margin-left: -15px;
|
||||
list-style: none;
|
||||
}
|
||||
li.file
|
||||
{
|
||||
margin-left: -1px !important;
|
||||
height: 1.5em;
|
||||
}
|
||||
li.file a
|
||||
{
|
||||
background: url(../images/fileview/document.png) 0 0 no-repeat;
|
||||
color: #fff;
|
||||
padding-left: 21px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
li.file a[href *= '.pdf'] { background: url(../images/fileview/document.png) 0 0 no-repeat; }
|
||||
li.file a[href *= '.html'] { background: url(../images/fileview/document.png) 0 0 no-repeat; }
|
||||
li.file a[href $= '.css'] { background: url(../images/fileview/document.png) 0 0 no-repeat; }
|
||||
li.file a[href $= '.js'] { background: url(../images/fileview/document.png) 0 0 no-repeat; }
|
||||
li input
|
||||
{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
margin-left: 0;
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
top: 0;
|
||||
}
|
||||
li input + ol
|
||||
{
|
||||
background: url(../images/fileview/toggle-small-expand.png) 40px 0 no-repeat;
|
||||
margin: -1.188em 0 0 -44px; /* 15px */
|
||||
height: 1.5em;
|
||||
}
|
||||
li input + ol > li { display: none; margin-left: -14px !important; padding-left: 1px; }
|
||||
li label
|
||||
{
|
||||
background: url(../images/fileview/folder-horizontal.png) 15px 1px no-repeat;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
padding-left: 37px;
|
||||
}
|
||||
|
||||
li input:checked + ol
|
||||
{
|
||||
background: url(../images/fileview/toggle-small.png) 40px 5px no-repeat;
|
||||
margin: -1.5em 0 0 -44px; /* 20px */
|
||||
padding: 1.563em 0 0 80px;
|
||||
height: auto;
|
||||
}
|
||||
li input:checked + ol > li { display: block; margin: 0 0 0.125em; /* 2px */}
|
||||
li input:checked + ol > li:last-child { margin: 0 0 0.063em; /* 1px */ }
|
||||
|
||||
@@ -30,6 +30,7 @@ a {
|
||||
-webkit-border-radius: 1em;
|
||||
}
|
||||
|
||||
.ff #gollum-editor,
|
||||
.ie #gollum-editor {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
@@ -51,9 +52,9 @@ a {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
color: #000;
|
||||
font-size: 1.3em;
|
||||
font-size: 1.1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.8em;
|
||||
line-height: 1.5em;
|
||||
margin: 1em 0 0.4em;
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
@@ -63,6 +64,12 @@ a {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#gollum-editor .path_note {
|
||||
text-align: right;
|
||||
font-size: small;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#gollum-editor-title-field input#gollum-editor-page-title {
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
@@ -192,62 +199,54 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar #gollum-editor-format-selector {
|
||||
overflow: hidden;
|
||||
padding: 0 0 1.1em 0;
|
||||
padding: .2em 0 .5em 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector select {
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid transparent;
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
|
||||
float: right;
|
||||
font-size: 1.1em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
padding: 0.5em 0.7em;
|
||||
margin-bottom: 0;
|
||||
padding: 0.3em 0.4em;
|
||||
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
-moz-outline: none;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector select:hover {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
-moz-outline: none;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector label {
|
||||
color: #999;
|
||||
float: right;
|
||||
font-size: 1.1em;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
padding: 0.6em 0.5em 0 0;
|
||||
padding: .3em 0.5em 0 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector label:after {
|
||||
#gollum-editor-format-selector label:after {
|
||||
content: ':';
|
||||
}
|
||||
|
||||
|
||||
/* @section form-fields */
|
||||
|
||||
#gollum-editor textarea#gollum-editor-body {
|
||||
#gollum-editor textarea {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 1.3em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.8em;
|
||||
line-height: 1.4em;
|
||||
margin: 1em 0 0.4em;
|
||||
padding: 0.5em; /* I don't really like mixing pct & em here… */
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
height: 20em;
|
||||
}
|
||||
@@ -259,7 +258,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 1.2em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
@@ -301,7 +300,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
border-bottom: 1px solid #ddd;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding: 1em 0 0.5em;
|
||||
padding: 0.5em 0 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-body + .collapsed,
|
||||
@@ -337,12 +336,15 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
font-size: 1.6em;
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding: 0.4em 0 0 0.3em;
|
||||
padding: 0.15em 0 0 0.3em;
|
||||
text-shadow: 0 -1px 0 #fff;
|
||||
}
|
||||
#gollum-editor .collapsed h4 {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed a.button:hover,
|
||||
#gollum-editor .expanded h4 a.button:hover {
|
||||
#gollum-editor .expanded a.button:hover {
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
text-decoration: none;
|
||||
@@ -385,10 +387,10 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
border: 1px solid #ddd;
|
||||
clear: both;
|
||||
display: block;
|
||||
font-size: 1.3em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
height: 7em;
|
||||
line-height: 1.8em;
|
||||
line-height: 1.4em;
|
||||
margin: 0.7em 0;
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
@@ -403,7 +405,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.2em;
|
||||
|
||||
@@ -37,18 +37,23 @@ a:hover, a:visited {
|
||||
|
||||
/* @section head */
|
||||
#head {
|
||||
margin: 4.5em 0 0.5em;
|
||||
padding: 0.5em 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 4em 0 1.5em;
|
||||
padding-bottom: 0.3em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#head h1 {
|
||||
display: none;
|
||||
}
|
||||
#head h1 {
|
||||
font-size: 33px;
|
||||
float: left;
|
||||
line-height: normal;
|
||||
margin: 0;
|
||||
padding: 2px 0 0 0;
|
||||
}
|
||||
|
||||
#head ul.actions {
|
||||
float: right;
|
||||
}
|
||||
#head ul.actions {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* @section content */
|
||||
#wiki-content {
|
||||
@@ -56,171 +61,173 @@ a:hover, a:visited {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#wiki-content .wrap {
|
||||
height: 1%;
|
||||
overflow: auto;
|
||||
}
|
||||
#wiki-content .wrap {
|
||||
height: 1%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* @section comments */
|
||||
#wiki-body #inline-comment {
|
||||
display: none; /* todo */
|
||||
}
|
||||
/* @section comments */
|
||||
#wiki-body #inline-comment {
|
||||
display: none; /* todo */
|
||||
}
|
||||
|
||||
/* @section body */
|
||||
#wiki-body {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 3%;
|
||||
width: 100%;
|
||||
}
|
||||
/* @section body */
|
||||
#wiki-body {
|
||||
display: block;
|
||||
float: left;
|
||||
clear: left;
|
||||
margin-right: 3%;
|
||||
margin-bottom: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.has-rightbar #wiki-body {
|
||||
width: 68%;
|
||||
}
|
||||
.has-rightbar #wiki-body {
|
||||
width: 68%;
|
||||
}
|
||||
|
||||
/* @section rightbar */
|
||||
#wiki-rightbar {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 13px;
|
||||
float: right;
|
||||
padding: 7px;
|
||||
width: 25%;
|
||||
/* @section toc */
|
||||
#wiki-toc-main {
|
||||
background-color: #F7F7F7;
|
||||
border: 1px solid #DDD;
|
||||
font-size: 13px;
|
||||
padding: 0px 5px;
|
||||
float:left;
|
||||
margin-bottom: 20px;
|
||||
min-width: 33%;
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
#wiki-toc-main > div {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#wiki-rightbar p {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
/* @section rightbar */
|
||||
#wiki-rightbar {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 13px;
|
||||
float: right;
|
||||
padding: 7px;
|
||||
width: 25%;
|
||||
color: #555;
|
||||
|
||||
#wiki-rightbar > p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
|
||||
#wiki-rightbar p.parent {
|
||||
border-bottom: 1px solid #bbb;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0.5em 0;
|
||||
padding: 0 0 0.5em 0;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
#wiki-rightbar p {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
|
||||
/* Back arrow */
|
||||
#wiki-rightbar p.parent:before {
|
||||
color: #666;
|
||||
content: "← ";
|
||||
}
|
||||
#wiki-rightbar > p:first-child {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#wiki-rightbar h3 {
|
||||
font-size: 1.2em;
|
||||
color: #333;
|
||||
margin: 1.2em 0 0;
|
||||
padding: 0;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
#wiki-rightbar p.parent {
|
||||
border-bottom: 1px solid #bbb;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0.5em 0;
|
||||
padding: 0 0 0.5em 0;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
#wiki-rightbar ul {
|
||||
margin: 0.5em 0 1em;
|
||||
padding: 0;
|
||||
}
|
||||
/* Back arrow */
|
||||
#wiki-rightbar p.parent:before {
|
||||
color: #666;
|
||||
content: "← ";
|
||||
}
|
||||
|
||||
#wiki-rightbar ul li {
|
||||
color: #bbb;
|
||||
margin: 0 0 0 1em;
|
||||
padding: 0;
|
||||
line-height: 1.75em;
|
||||
list-style-position: inside;
|
||||
list-style-type: round;
|
||||
}
|
||||
/* @section footer */
|
||||
|
||||
#wiki-rightbar #nav ul li a {
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
#wiki-footer {
|
||||
clear: both;
|
||||
margin: 2em 0 5em;
|
||||
}
|
||||
|
||||
/* @section footer */
|
||||
#wiki-footer {
|
||||
clear: both;
|
||||
margin: 2em 0 5em;
|
||||
}
|
||||
.has-rightbar #wiki-footer {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.has-rightbar #wiki-footer {
|
||||
width: 70%;
|
||||
}
|
||||
#wiki-header #header-content,
|
||||
#wiki-footer #footer-content {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
padding: 1em;
|
||||
|
||||
#wiki-footer #footer-content {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.5em;
|
||||
margin-top: 1.5em;
|
||||
padding: 1em;
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
#wiki-header #header-content {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
#wiki-footer #footer-content {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
#wiki-footer #footer-content h3 {
|
||||
font-size: 1.2em;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 0 0 0.2em;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
#wiki-footer #footer-content h3 {
|
||||
font-size: 1.2em;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 0 0 0.2em;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
#wiki-footer #footer-content p {
|
||||
margin: 0.5em 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
#wiki-footer #footer-content p {
|
||||
margin: 0.5em 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#wiki-footer #footer-content ul.links {
|
||||
margin: 0.5em 0 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
#wiki-footer #footer-content ul.links {
|
||||
margin: 0.5em 0 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#wiki-footer #footer-content ul.links li {
|
||||
color: #999;
|
||||
float: left;
|
||||
list-style-position: inside;
|
||||
list-style-type: square;
|
||||
padding: 0;
|
||||
margin-left: 0.75em;
|
||||
}
|
||||
#wiki-footer #footer-content ul.links li {
|
||||
color: #999;
|
||||
float: left;
|
||||
list-style-position: inside;
|
||||
list-style-type: square;
|
||||
padding: 0;
|
||||
margin-left: 0.75em;
|
||||
}
|
||||
|
||||
#wiki-footer #footer-content ul.links li a {
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
#wiki-footer #footer-content ul.links li a {
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
#wiki-footer #footer-content ul.links li:first-child {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
}
|
||||
#wiki-footer #footer-content ul.links li:first-child {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ff #wiki-footer #footer-content ul.links li:first-child {
|
||||
margin: 0 -0.75em 0 0;
|
||||
}
|
||||
.ff #wiki-footer #footer-content ul.links li:first-child {
|
||||
margin: 0 -0.75em 0 0;
|
||||
}
|
||||
|
||||
/* @section page-footer */
|
||||
.page #footer {
|
||||
margin: 1em 0 7em;
|
||||
}
|
||||
/* @section page-footer */
|
||||
.page #footer {
|
||||
clear: both;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 1em 0 7em;
|
||||
}
|
||||
|
||||
#footer p#last-edit {
|
||||
font-size: .9em;
|
||||
line-height: 1.6em;
|
||||
color: #999;
|
||||
margin: 0.9em 0;
|
||||
}
|
||||
#footer p#last-edit {
|
||||
font-size: .9em;
|
||||
line-height: 1.6em;
|
||||
color: #999;
|
||||
margin: 0.9em 0;
|
||||
}
|
||||
|
||||
#footer p#last-edit span.username {
|
||||
font-weight: bold;
|
||||
}
|
||||
#footer p#last-edit span.username {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* @section history */
|
||||
@@ -229,107 +236,113 @@ a:hover, a:visited {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.history h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#wiki-history {
|
||||
margin-top: 3em;
|
||||
.history h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#wiki-history fieldset {
|
||||
border: 0;
|
||||
margin: 2em 0;
|
||||
padding: 0;
|
||||
}
|
||||
#wiki-history {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#wiki-history table, #wiki-history tbody {
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
#wiki-history fieldset {
|
||||
border: 0;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#wiki-history table tr {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#wiki-history table, #wiki-history tbody {
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#wiki-history table tr {
|
||||
background-color: #ebf2f6;
|
||||
}
|
||||
#wiki-history table tr {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#wiki-history table tr td {
|
||||
border: 1px solid #c0dce9;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
margin: 0;
|
||||
padding: 0.3em 0.7em;
|
||||
}
|
||||
#wiki-history table tr {
|
||||
background-color: #ebf2f6;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.checkbox {
|
||||
min-width: 2em;
|
||||
padding: 0.3em;
|
||||
}
|
||||
#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 input {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
padding-right: 0;
|
||||
padding-top: 0.4em;
|
||||
margin-right: -0.2em;
|
||||
}
|
||||
#wiki-history table tr td.checkbox {
|
||||
width: 4em;
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
#wiki-history table tr:nth-child(2n),
|
||||
#wiki-history table tr.alt-row {
|
||||
background-color: #f3f7fa;
|
||||
}
|
||||
#wiki-history table tr td.checkbox input {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
padding-right: 0;
|
||||
padding-top: 0.4em;
|
||||
margin: 0 auto;
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
}
|
||||
|
||||
#wiki-history table tr.selected {
|
||||
background-color: #ffffea !important;
|
||||
z-index: 100;
|
||||
}
|
||||
#wiki-history table tr:nth-child(2n),
|
||||
#wiki-history table tr.alt-row {
|
||||
background-color: #f3f7fa;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.commit-name {
|
||||
border-left: 0;
|
||||
}
|
||||
#wiki-history table tr.selected {
|
||||
background-color: #ffffea !important;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.commit-name span.time-elapsed {
|
||||
color: #999;
|
||||
}
|
||||
#wiki-history table tr td.commit-name {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.author {
|
||||
width: 20%;
|
||||
}
|
||||
#wiki-history table tr td.commit-name span.time-elapsed {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.author a {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
#wiki-history table tr td.author {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.author a span.username {
|
||||
display: block;
|
||||
padding-top: 3px;
|
||||
}
|
||||
#wiki-history table tr td.author a {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#wiki-history table tr td img {
|
||||
background-color: #fff;
|
||||
border: 1px solid #999;
|
||||
display: block;
|
||||
float: left;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
margin: 0 0.5em 0 0;
|
||||
width: 18px;
|
||||
padding: 2px;
|
||||
}
|
||||
#wiki-history table tr td.author a span.username {
|
||||
display: block;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.commit-name a {
|
||||
font-size: 0.9em;
|
||||
font-family: 'Monaco', 'Andale Mono', Consolas, 'Courier New', monospace;
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
#wiki-history table tr td img {
|
||||
background-color: #fff;
|
||||
border: 1px solid #999;
|
||||
display: block;
|
||||
float: left;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
margin: 0 0.5em 0 0;
|
||||
width: 18px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.commit-name a {
|
||||
font-size: 0.9em;
|
||||
font-family: 'Monaco', 'Andale Mono', Consolas, 'Courier New', monospace;
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
|
||||
.history #footer {
|
||||
margin-bottom: 7em;
|
||||
}
|
||||
|
||||
.history #wiki-history ul.actions li,
|
||||
.history #footer ul.actions li {
|
||||
@@ -343,10 +356,10 @@ a:hover, a:visited {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.edit h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
.edit h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* @section search */
|
||||
@@ -355,42 +368,42 @@ a:hover, a:visited {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.results h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
.results h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.results #results {
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin-bottom: 2em;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
.results #results {
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin-bottom: 2em;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
.results #results ul {
|
||||
margin: 2em 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
.results #results ul {
|
||||
margin: 2em 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.results #results ul li {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
list-style-position: outside;
|
||||
padding: 0.2em 0;
|
||||
}
|
||||
.results #results ul li {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
list-style-position: outside;
|
||||
padding: 0.2em 0;
|
||||
}
|
||||
|
||||
.results #results ul li span.count {
|
||||
color: #999;
|
||||
}
|
||||
.results #results ul li span.count {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.results p#no-results {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
.results p#no-results {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.results #footer ul.actions li {
|
||||
margin: 0 1em 0 0;
|
||||
}
|
||||
.results #footer ul.actions li {
|
||||
margin: 0 1em 0 0;
|
||||
}
|
||||
|
||||
|
||||
/* @section compare */
|
||||
@@ -399,44 +412,52 @@ a:hover, a:visited {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.compare h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
.compare h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.compare #compare-content {
|
||||
margin-top: 3em;
|
||||
}
|
||||
.compare #compare-content {
|
||||
margin-top: 3em;
|
||||
}
|
||||
|
||||
.compare .data {
|
||||
border: 1px solid #ddd;
|
||||
margin-top: 1em;
|
||||
overflow: auto;
|
||||
}
|
||||
.compare .data {
|
||||
border: 1px solid #ddd;
|
||||
margin: 1em 0 2em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.compare .data pre {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.compare .data table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.compare .data pre div {
|
||||
padding: 0 0 0 1em;
|
||||
}
|
||||
.compare .data pre {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.compare .data tr td {
|
||||
font-family: "Consolas", "Monaco", "Andale Mono", "Courier New", monospace;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.8em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.compare .data pre div {
|
||||
padding: 0 0 0 1em;
|
||||
}
|
||||
|
||||
.compare .data td.line_numbers {
|
||||
background: #f7f7f7;
|
||||
border-right: 1px solid #999;
|
||||
color: #999;
|
||||
padding: 0 0 0 0.5em;
|
||||
}
|
||||
.compare .data tr td {
|
||||
font-family: "Consolas", "Monaco", "Andale Mono", "Courier New", monospace;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.2em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.compare .data tr td + td + td {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.compare .data td.line_numbers {
|
||||
background: #f7f7f7;
|
||||
border-right: 1px solid #999;
|
||||
color: #999;
|
||||
padding: 0 0 0 0.5em;
|
||||
}
|
||||
|
||||
.compare #compare-content ul.actions li,
|
||||
.compare #footer ul.actions li {
|
||||
@@ -444,6 +465,10 @@ a:hover, a:visited {
|
||||
margin-right: 0.6em;
|
||||
}
|
||||
|
||||
.compare #footer {
|
||||
margin-bottom: 7em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* @control syntax */
|
||||
@@ -481,8 +506,9 @@ ul.actions {
|
||||
|
||||
ul.actions li {
|
||||
float: left;
|
||||
font-size: 1.2em;
|
||||
font-size: 0.9em;
|
||||
margin-left: 0.6em;
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
.minibutton a {
|
||||
@@ -586,75 +612,105 @@ ul.actions {
|
||||
/* @control searchbar */
|
||||
#head #searchbar {
|
||||
float: right;
|
||||
margin: 1em 0 0 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext {
|
||||
background: #fff;
|
||||
border: 1px solid #d4d4d4;
|
||||
overflow: hidden;
|
||||
#head #searchbar #searchbar-fauxtext {
|
||||
background: #fff;
|
||||
border: 1px solid #d4d4d4;
|
||||
overflow: hidden;
|
||||
height: 2.2em;
|
||||
|
||||
border-radius: 0.3em;
|
||||
-moz-border-radius: 0.3em;
|
||||
-webkit-border-radius: 0.3em;
|
||||
}
|
||||
border-radius: 0.3em;
|
||||
-moz-border-radius: 0.3em;
|
||||
-webkit-border-radius: 0.3em;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext input#search-query {
|
||||
border: none;
|
||||
color: #000;
|
||||
float: left;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 1.2em;
|
||||
height: 1.8em;
|
||||
#head #searchbar #searchbar-fauxtext input#search-query {
|
||||
border: none;
|
||||
color: #000;
|
||||
float: left;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 1em;
|
||||
height: inherit;
|
||||
padding: 0 .5em;
|
||||
|
||||
-webkit-focus-ring: none;
|
||||
}
|
||||
-webkit-focus-ring: none;
|
||||
}
|
||||
|
||||
.ff #head #searchbar #searchbar-fauxtext input#search-query {
|
||||
padding: 0.2em 0 0.2em 0.5em;
|
||||
}
|
||||
.ie8 #head #searchbar #searchbar-fauxtext input#search-query {
|
||||
padding: 0.5em 0 0 0.5em;
|
||||
}
|
||||
|
||||
.ie #head #searchbar #searchbar-fauxtext input#search-query {
|
||||
padding: 0.4em 0 0 0.5em;
|
||||
}
|
||||
#head #searchbar #searchbar-fauxtext input#search-query.ph {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext input#search-query.ph {
|
||||
color: #999;
|
||||
}
|
||||
#head #searchbar #searchbar-fauxtext #search-submit {
|
||||
border: 0;
|
||||
border-left: 1px solid #d4d4d4;
|
||||
cursor: pointer;
|
||||
margin: 0 !important;
|
||||
padding: 0;
|
||||
float: right;
|
||||
height: inherit;
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit {
|
||||
border: 0;
|
||||
border-left: 1px solid #d4d4d4;
|
||||
cursor: pointer;
|
||||
margin: 0 !important;
|
||||
border-radius: 0 3px 3px 0;
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
-webkit-border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit span {
|
||||
background-image: url(../images/icon-sprite.png);
|
||||
background-position: -431px -1px;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
height: inherit;
|
||||
overflow: hidden;
|
||||
text-indent: -5000px;
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.ff #head #searchbar #searchbar-fauxtext #search-submit span,
|
||||
.ie #head #searchbar #searchbar-fauxtext #search-submit span {
|
||||
height: 2.2em;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit:hover span {
|
||||
background-position: -431px -28px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* @section pages */
|
||||
|
||||
#pages {
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#pages ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
float: right;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
border-radius: 0 3px 3px 0;
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
-webkit-border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit span {
|
||||
background-image: url(/images/icon-sprite.png);
|
||||
background-position: -431px -1px;
|
||||
#pages li a.file,
|
||||
#pages li a.folder {
|
||||
background-image: url(/images/fileview/document.png);
|
||||
background-position: 0 1px;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
height: 2em;
|
||||
overflow: hidden;
|
||||
text-indent: -5000px;
|
||||
width: 28px;
|
||||
}
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.ff #head #searchbar #searchbar-fauxtext #search-submit span,
|
||||
.ie #head #searchbar #searchbar-fauxtext #search-submit span {
|
||||
height: 2.2em;
|
||||
}
|
||||
#pages li a.folder {
|
||||
background-image: url(/images/fileview/folder-horizontal.png);
|
||||
}
|
||||
|
||||
#pages .breadcrumb {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit:hover span {
|
||||
background-position: -431px -28px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
html, body {
|
||||
color: black;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -22,360 +21,613 @@ img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#template {
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 40px;
|
||||
a {
|
||||
color: #4183C4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Link Colors */
|
||||
a.absent {
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
/* Primary Body Copy */
|
||||
#template p {
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
.markdown-body a[id].wiki-toc-anchor {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* ReST first graf in nested list */
|
||||
#template * li p.first {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
#template h1, #template h2, #template h3,
|
||||
#template h4, #template h5, #template h6 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
.markdown-body {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
#template h1 {
|
||||
.markdown-body>*:first-child {
|
||||
margin-top: 0!important;
|
||||
}
|
||||
.markdown-body>*:last-child {
|
||||
margin-bottom: 0!important;
|
||||
}
|
||||
.markdown-body a.absent {
|
||||
color: #c00;
|
||||
}
|
||||
.markdown-body a.anchor {
|
||||
display: block;
|
||||
padding-left: 30px;
|
||||
margin-left: -30px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.markdown-body h1,
|
||||
.markdown-body h2,
|
||||
.markdown-body h3,
|
||||
.markdown-body h4,
|
||||
.markdown-body h5,
|
||||
.markdown-body h6 {
|
||||
margin: 20px 0 10px;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
cursor: text;
|
||||
position: relative;
|
||||
}
|
||||
.markdown-body h1:hover a.anchor,
|
||||
.markdown-body h2:hover a.anchor,
|
||||
.markdown-body h3:hover a.anchor,
|
||||
.markdown-body h4:hover a.anchor,
|
||||
.markdown-body h5:hover a.anchor,
|
||||
.markdown-body h6:hover a.anchor {
|
||||
background: url(../images/pin-20.png) no-repeat left center;
|
||||
text-decoration: none;
|
||||
}
|
||||
.markdown-body h1 tt,
|
||||
.markdown-body h1 code,
|
||||
.markdown-body h2 tt,
|
||||
.markdown-body h2 code,
|
||||
.markdown-body h3 tt,
|
||||
.markdown-body h3 code,
|
||||
.markdown-body h4 tt,
|
||||
.markdown-body h4 code,
|
||||
.markdown-body h5 tt,
|
||||
.markdown-body h5 code,
|
||||
.markdown-body h6 tt,
|
||||
.markdown-body h6 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
.markdown-body h1 {
|
||||
font-size: 28px;
|
||||
color: #000;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.markdown-body h2 {
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
font-size: 33px; /* was 32, GH is 33px */
|
||||
line-height: normal;
|
||||
padding: .08em 0 0 0;
|
||||
margin: 0;
|
||||
color: #000;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#template h2 {
|
||||
font-size: 22px;
|
||||
line-height: normal;
|
||||
margin: 22px 0 0;
|
||||
padding: 7px 0 0;
|
||||
.markdown-body h3 {
|
||||
font-size: 18px;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#template h3 {
|
||||
.markdown-body h4 {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
padding: 26px 0 0;
|
||||
}
|
||||
|
||||
#template h4 {
|
||||
.markdown-body h5 {
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
padding: 18px 0 4px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#template h5 {
|
||||
font-size: 13px;
|
||||
line-height: 26px;
|
||||
margin-bottom: -19px;
|
||||
padding: 14px 0 0;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#template h6 {
|
||||
color: #666;
|
||||
.markdown-body h6 {
|
||||
color: #777;
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
margin-bottom: -19px;
|
||||
padding: 18px 0 0;
|
||||
font-weight: normal;
|
||||
font-variant: italic;
|
||||
}
|
||||
|
||||
#template hr {
|
||||
background-color: #ccc;
|
||||
.markdown-body p,
|
||||
.markdown-body blockquote,
|
||||
.markdown-body ul,
|
||||
.markdown-body ol,
|
||||
.markdown-body dl,
|
||||
.markdown-body li,
|
||||
.markdown-body table,
|
||||
.markdown-body pre {
|
||||
margin: 15px 0;
|
||||
}
|
||||
.markdown-body hr {
|
||||
background: transparent url(../images/dirty-shade.png) repeat-x 0 0;
|
||||
border: 0 none;
|
||||
color: #ccc;
|
||||
border: 2px solid #ccc;
|
||||
margin: 20px 0;
|
||||
height: 4px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Border Reset for headers with horizontal rules */
|
||||
#template > h2:first-child,
|
||||
#template > h1:first-child {
|
||||
margin: 12px 0 0;
|
||||
padding: 10px 0 0;
|
||||
}
|
||||
|
||||
|
||||
/* Lists, Blockquotes & Such */
|
||||
#template ul,
|
||||
#template ol {
|
||||
margin-top: 1.5em;
|
||||
margin-left: 2.6em;
|
||||
.markdown-body>h1:first-child,
|
||||
.markdown-body>h2:first-child,
|
||||
.markdown-body>h3:first-child,
|
||||
.markdown-body>h4:first-child,
|
||||
.markdown-body>h5:first-child,
|
||||
.markdown-body>h6:first-child {
|
||||
}
|
||||
|
||||
/* Nested Lists */
|
||||
#template ul li,
|
||||
#template ol li,
|
||||
#template ul li ul,
|
||||
#template ol li ol,
|
||||
#template ul li ol,
|
||||
#template ol li ul,
|
||||
#template ul ul,
|
||||
#template ol ol {
|
||||
padding: 0;
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
#template dl {
|
||||
margin: 0;
|
||||
padding: 20px 0 0;
|
||||
.markdown-body h1+h2{
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
#template dl dt {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: normal;
|
||||
margin: 0;
|
||||
padding: 20px 0 0;
|
||||
}
|
||||
|
||||
#template dl dt:first-child {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#template dl dd {
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
padding: 3px 0 0;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
#template table {
|
||||
.markdown-body h2+h3{
|
||||
margin-top: 10px;
|
||||
}
|
||||
.markdown-body a:first-child h1,
|
||||
.markdown-body a:first-child h2,
|
||||
.markdown-body a:first-child h3,
|
||||
.markdown-body a:first-child h4,
|
||||
.markdown-body a:first-child h5,
|
||||
.markdown-body a:first-child h6 {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.markdown-body h1+p,
|
||||
.markdown-body h2+p,
|
||||
.markdown-body h3+p,
|
||||
.markdown-body h4+p,
|
||||
.markdown-body h5+p,
|
||||
.markdown-body h6+p {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body li p.first {
|
||||
display: inline-block;
|
||||
}
|
||||
.markdown-body ul,
|
||||
.markdown-body ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
.markdown-body ul li>:first-child,
|
||||
.markdown-body ol li>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body ul li>:last-child,
|
||||
.markdown-body ol li>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body dl {
|
||||
padding: 0;
|
||||
}
|
||||
.markdown-body dl dt {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
padding: 0;
|
||||
margin: 15px 0 5px;
|
||||
}
|
||||
.markdown-body dl dt:first-child {
|
||||
padding: 0;
|
||||
}
|
||||
.markdown-body dl dt>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body dl dt>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body dl dd {
|
||||
margin: 0 0 15px;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.markdown-body dl dd>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body dl dd>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body blockquote {
|
||||
border-left: 4px solid #DDD;
|
||||
padding: 0 15px;
|
||||
color: #777;
|
||||
}
|
||||
.markdown-body blockquote>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body blockquote>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body table {
|
||||
padding: 0;
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0 0;
|
||||
padding: 0;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
#template table * tr {
|
||||
.markdown-body table tr {
|
||||
border-top: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#template table * tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
#template table * tr th,
|
||||
#template table * tr td {
|
||||
border: 1px solid #ccc;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px;
|
||||
}
|
||||
|
||||
/* Images & Stuff */
|
||||
#template img {
|
||||
.markdown-body table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
.markdown-body table tr th {
|
||||
font-weight: bold;
|
||||
}
|
||||
.markdown-body table tr th,
|
||||
.markdown-body table tr td {
|
||||
border: 1px solid #ccc;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px;
|
||||
}
|
||||
.markdown-body table tr th>:first-child,
|
||||
.markdown-body table tr td>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body table tr th>:last-child,
|
||||
.markdown-body table tr td>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Gollum Image Tags */
|
||||
|
||||
/* Framed */
|
||||
#template span.frame {
|
||||
.markdown-body span.frame {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#template span.frame > span {
|
||||
border: 1px solid #ddd;
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
padding: 7px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#template span.frame span img {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#template span.frame span span {
|
||||
clear: both;
|
||||
color: #333;
|
||||
display: block;
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
|
||||
#template span.align-center {
|
||||
.markdown-body span.frame>span {
|
||||
border: 1px solid #ddd;
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
padding: 7px;
|
||||
width: auto;
|
||||
}
|
||||
.markdown-body span.frame span img {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
.markdown-body span.frame span span {
|
||||
clear: both;
|
||||
color: #333;
|
||||
display: block;
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
.markdown-body span.align-center {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#template span.align-center > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#template span.align-center span img {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#template span.align-right {
|
||||
.markdown-body span.align-center>span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: center;
|
||||
}
|
||||
.markdown-body span.align-center span img {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
.markdown-body span.align-right {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#template span.align-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#template span.align-right span img {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#template span.float-left {
|
||||
.markdown-body span.align-right>span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
text-align: right;
|
||||
}
|
||||
.markdown-body span.align-right span img {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
}
|
||||
.markdown-body span.float-left {
|
||||
display: block;
|
||||
margin-right: 13px;
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#template span.float-left span {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
|
||||
#template span.float-right {
|
||||
.markdown-body span.float-left span {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
.markdown-body span.float-right {
|
||||
display: block;
|
||||
margin-left: 13px;
|
||||
overflow: hidden;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#template span.float-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
/* Code */
|
||||
#template code, #template tt {
|
||||
.markdown-body span.float-right>span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: right;
|
||||
}
|
||||
.markdown-body code,
|
||||
.markdown-body tt {
|
||||
margin: 0 2px;
|
||||
padding: 0 5px;
|
||||
white-space: nowrap;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #dedede;
|
||||
font-size: 13px;
|
||||
padding: 0;
|
||||
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#template .highlight pre, #template pre {
|
||||
.markdown-body pre>tt,
|
||||
.markdown-body pre>code {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
.markdown-body pre {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font: 12px 'Bitstream Vera Sans Mono','Courier',monospace
|
||||
}
|
||||
|
||||
#template pre code, #template pre tt {
|
||||
.markdown-body pre pre,
|
||||
.markdown-body pre code,
|
||||
.markdown-body pre tt {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/*
|
||||
Highlight rules from pull req 191
|
||||
https://github.com/eboto/gollum/commit/5df09477abf4a04c82c7fcaa2bd7ee2a85e7ec82
|
||||
*/
|
||||
#template .highlight { background:#fff; }
|
||||
#template .highlight .c { color:#998;font-style:italic; }
|
||||
#template .highlight .err { color:#a61717;background-color:#e3d2d2; }
|
||||
#template .highlight .k { font-weight:bold; }
|
||||
#template .highlight .o { font-weight:bold; }
|
||||
#template .highlight .cm { color:#998;font-style:italic; }
|
||||
#template .highlight .cp { color:#999;font-weight:bold; }
|
||||
#template .highlight .c1 { color:#998;font-style:italic; }
|
||||
#template .highlight .cs { color:#999;font-weight:bold;font-style:italic; }
|
||||
#template .highlight .gd { color:#000;background-color:#fdd; }
|
||||
#template .highlight .gd .x { color:#000;background-color:#faa; }
|
||||
#template .highlight .ge { font-style:italic; }
|
||||
#template .highlight .gr { color:#a00; }
|
||||
#template .highlight .gh { color:#999; }
|
||||
#template .highlight .gi { color:#000;background-color:#dfd; }
|
||||
#template .highlight .gi .x { color:#000;background-color:#afa; }
|
||||
#template .highlight .go { color:#888; }
|
||||
#template .highlight .gp { color:#555; }
|
||||
#template .highlight .gs { font-weight:bold; }
|
||||
#template .highlight .gu { color:#800080;font-weight:bold; }
|
||||
#template .highlight .gt { color:#a00; }
|
||||
#template .highlight .kc { font-weight:bold; }
|
||||
#template .highlight .kd { font-weight:bold; }
|
||||
#template .highlight .kp { font-weight:bold; }
|
||||
#template .highlight .kr { font-weight:bold; }
|
||||
#template .highlight .kt { color:#458;font-weight:bold; }
|
||||
#template .highlight .m { color:#099; }
|
||||
#template .highlight .s { color:#d14; }
|
||||
#template .highlight .na { color:#008080; }
|
||||
#template .highlight .nb { color:#0086B3; }
|
||||
#template .highlight .nc { color:#458;font-weight:bold; }
|
||||
#template .highlight .no { color:#008080; }
|
||||
#template .highlight .ni { color:#800080; }
|
||||
#template .highlight .ne { color:#900;font-weight:bold; }
|
||||
#template .highlight .nf { color:#900;font-weight:bold; }
|
||||
#template .highlight .nn { color:#555; }
|
||||
#template .highlight .nt { color:#000080; }
|
||||
#template .highlight .nv { color:#008080; }
|
||||
#template .highlight .ow { font-weight:bold; }
|
||||
#template .highlight .w { color:#bbb; }
|
||||
#template .highlight .mf { color:#099; }
|
||||
#template .highlight .mh { color:#099; }
|
||||
#template .highlight .mi { color:#099; }
|
||||
#template .highlight .mo { color:#099; }
|
||||
#template .highlight .sb { color:#d14; }
|
||||
#template .highlight .sc { color:#d14; }
|
||||
#template .highlight .sd { color:#d14; }
|
||||
#template .highlight .s2 { color:#d14; }
|
||||
#template .highlight .se { color:#d14; }
|
||||
#template .highlight .sh { color:#d14; }
|
||||
#template .highlight .si { color:#d14; }
|
||||
#template .highlight .sx { color:#d14; }
|
||||
#template .highlight .sr { color:#009926; }
|
||||
#template .highlight .s1 { color:#d14; }
|
||||
#template .highlight .ss { color:#990073; }
|
||||
#template .highlight .bp { color:#999; }
|
||||
#template .highlight .vc { color:#008080; }
|
||||
#template .highlight .vg { color:#008080; }
|
||||
#template .highlight .vi { color:#008080; }
|
||||
#template .highlight .il { color:#099; }
|
||||
.markdown-body pre pre {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.toc {
|
||||
background-color: #F7F7F7;
|
||||
border: 1px solid #ddd;
|
||||
padding: 5px 10px;
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.toc-title {
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
padding: 2px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.toc ul {
|
||||
padding-left: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
.toc>ul {
|
||||
margin-left: 10px;
|
||||
font-size: 17px;
|
||||
}
|
||||
.toc ul ul {
|
||||
font-size: 15px;
|
||||
}
|
||||
.toc ul ul ul {
|
||||
font-size: 14px;
|
||||
}
|
||||
.toc ul li{
|
||||
margin: 0;
|
||||
}
|
||||
#header-content .toc,
|
||||
#footer-content .toc,
|
||||
#sidebar-content .toc {
|
||||
border: none;
|
||||
}
|
||||
.highlight {
|
||||
background: #fff;
|
||||
}
|
||||
.highlight .c {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
.highlight .err {
|
||||
color: #a61717;
|
||||
background-color: #e3d2d2;
|
||||
}
|
||||
.highlight .k {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .o {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .cm {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
.highlight .cp {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .c1 {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
.highlight .cs {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
.highlight .gd {
|
||||
color: #000;
|
||||
background-color: #fdd;
|
||||
}
|
||||
.highlight .gd .x {
|
||||
color: #000;
|
||||
background-color: #faa;
|
||||
}
|
||||
.highlight .ge {
|
||||
font-style: italic;
|
||||
}
|
||||
.highlight .gr {
|
||||
color: #a00;
|
||||
}
|
||||
.highlight .gh {
|
||||
color: #999;
|
||||
}
|
||||
.highlight .gi {
|
||||
color: #000;
|
||||
background-color: #dfd;
|
||||
}
|
||||
.highlight .gi .x {
|
||||
color: #000;
|
||||
background-color: #afa;
|
||||
}
|
||||
.highlight .go {
|
||||
color: #888;
|
||||
}
|
||||
.highlight .gp {
|
||||
color: #555;
|
||||
}
|
||||
.highlight .gs {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .gu {
|
||||
color: #800080;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .gt {
|
||||
color: #a00;
|
||||
}
|
||||
.highlight .kc {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .kd {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .kn {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .kp {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .kr {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .kt {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .m {
|
||||
color: #099;
|
||||
}
|
||||
.highlight .s {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .na {
|
||||
color: #008080;
|
||||
}
|
||||
.highlight .nb {
|
||||
color: #0086B3;
|
||||
}
|
||||
.highlight .nc {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .no {
|
||||
color: #008080;
|
||||
}
|
||||
.highlight .ni {
|
||||
color: #800080;
|
||||
}
|
||||
.highlight .ne {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .nf {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .nn {
|
||||
color: #555;
|
||||
}
|
||||
.highlight .nt {
|
||||
color: #000080;
|
||||
}
|
||||
.highlight .nv {
|
||||
color: #008080;
|
||||
}
|
||||
.highlight .ow {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .w {
|
||||
color: #bbb;
|
||||
}
|
||||
.highlight .mf {
|
||||
color: #099;
|
||||
}
|
||||
.highlight .mh {
|
||||
color: #099;
|
||||
}
|
||||
.highlight .mi {
|
||||
color: #099;
|
||||
}
|
||||
.highlight .mo {
|
||||
color: #099;
|
||||
}
|
||||
.highlight .sb {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .sc {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .sd {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .s2 {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .se {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .sh {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .si {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .sx {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .sr {
|
||||
color: #009926;
|
||||
}
|
||||
.highlight .s1 {
|
||||
color: #d14;
|
||||
}
|
||||
.highlight .ss {
|
||||
color: #990073;
|
||||
}
|
||||
.highlight .bp {
|
||||
color: #999;
|
||||
}
|
||||
.highlight .vc {
|
||||
color: #008080;
|
||||
}
|
||||
.highlight .vg {
|
||||
color: #008080;
|
||||
}
|
||||
.highlight .vi {
|
||||
color: #008080;
|
||||
}
|
||||
.highlight .il {
|
||||
color: #099;
|
||||
}
|
||||
.highlight .gc {
|
||||
color: #999;
|
||||
background-color: #EAF2F5;
|
||||
}
|
||||
.type-csharp .highlight .k {
|
||||
color: #00F;
|
||||
}
|
||||
.type-csharp .highlight .kt {
|
||||
color: #00F;
|
||||
}
|
||||
.type-csharp .highlight .nf {
|
||||
color: #000;
|
||||
font-weight: normal;
|
||||
}
|
||||
.type-csharp .highlight .nc {
|
||||
color: #2B91AF;
|
||||
}
|
||||
.type-csharp .highlight .nn {
|
||||
color: #000;
|
||||
}
|
||||
.type-csharp .highlight .s {
|
||||
color: #A31515;
|
||||
}
|
||||
.type-csharp .highlight .sc {
|
||||
color: #A31515;
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 939 B |
|
After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 271 B |
|
After Width: | Height: | Size: 433 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
@@ -24,7 +24,6 @@
|
||||
* You don't need to do anything. Just run this on DOM ready.
|
||||
*/
|
||||
$.GollumEditor = function( IncomingOptions ) {
|
||||
|
||||
ActiveOptions = $.extend( DefaultOptions, IncomingOptions );
|
||||
|
||||
debug('GollumEditor loading');
|
||||
@@ -64,6 +63,8 @@
|
||||
var $form = $($('#gollum-editor form').get(0));
|
||||
$form.attr('action', this.href || '/preview');
|
||||
$form.attr('target', '_blank');
|
||||
var paths = window.location.pathname.split('/');
|
||||
$form.attr('page', paths[ paths.length - 1 ] || '')
|
||||
$form.submit();
|
||||
|
||||
|
||||
@@ -94,11 +95,8 @@
|
||||
$('#gollum-editor-help').hide();
|
||||
$('#gollum-editor-help').removeClass('jaws');
|
||||
}
|
||||
|
||||
}
|
||||
// EditorHas.functionBar
|
||||
}
|
||||
// EditorHas.baseEditorMarkup
|
||||
} // EditorHas.functionBar
|
||||
} // EditorHas.baseEditorMarkup
|
||||
};
|
||||
|
||||
|
||||
@@ -168,6 +166,11 @@
|
||||
},
|
||||
|
||||
setActiveLanguage: function( name ) {
|
||||
// On first load _ACTIVE_LANG.length is 0 and evtChangeFormat isn't called.
|
||||
if ( LanguageDefinition._ACTIVE_LANG != null && LanguageDefinition._ACTIVE_LANG.length <= 0 ) {
|
||||
FormatSelector.updateCommitMessage( name );
|
||||
}
|
||||
|
||||
if(LanguageDefinition.getHookFunctionFor("deactivate")) {
|
||||
LanguageDefinition.getHookFunctionFor("deactivate")();
|
||||
}
|
||||
@@ -192,6 +195,18 @@
|
||||
if(LanguageDefinition.getHookFunctionFor("activate")) {
|
||||
LanguageDefinition.getHookFunctionFor("activate")();
|
||||
}
|
||||
|
||||
function hotkey( cmd ) {
|
||||
var def = LanguageDefinition.getDefinitionFor( cmd );
|
||||
if ( typeof def == 'object' ) {
|
||||
FunctionBar.executeAction( def );
|
||||
}
|
||||
// Prevent bubbling of hotkey.
|
||||
return false;
|
||||
}
|
||||
|
||||
Mousetrap.bind(['command+b', 'ctrl+b'], function(){ hotkey('function-bold'); });
|
||||
Mousetrap.bind(['command+i', 'ctrl+i'], function(){ hotkey('function-italic'); });
|
||||
} );
|
||||
} else {
|
||||
LanguageDefinition._ACTIVE_LANG = name;
|
||||
@@ -262,7 +277,7 @@
|
||||
}
|
||||
|
||||
// attempt to load the definition for this language
|
||||
var script_uri = '/javascript/editor/langs/' + markup_name + '.js';
|
||||
var script_uri = baseUrl + '/javascript/editor/langs/' + markup_name + '.js';
|
||||
$.ajax({
|
||||
url: script_uri,
|
||||
dataType: 'script',
|
||||
@@ -747,9 +762,18 @@
|
||||
*/
|
||||
evtChangeFormat: function( e ) {
|
||||
var newMarkup = $(this).val();
|
||||
FormatSelector.updateCommitMessage( newMarkup );
|
||||
LanguageDefinition.setActiveLanguage( newMarkup );
|
||||
},
|
||||
|
||||
updateCommitMessage: function( newMarkup ) {
|
||||
var msg = document.getElementById( "gollum-editor-message-field" );
|
||||
var val = msg.value;
|
||||
// Must start with created or updated.
|
||||
if (/^(?:created|updated)/i.test(val)) {
|
||||
msg.value = val.replace( /\([^\)]*\)$/, "(" + newMarkup + ")" );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* FormatSelector.init
|
||||
|
||||
@@ -47,7 +47,8 @@ var ASCIIDoc = {
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
help: 'The text to display to the user.'
|
||||
help: 'The text to display to the user.',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
|
||||
@@ -46,7 +46,8 @@ var Creole = {
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
help: 'The text to display to the user.'
|
||||
help: 'The text to display to the user.',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
|
||||
@@ -32,7 +32,7 @@ var MarkDown = {
|
||||
},
|
||||
|
||||
'function-code' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
search: /([^\n]+)([\n\s]*)/g,
|
||||
replace: "`$1`$2"
|
||||
},
|
||||
|
||||
@@ -44,11 +44,22 @@ var MarkDown = {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
/* This looks silly but is completely valid Markdown */
|
||||
/* based on rdoc.js */
|
||||
'function-ol' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "1. $1$2"
|
||||
exec: function( txt, selText, $field ) {
|
||||
var count = 1;
|
||||
// split into lines
|
||||
var repText = '';
|
||||
var lines = selText.split("\n");
|
||||
var hasContent = /[\w]+/;
|
||||
for ( var i = 0; i < lines.length; i++ ) {
|
||||
if ( hasContent.test(lines[i]) ) {
|
||||
repText += (i + 1).toString() + '. ' +
|
||||
lines[i] + "\n";
|
||||
}
|
||||
}
|
||||
$.GollumEditor.replaceSelection( repText );
|
||||
}
|
||||
},
|
||||
|
||||
'function-blockquote' : {
|
||||
@@ -80,7 +91,8 @@ var MarkDown = {
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
|
||||
@@ -60,7 +60,8 @@ var OrgMode = {
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
|
||||
@@ -44,7 +44,8 @@ var Pod = {
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
|
||||
@@ -49,7 +49,8 @@ var Textile = {
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
help: 'The text to display to the user.'
|
||||
help: 'The text to display to the user.',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
if ( fieldAttributes.type == 'code' ) {
|
||||
html+= ' class="code"';
|
||||
}
|
||||
if ( fieldAttributes.defaultValue ) {
|
||||
html+= ' value="' + fieldAttributes.defaultValue.split('"').join('"') + '"';
|
||||
}
|
||||
html += ' id="gollum-dialog-dialog-generated-field-' +
|
||||
fieldAttributes.id + '">';
|
||||
}
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
// ua
|
||||
$(document).ready(function() {
|
||||
$('#delete-link').click( function(e) {
|
||||
var ok = confirm($(this).data('confirm'));
|
||||
if ( ok ) {
|
||||
var loc = window.location;
|
||||
loc = baseUrl + '/delete' + loc.pathname.replace(baseUrl,'');
|
||||
window.location = loc;
|
||||
}
|
||||
// Don't navigate on cancel.
|
||||
e.preventDefault();
|
||||
} );
|
||||
|
||||
var nodeSelector = {
|
||||
node1: null,
|
||||
node2: null,
|
||||
@@ -97,27 +108,70 @@ $(document).ready(function() {
|
||||
}
|
||||
}
|
||||
|
||||
if ($('#minibutton-rename-page').length) {
|
||||
$('#minibutton-rename-page').removeClass('jaws');
|
||||
$('#minibutton-rename-page').click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Path name without the leading slash.
|
||||
var pathname = window.location.pathname.substr(1);
|
||||
var slashIndex = pathname.lastIndexOf('/');
|
||||
var oldName = pathname.substr(slashIndex + 1)
|
||||
var path = pathname.substr(0, slashIndex);
|
||||
|
||||
$.GollumDialog.init({
|
||||
title: 'Rename Page',
|
||||
fields: [
|
||||
{
|
||||
id: 'name',
|
||||
name: 'Rename to',
|
||||
type: 'text',
|
||||
defaultValue: oldName || ''
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var newName = 'Rename Page';
|
||||
if ( res['name'] ) {
|
||||
newName = res['name'];
|
||||
}
|
||||
|
||||
var msg = 'Renamed ' + oldName + ' to ' + newName;
|
||||
jQuery.ajax( {
|
||||
type: 'POST',
|
||||
url: baseUrl + '/edit/' + oldName,
|
||||
data: { path: path, rename: newName, page: oldName, message: msg },
|
||||
success: function() {
|
||||
window.location = baseUrl + '/' + encodeURIComponent(newName);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ($('#minibutton-new-page').length) {
|
||||
$('#minibutton-new-page').removeClass('jaws');
|
||||
$('#minibutton-new-page').click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.GollumDialog.init({
|
||||
title: 'Create New Page',
|
||||
fields: [
|
||||
{
|
||||
id: 'name',
|
||||
name: 'Page Name',
|
||||
type: 'text'
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var n = 'New Page';
|
||||
if ( res['name'] )
|
||||
var n = res['name'];
|
||||
n = encodeURIComponent( n );
|
||||
window.location = '/' + n;
|
||||
}
|
||||
});
|
||||
title: 'Create New Page',
|
||||
fields: [
|
||||
{
|
||||
id: 'name',
|
||||
name: 'Page Name',
|
||||
type: 'text',
|
||||
defaultValue: ''
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var name = 'New Page';
|
||||
if ( res['name'] ) {
|
||||
name = res['name'];
|
||||
}
|
||||
window.location = baseUrl + '/' + encodeURIComponent(name);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/* mousetrap v1.1.2 craig.is/killing/mice */
|
||||
window.Mousetrap=function(){function o(a,c,b){if(a.addEventListener)return a.addEventListener(c,b,!1);a.attachEvent("on"+c,b)}function u(a){return"keypress"==a.type?String.fromCharCode(a.which):h[a.which]?h[a.which]:v[a.which]?v[a.which]:String.fromCharCode(a.which).toLowerCase()}function p(a){var a=a||{},c=!1,b;for(b in l)a[b]?c=!0:l[b]=0;c||(n=!1)}function w(a,c,b,d,C){var g,e,f=[];if(!j[a])return[];"keyup"==b&&q(a)&&(c=[a]);for(g=0;g<j[a].length;++g)if(e=j[a][g],!(e.seq&&l[e.seq]!=e.level)&&b==
|
||||
e.action&&("keypress"==b||c.sort().join(",")===e.modifiers.sort().join(",")))d&&e.combo==C&&j[a].splice(g,1),f.push(e);return f}function r(a,c){!1===a(c)&&(c.preventDefault&&c.preventDefault(),c.stopPropagation&&c.stopPropagation(),c.returnValue=!1,c.cancelBubble=!0)}function s(a){a.which="number"==typeof a.which?a.which:a.keyCode;var c=u(a);if(c)if("keyup"==a.type&&t==c)t=!1;else{var b=a.target||a.srcElement,d=b.tagName;if(!(-1<(" "+b.className+" ").indexOf(" mousetrap ")?0:"INPUT"==d||"SELECT"==
|
||||
d||"TEXTAREA"==d||b.contentEditable&&"true"==b.contentEditable)){b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");for(var b=w(c,b,a.type),f={},g=!1,d=0;d<b.length;++d)b[d].seq?(g=!0,f[b[d].seq]=1,r(b[d].callback,a)):!g&&!n&&r(b[d].callback,a);a.type==n&&!q(c)&&p(f)}}}function q(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function x(a,c,b){if(!b){if(!k){k={};for(var d in h)95<d&&112>d||h.hasOwnProperty(d)&&(k[h[d]]=d)}b=k[a]?"keydown":
|
||||
"keypress"}"keypress"==b&&c.length&&(b="keydown");return b}function y(a,c,b,d,f){var a=a.replace(/\s+/g," "),g=a.split(" "),e,h,i=[];if(1<g.length){var k=a,m=b;l[k]=0;m||(m=x(g[0],[]));a=function(){n=m;++l[k];clearTimeout(z);z=setTimeout(p,1E3)};b=function(a){r(c,a);"keyup"!==m&&(t=u(a));setTimeout(p,10)};for(d=0;d<g.length;++d)y(g[d],d<g.length-1?a:b,m,k,d)}else{h="+"===a?["+"]:a.split("+");for(g=0;g<h.length;++g)e=h[g],A[e]&&(e=A[e]),b&&("keypress"!=b&&B[e])&&(e=B[e],i.push("shift")),q(e)&&i.push(e);
|
||||
b=x(e,i,b);j[e]||(j[e]=[]);w(e,i,b,!d,a);j[e][d?"unshift":"push"]({callback:c,modifiers:i,action:b,seq:d,level:f,combo:a})}}for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},v={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},B=
|
||||
{"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},A={option:"alt",command:"meta","return":"enter",escape:"esc"},k,j={},i={},l={},z,t=!1,n=!1,f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;o(document,"keypress",s);o(document,"keydown",s);o(document,"keyup",s);return{bind:function(a,c,b){for(var d=a instanceof Array?a:[a],f=0;f<d.length;++f)y(d[f],c,b);i[a+":"+b]=c},unbind:function(a,c){i[a+
|
||||
":"+c]&&(delete i[a+":"+c],this.bind(a,function(){},c))},trigger:function(a,c){i[a+":"+c]()},reset:function(){j={};i={}}}}();
|
||||
@@ -0,0 +1,132 @@
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#editor .ace_sb {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
#darkness {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
background-color: black;
|
||||
opacity: 0.8;
|
||||
z-index: 1001; /* must be > 1000 to overlay ace gutter */
|
||||
}
|
||||
|
||||
#commenttoolpanel {
|
||||
visibility: hidden;
|
||||
z-index: 1002; /* > 1001 to not be hidden by darkness */
|
||||
}
|
||||
|
||||
#comment, #editor {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
/* Set font size of both ace editors. */
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/*
|
||||
Must set ace-line to preserve whitespace in empty lines.
|
||||
Ace editor sets the height inline. The static highlight ext does not.
|
||||
<div class="ace_line" style="height:15px"></div>
|
||||
*/
|
||||
#previewframe #contentframe .ace-github .ace_editor.ace_scroller.ace_text-layer .ace_line {
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
/* Set comment to have a higher z-index
|
||||
so editor doesn't display in the background. */
|
||||
|
||||
#comment {
|
||||
visibility: hidden;
|
||||
z-index: 1003; /* > 1002 to not be hidden by toolpanel */
|
||||
}
|
||||
|
||||
#contentframe {
|
||||
margin: 0 auto;
|
||||
overflow: visible;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#previewframe {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 10px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.editor_bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: black;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
.toolpanel_bg {
|
||||
position: fixed;
|
||||
background: #666;
|
||||
top: 0;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
margin: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* -- Start from notepag.es -- */
|
||||
.toolpanel {
|
||||
position: fixed;
|
||||
background: #666;
|
||||
top: 0;
|
||||
height: 30px;
|
||||
width: 50%;
|
||||
vertical-align: middle;
|
||||
padding: 5px 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.toolpanel.edit a.edit {
|
||||
opacity: 0.4;
|
||||
/* Make it appear as a link even though save
|
||||
doesn't have a href attribute. */
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.toolpanel a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin: 0 5px;
|
||||
display: none;
|
||||
padding: 4px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.toolpanel a img {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
/* -- End from notepag.es -- */
|
||||
|
After Width: | Height: | Size: 525 B |
|
After Width: | Height: | Size: 757 B |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 278 B |
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Live Preview</title>
|
||||
<link rel='stylesheet' type='text/css' href='../css/template.css' />
|
||||
<link rel='stylesheet' type='text/css' href='css/custom.css' />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id='editor'></div>
|
||||
<div id='previewframe'><div id='contentframe' class='markdown-body'></div></div>
|
||||
<!-- tool panel from notepage.es. save & savecomment icons from Retina Display Icon Set. -->
|
||||
<div id='toolpanel' class='toolpanel edit' style='width: 500px; right: 0px; visibility: hidden;'>
|
||||
<a id='save' class='edit'><img src='images/save_24.png' alt='Save' title='Save'></a>
|
||||
<a id='savecomment' class='edit'><img src='images/savecomment_24.png' alt='Save with comment' title='Save with comment'></a>
|
||||
<a id='toggle' class='edit' href='javascript:void(0)' onclick='jsm.toggleLeftRight();'><img src='images/lr_24.png' alt='Toggle left to right' title='Toggle left to right'></a>
|
||||
</div>
|
||||
|
||||
<div class='editor_bg'></div>
|
||||
<div class='toolpanel_bg'></div>
|
||||
|
||||
<div id='commenttoolpanel' class='toolpanel edit' style='width: 500px; right: 0px; '>
|
||||
<a id='savecommentconfirm' class='edit'><img src='images/savecomment_24.png' alt='Confirm save with comment' title='Confirm save with comment'></a>
|
||||
<a id='commentcancel' class='edit'><img src='images/cancel_24.png' alt='Cancel save with comment' title='Cancel save with comment'></a>
|
||||
</div>
|
||||
<div id='comment'></div>
|
||||
<div id='darkness'></div>
|
||||
|
||||
<script>
|
||||
var require = {
|
||||
paths: {
|
||||
ace: 'js/ace/lib/ace'
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src='js/requirejs.min.js'></script>
|
||||
<script src='../javascript/jquery-1.7.2.min.js'></script>
|
||||
<script src='js/jquery.ba-throttle-debounce.min.js'></script>
|
||||
<script src='js/sundown.js'></script>
|
||||
<script src='js/md_sundown.js'></script>
|
||||
<script src='js/livepreview.js'></script>
|
||||
<!--<script>(function(d,j){
|
||||
j = d.createElement('script');
|
||||
j.src = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML';
|
||||
(d.head || d.getElementsByTagName('head')[0]).appendChild(j);
|
||||
}(document));
|
||||
</script>-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,103 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kevin Dangoor (kdangoor@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* class Ace
|
||||
*
|
||||
* The main class required to set up an Ace instance in the browser.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
require("./lib/fixoldbrowsers");
|
||||
|
||||
var Dom = require("./lib/dom");
|
||||
var Event = require("./lib/event");
|
||||
|
||||
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("./keyboard/state_handler");
|
||||
require("./placeholder");
|
||||
exports.config = require("./config");
|
||||
/**
|
||||
* Ace.edit(el) -> Editor
|
||||
* - el (String | DOMElement): Either the id of an element, or the element itself
|
||||
*
|
||||
* This method embeds the Ace editor into the DOM, at the element provided by `el`.
|
||||
*
|
||||
**/
|
||||
exports.edit = function(el) {
|
||||
if (typeof(el) == "string") {
|
||||
el = document.getElementById(el);
|
||||
}
|
||||
|
||||
if (el.env && el.env.editor instanceof Editor)
|
||||
return el.env.editor;
|
||||
|
||||
var doc = new EditSession(Dom.getInnerText(el));
|
||||
doc.setUndoManager(new UndoManager());
|
||||
el.innerHTML = '';
|
||||
|
||||
var editor = new Editor(new Renderer(el, require("./theme/textmate")));
|
||||
new MultiSelect(editor);
|
||||
editor.setSession(doc);
|
||||
|
||||
var env = {};
|
||||
env.document = doc;
|
||||
env.editor = editor;
|
||||
editor.resize();
|
||||
Event.addListener(window, "resize", function() {
|
||||
editor.resize();
|
||||
});
|
||||
el.env = env;
|
||||
// Store env on editor such that it can be accessed later on from
|
||||
// the returned object.
|
||||
editor.env = env;
|
||||
return editor;
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,254 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
|
||||
/**
|
||||
* class Anchor
|
||||
*
|
||||
* Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new Anchor(doc, row, column)
|
||||
* - doc (Document): The document to associate with the anchor
|
||||
* - row (Number): The starting row position
|
||||
* - column (Number): The starting column position
|
||||
*
|
||||
* Creates a new `Anchor` and associates it with a document.
|
||||
*
|
||||
**/
|
||||
|
||||
var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
this.document = 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() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
/**
|
||||
* Anchor.getPosition() -> Object
|
||||
*
|
||||
* Returns an object identifying the `row` and `column` position of the current anchor.
|
||||
*
|
||||
**/
|
||||
|
||||
this.getPosition = function() {
|
||||
return this.$clipPositionToDocument(this.row, this.column);
|
||||
};
|
||||
|
||||
/**
|
||||
* Anchor.getDocument() -> Document
|
||||
*
|
||||
* Returns the current document.
|
||||
*
|
||||
**/
|
||||
|
||||
this.getDocument = function() {
|
||||
return this.document;
|
||||
};
|
||||
|
||||
/**
|
||||
* Anchor@onChange(e)
|
||||
* - e (Event): Contains data about the event
|
||||
*
|
||||
* Fires whenever the anchor position changes. Events that can trigger this function include `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
*
|
||||
**/
|
||||
|
||||
this.onChange = function(e) {
|
||||
var delta = e.data;
|
||||
var range = delta.range;
|
||||
|
||||
if (range.start.row == range.end.row && range.start.row != this.row)
|
||||
return;
|
||||
|
||||
if (range.start.row > this.row)
|
||||
return;
|
||||
|
||||
if (range.start.row == this.row && range.start.column > this.column)
|
||||
return;
|
||||
|
||||
var row = this.row;
|
||||
var column = this.column;
|
||||
|
||||
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;
|
||||
}
|
||||
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 (delta.action === "insertLines") {
|
||||
if (range.start.row <= row) {
|
||||
row += range.end.row - range.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
|
||||
column = Math.max(0, column - (range.end.column - range.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 (delta.action == "removeLines") {
|
||||
if (range.start.row <= row) {
|
||||
if (range.end.row <= row)
|
||||
row -= range.end.row - range.start.row;
|
||||
else {
|
||||
row = range.start.row;
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setPosition(row, column, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Anchor.setPosition(row, column, noClip)
|
||||
* - row (Number): The row index to move the anchor to
|
||||
* - column (Number): The column index to move the anchor to
|
||||
* - noClip (Boolean): Identifies if you want the position to be clipped
|
||||
*
|
||||
* Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped.
|
||||
*
|
||||
**/
|
||||
|
||||
this.setPosition = function(row, column, noClip) {
|
||||
var pos;
|
||||
if (noClip) {
|
||||
pos = {
|
||||
row: row,
|
||||
column: column
|
||||
};
|
||||
}
|
||||
else {
|
||||
pos = this.$clipPositionToDocument(row, column);
|
||||
}
|
||||
|
||||
if (this.row == pos.row && this.column == pos.column)
|
||||
return;
|
||||
|
||||
var old = {
|
||||
row: this.row,
|
||||
column: this.column
|
||||
};
|
||||
|
||||
this.row = pos.row;
|
||||
this.column = pos.column;
|
||||
this._emit("change", {
|
||||
old: old,
|
||||
value: pos
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Anchor.detach()
|
||||
*
|
||||
* When called, the `'change'` event listener is removed.
|
||||
*
|
||||
**/
|
||||
|
||||
this.detach = function() {
|
||||
this.document.removeEventListener("change", this.$onChange);
|
||||
};
|
||||
|
||||
/** internal, hide
|
||||
* Anchor.clipPositionToDocument(row, column)
|
||||
* - row (Number): The row index to clip the anchor to
|
||||
* - column (Number): The column index to clip the anchor to
|
||||
*
|
||||
* Clips the anchor position to the specified row and column.
|
||||
*
|
||||
**/
|
||||
|
||||
this.$clipPositionToDocument = function(row, column) {
|
||||
var pos = {};
|
||||
|
||||
if (row >= this.document.getLength()) {
|
||||
pos.row = Math.max(0, this.document.getLength() - 1);
|
||||
pos.column = this.document.getLine(pos.row).length;
|
||||
}
|
||||
else if (row < 0) {
|
||||
pos.row = 0;
|
||||
pos.column = 0;
|
||||
}
|
||||
else {
|
||||
pos.row = row;
|
||||
pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
|
||||
}
|
||||
|
||||
if (column < 0)
|
||||
pos.column = 0;
|
||||
|
||||
return pos;
|
||||
};
|
||||
|
||||
}).call(Anchor.prototype);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,184 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Document = require("./document").Document;
|
||||
var Anchor = require("./anchor").Anchor;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test create anchor" : function() {
|
||||
var doc = new Document("juhu");
|
||||
var anchor = new Anchor(doc, 0, 0);
|
||||
|
||||
assert.position(anchor.getPosition(), 0, 0);
|
||||
assert.equal(anchor.getDocument(), doc);
|
||||
},
|
||||
|
||||
"test insert text in same row before cursor should move anchor column": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.insert({row: 1, column: 1}, "123");
|
||||
assert.position(anchor.getPosition(), 1, 7);
|
||||
},
|
||||
|
||||
"test insert lines before cursor should move anchor row": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.insertLines(1, ["123", "456"]);
|
||||
assert.position(anchor.getPosition(), 3, 4);
|
||||
},
|
||||
|
||||
"test insert new line before cursor should move anchor column": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.insertNewLine({row: 0, column: 0});
|
||||
assert.position(anchor.getPosition(), 2, 4);
|
||||
},
|
||||
|
||||
"test insert new line in anchor line before anchor should move anchor column and row": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.insertNewLine({row: 1, column: 2});
|
||||
assert.position(anchor.getPosition(), 2, 2);
|
||||
},
|
||||
|
||||
"test delete text in anchor line before anchor should move anchor column": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.remove(new Range(1, 1, 1, 3));
|
||||
assert.position(anchor.getPosition(), 1, 2);
|
||||
},
|
||||
|
||||
"test remove range which contains the anchor should move the anchor to the start of the range": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 0, 3);
|
||||
|
||||
doc.remove(new Range(0, 1, 1, 3));
|
||||
assert.position(anchor.getPosition(), 0, 1);
|
||||
},
|
||||
|
||||
"test delete character before the anchor should have no effect": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.remove(new Range(1, 4, 1, 5));
|
||||
assert.position(anchor.getPosition(), 1, 4);
|
||||
},
|
||||
|
||||
"test delete lines in anchor line before anchor should move anchor row": function() {
|
||||
var doc = new Document("juhu\n1\n2\nkinners");
|
||||
var anchor = new Anchor(doc, 3, 4);
|
||||
|
||||
doc.removeLines(1, 2);
|
||||
assert.position(anchor.getPosition(), 1, 4);
|
||||
},
|
||||
|
||||
"test remove new line before the cursor": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.removeNewLine(0);
|
||||
assert.position(anchor.getPosition(), 0, 8);
|
||||
},
|
||||
|
||||
"test delete range which contains the anchor should move anchor to the end of the range": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.remove(new Range(0, 2, 1, 2));
|
||||
assert.position(anchor.getPosition(), 0, 4);
|
||||
},
|
||||
|
||||
"test delete line which contains the anchor should move anchor to the end of the range": function() {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 1, 5);
|
||||
|
||||
doc.removeLines(1, 1);
|
||||
assert.position(anchor.getPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test remove after the anchor should have no effect": function() {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 1, 2);
|
||||
|
||||
doc.remove(new Range(1, 4, 2, 2));
|
||||
assert.position(anchor.getPosition(), 1, 2);
|
||||
},
|
||||
|
||||
"test anchor changes triggered by document changes should emit change event": function(next) {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 1, 5);
|
||||
|
||||
anchor.on("change", function(e) {
|
||||
assert.position(anchor.getPosition(), 0, 0);
|
||||
next();
|
||||
});
|
||||
|
||||
doc.remove(new Range(0, 0, 2, 1));
|
||||
},
|
||||
|
||||
"test only fire change event if position changes": function() {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 1, 5);
|
||||
|
||||
anchor.on("change", function(e) {
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
doc.remove(new Range(2, 0, 2, 1));
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* class BackgroundTokenizer
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new BackgroundTokenizer(tokenizer, editor)
|
||||
* - tokenizer (Tokenizer): The tokenizer to use
|
||||
* - editor (Editor): The editor to associate with
|
||||
*
|
||||
* Creates a new `BackgroundTokenizer` object.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
var BackgroundTokenizer = function(tokenizer, editor) {
|
||||
this.running = false;
|
||||
this.lines = [];
|
||||
this.states = [];
|
||||
this.currentLine = 0;
|
||||
this.tokenizer = tokenizer;
|
||||
|
||||
var self = this;
|
||||
|
||||
this.$worker = function() {
|
||||
if (!self.running) { return; }
|
||||
|
||||
var workerStart = new Date();
|
||||
var startLine = self.currentLine;
|
||||
var doc = self.doc;
|
||||
|
||||
var processedLines = 0;
|
||||
|
||||
var len = doc.getLength();
|
||||
while (self.currentLine < len) {
|
||||
self.$tokenizeRow(self.currentLine);
|
||||
while (self.lines[self.currentLine])
|
||||
self.currentLine++;
|
||||
|
||||
// only check every 5 lines
|
||||
processedLines ++;
|
||||
if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) {
|
||||
self.fireUpdateEvent(startLine, self.currentLine-1);
|
||||
self.running = setTimeout(self.$worker, 20);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.running = false;
|
||||
|
||||
self.fireUpdateEvent(startLine, len - 1);
|
||||
};
|
||||
};
|
||||
|
||||
(function(){
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.setTokenizer(tokenizer)
|
||||
* - tokenizer (Tokenizer): The new tokenizer to use
|
||||
*
|
||||
* Sets a new tokenizer for this object.
|
||||
*
|
||||
**/
|
||||
this.setTokenizer = function(tokenizer) {
|
||||
this.tokenizer = tokenizer;
|
||||
this.lines = [];
|
||||
this.states = [];
|
||||
|
||||
this.start(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.setDocument(doc)
|
||||
* - doc (Document): The new document to associate with
|
||||
*
|
||||
* Sets a new document to associate with this object.
|
||||
*
|
||||
**/
|
||||
this.setDocument = function(doc) {
|
||||
this.doc = doc;
|
||||
this.lines = [];
|
||||
this.states = [];
|
||||
|
||||
this.stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.fireUpdateEvent(firstRow, lastRow)
|
||||
* - firstRow (Number): The starting row region
|
||||
* - lastRow (Number): The final row region
|
||||
*
|
||||
* Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated.
|
||||
*
|
||||
**/
|
||||
this.fireUpdateEvent = function(firstRow, lastRow) {
|
||||
var data = {
|
||||
first: firstRow,
|
||||
last: lastRow
|
||||
};
|
||||
this._emit("update", {data: data});
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.start(startRow)
|
||||
* - startRow (Number): The row to start at
|
||||
*
|
||||
* Starts tokenizing at the row indicated.
|
||||
*
|
||||
**/
|
||||
this.start = function(startRow) {
|
||||
this.currentLine = Math.min(startRow || 0, this.currentLine, this.doc.getLength());
|
||||
|
||||
// remove all cached items below this line
|
||||
this.lines.splice(this.currentLine, this.lines.length);
|
||||
this.states.splice(this.currentLine, this.states.length);
|
||||
|
||||
this.stop();
|
||||
// pretty long delay to prevent the tokenizer from interfering with the user
|
||||
this.running = setTimeout(this.$worker, 700);
|
||||
};
|
||||
|
||||
this.$updateOnChange = function(delta) {
|
||||
var range = delta.range;
|
||||
var startRow = range.start.row;
|
||||
var len = range.end.row - startRow;
|
||||
|
||||
if (len === 0) {
|
||||
this.lines[startRow] = null;
|
||||
} else if (delta.action == "removeText" || delta.action == "removeLines") {
|
||||
this.lines.splice(startRow, len + 1, null);
|
||||
this.states.splice(startRow, len + 1, null);
|
||||
} else {
|
||||
var args = Array(len + 1);
|
||||
args.unshift(startRow, 1);
|
||||
this.lines.splice.apply(this.lines, args);
|
||||
this.states.splice.apply(this.states, args);
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.stop()
|
||||
*
|
||||
* Stops tokenizing.
|
||||
*
|
||||
**/
|
||||
this.stop = function() {
|
||||
if (this.running)
|
||||
clearTimeout(this.running);
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
/** related to: BackgroundTokenizer.$tokenizeRows
|
||||
* BackgroundTokenizer.getTokens(firstRow, lastRow) -> [Object]
|
||||
* - firstRow (Number): The row to start at
|
||||
* - lastRow (Number): The row to finish at
|
||||
*
|
||||
* Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows.
|
||||
*
|
||||
**/
|
||||
this.getTokens = function(row) {
|
||||
return this.lines[row] || this.$tokenizeRow(row);
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.getState(row) -> String
|
||||
* - row (Number): The row to start at
|
||||
*
|
||||
* [Returns the state of tokenization at the end of a row.]{: #BackgroundTokenizer.getState}
|
||||
**/
|
||||
this.getState = function(row) {
|
||||
if (this.currentLine == row)
|
||||
this.$tokenizeRow(row);
|
||||
return this.states[row] || "start";
|
||||
};
|
||||
|
||||
this.$tokenizeRow = function(row) {
|
||||
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";
|
||||
}
|
||||
|
||||
if (this.states[row] !== data.state) {
|
||||
this.states[row] = data.state;
|
||||
this.lines[row + 1] = null;
|
||||
if (this.currentLine > row + 1)
|
||||
this.currentLine = row + 1;
|
||||
} else if (this.currentLine == row) {
|
||||
this.currentLine = row + 1;
|
||||
}
|
||||
|
||||
return this.lines[row] = data.tokens;
|
||||
};
|
||||
|
||||
}).call(BackgroundTokenizer.prototype);
|
||||
|
||||
exports.BackgroundTokenizer = BackgroundTokenizer;
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <harutyun@c9.io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
function forceTokenize(session){
|
||||
for (var i = 0, l = session.getLength(); i < l; i++)
|
||||
session.getTokens(i)
|
||||
}
|
||||
|
||||
function testStates(session, states) {
|
||||
for (var i = 0, l = session.getLength(); i < l; i++)
|
||||
assert.equal(session.bgTokenizer.states[i], states[i])
|
||||
assert.ok(l == states.length)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test background tokenizer update on session change" : function() {
|
||||
var doc = new EditSession([
|
||||
"/*",
|
||||
"*/",
|
||||
"var juhu"
|
||||
]);
|
||||
doc.setMode("./mode/javascript")
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "start", "start"])
|
||||
|
||||
doc.remove(new Range(0,2,1,2))
|
||||
testStates(doc, [null, "start"])
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "comment"])
|
||||
|
||||
doc.insert({row:0, column:2}, "\n*/")
|
||||
testStates(doc, [undefined, undefined, "comment"])
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "start", "start"])
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
||||
|
||||
/**
|
||||
* class CommandManager
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new CommandManager(platform, commands)
|
||||
* - platform (String): Identifier for the platform; must be either `'mac'` or `'win'`
|
||||
* - commands (Array): A list of commands
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
var CommandManager = function(platform, commands) {
|
||||
this.platform = platform;
|
||||
this.commands = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
this.addCommands(commands);
|
||||
|
||||
this.setDefaultHandler("exec", function(e) {
|
||||
return e.command.exec(e.editor, e.args || {});
|
||||
});
|
||||
};
|
||||
|
||||
oop.inherits(CommandManager, HashHandler);
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.exec = function(command, editor, args) {
|
||||
if (typeof command === 'string')
|
||||
command = this.commands[command];
|
||||
|
||||
if (!command)
|
||||
return false;
|
||||
|
||||
if (editor && editor.$readOnly && !command.readOnly)
|
||||
return false;
|
||||
|
||||
var retvalue = this._emit("exec", {
|
||||
editor: editor,
|
||||
command: command,
|
||||
args: args
|
||||
});
|
||||
|
||||
return retvalue === false ? false : true;
|
||||
};
|
||||
|
||||
this.toggleRecording = function() {
|
||||
if (this.$inReplay)
|
||||
return;
|
||||
if (this.recording) {
|
||||
this.macro.pop();
|
||||
this.removeEventListener("exec", this.$addCommandToMacro);
|
||||
|
||||
if (!this.macro.length)
|
||||
this.macro = this.oldMacro;
|
||||
|
||||
return this.recording = false;
|
||||
}
|
||||
if (!this.$addCommandToMacro) {
|
||||
this.$addCommandToMacro = function(e) {
|
||||
this.macro.push([e.command, e.args]);
|
||||
}.bind(this);
|
||||
}
|
||||
|
||||
this.oldMacro = this.macro;
|
||||
this.macro = [];
|
||||
this.on("exec", this.$addCommandToMacro);
|
||||
return this.recording = true;
|
||||
};
|
||||
|
||||
this.replay = function(editor) {
|
||||
if (this.$inReplay || !this.macro)
|
||||
return;
|
||||
|
||||
if (this.recording)
|
||||
return this.toggleRecording();
|
||||
|
||||
try {
|
||||
this.$inReplay = true;
|
||||
this.macro.forEach(function(x) {
|
||||
if (typeof x == "string")
|
||||
this.exec(x, editor);
|
||||
else
|
||||
this.exec(x[0], editor, x[1]);
|
||||
}, this);
|
||||
} finally {
|
||||
this.$inReplay = false;
|
||||
}
|
||||
};
|
||||
|
||||
this.trimMacro = function(m) {
|
||||
return m.map(function(x){
|
||||
if (typeof x[0] != "string")
|
||||
x[0] = x[0].name;
|
||||
if (!x[1])
|
||||
x = x[0];
|
||||
return x;
|
||||
});
|
||||
};
|
||||
|
||||
}).call(CommandManager.prototype);
|
||||
|
||||
exports.CommandManager = CommandManager;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,193 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var CommandManager = require("./command_manager").CommandManager;
|
||||
var keys = require("../lib/keys");
|
||||
var assert = require("../test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
setUp: function() {
|
||||
this.command = {
|
||||
name: "gotoline",
|
||||
bindKey: {
|
||||
mac: "Command-L",
|
||||
win: "Ctrl-L"
|
||||
},
|
||||
called: false,
|
||||
exec: function(editor) { this.called = true; }
|
||||
};
|
||||
|
||||
this.cm = new CommandManager("mac", [this.command]);
|
||||
},
|
||||
|
||||
"test: register command": function() {
|
||||
this.cm.exec("gotoline");
|
||||
assert.ok(this.command.called);
|
||||
},
|
||||
|
||||
"test: mac hotkeys": function() {
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "L");
|
||||
assert.equal(command, this.command);
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "L");
|
||||
assert.equal(command, undefined);
|
||||
},
|
||||
|
||||
"test: win hotkeys": function() {
|
||||
var cm = new CommandManager("win", [this.command]);
|
||||
|
||||
var command = cm.findKeyCommand(keys.KEY_MODS.command, "L");
|
||||
assert.equal(command, undefined);
|
||||
|
||||
var command = cm.findKeyCommand(keys.KEY_MODS.ctrl, "L");
|
||||
assert.equal(command, this.command);
|
||||
},
|
||||
|
||||
"test: remove command by object": function() {
|
||||
this.cm.removeCommand(this.command);
|
||||
|
||||
this.cm.exec("gotoline");
|
||||
assert.ok(!this.command.called);
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "L");
|
||||
assert.equal(command, null);
|
||||
},
|
||||
|
||||
"test: remove command by name": function() {
|
||||
this.cm.removeCommand("gotoline");
|
||||
|
||||
this.cm.exec("gotoline");
|
||||
assert.ok(!this.command.called);
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "L");
|
||||
assert.equal(command, null);
|
||||
},
|
||||
|
||||
"test: adding a new command with the same name as an existing one should remove the old one first": function() {
|
||||
var command = {
|
||||
name: "gotoline",
|
||||
bindKey: {
|
||||
mac: "Command-L",
|
||||
win: "Ctrl-L"
|
||||
},
|
||||
called: false,
|
||||
exec: function(editor) { this.called = true; }
|
||||
};
|
||||
this.cm.addCommand(command);
|
||||
|
||||
this.cm.exec("gotoline");
|
||||
assert.ok(command.called);
|
||||
assert.ok(!this.command.called);
|
||||
|
||||
assert.equal(this.cm.findKeyCommand(keys.KEY_MODS.command, "L"), command);
|
||||
},
|
||||
|
||||
"test: adding commands and recording a macro": function() {
|
||||
var called = "";
|
||||
this.cm.addCommands({
|
||||
togglerecording: function(editor) {
|
||||
editor.cm.toggleRecording();
|
||||
},
|
||||
replay: function(editor) {
|
||||
editor.cm.replay();
|
||||
},
|
||||
cm1: function(editor, arg) {
|
||||
called += "1" + (arg || "");
|
||||
},
|
||||
cm2: function(editor) {
|
||||
called += "2";
|
||||
}
|
||||
});
|
||||
|
||||
this.cm.exec("togglerecording", this);
|
||||
assert.ok(this.cm.recording);
|
||||
|
||||
this.cm.exec("cm1", this, "-");
|
||||
this.cm.exec("cm2");
|
||||
this.cm.exec("replay", this);
|
||||
assert.ok(!this.cm.recording);
|
||||
assert.equal(called, "1-2");
|
||||
|
||||
called = "";
|
||||
this.cm.exec("replay", this);
|
||||
assert.equal(called, "1-2");
|
||||
},
|
||||
|
||||
"test: bindkeys": function() {
|
||||
var called = "";
|
||||
this.cm.addCommands({
|
||||
cm1: function(editor, arg) {
|
||||
called += "1" + (arg || "");
|
||||
},
|
||||
cm2: function(editor) {
|
||||
called += "2";
|
||||
}
|
||||
});
|
||||
|
||||
this.cm.bindKeys({
|
||||
"Ctrl-L|Command-C": "cm1",
|
||||
"Ctrl-R": "cm2"
|
||||
});
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "C");
|
||||
assert.equal(command, "cm1");
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "R");
|
||||
assert.equal(command, "cm2");
|
||||
|
||||
this.cm.bindKeys({
|
||||
"Ctrl-R": null
|
||||
});
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "R");
|
||||
assert.equal(command, null);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var lang = require("../lib/lang");
|
||||
|
||||
function bindKey(win, mac) {
|
||||
return {
|
||||
win: win,
|
||||
mac: mac
|
||||
};
|
||||
}
|
||||
|
||||
exports.commands = [{
|
||||
name: "selectall",
|
||||
bindKey: bindKey("Ctrl-A", "Command-A"),
|
||||
exec: function(editor) { editor.selectAll(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "centerselection",
|
||||
bindKey: bindKey(null, "Ctrl-L"),
|
||||
exec: function(editor) { editor.centerSelection(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoline",
|
||||
bindKey: bindKey("Ctrl-L", "Command-L"),
|
||||
exec: function(editor) {
|
||||
var line = parseInt(prompt("Enter line number:"), 10);
|
||||
if (!isNaN(line)) {
|
||||
editor.gotoLine(line);
|
||||
}
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "fold",
|
||||
bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"),
|
||||
exec: function(editor) { editor.session.toggleFold(false); },
|
||||
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); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "foldall",
|
||||
bindKey: bindKey("Alt-0", "Command-Option-0"),
|
||||
exec: function(editor) { editor.session.foldAll(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "unfoldall",
|
||||
bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"),
|
||||
exec: function(editor) { editor.session.unfold(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "findnext",
|
||||
bindKey: bindKey("Ctrl-K", "Command-G"),
|
||||
exec: function(editor) { editor.findNext(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "findprevious",
|
||||
bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"),
|
||||
exec: function(editor) { editor.findPrevious(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "find",
|
||||
bindKey: bindKey("Ctrl-F", "Command-F"),
|
||||
exec: function(editor) {
|
||||
var needle = prompt("Find:", editor.getCopyText());
|
||||
editor.find(needle);
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "overwrite",
|
||||
bindKey: "Insert",
|
||||
exec: function(editor) { editor.toggleOverwrite(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttostart",
|
||||
bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Up"),
|
||||
exec: function(editor) { editor.getSelection().selectFileStart(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotostart",
|
||||
bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"),
|
||||
exec: function(editor) { editor.navigateFileStart(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectup",
|
||||
bindKey: bindKey("Shift-Up", "Shift-Up"),
|
||||
exec: function(editor) { editor.getSelection().selectUp(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "golineup",
|
||||
bindKey: bindKey("Up", "Up|Ctrl-P"),
|
||||
exec: function(editor, args) { editor.navigateUp(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttoend",
|
||||
bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-Down"),
|
||||
exec: function(editor) { editor.getSelection().selectFileEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoend",
|
||||
bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"),
|
||||
exec: function(editor) { editor.navigateFileEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectdown",
|
||||
bindKey: bindKey("Shift-Down", "Shift-Down"),
|
||||
exec: function(editor) { editor.getSelection().selectDown(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "golinedown",
|
||||
bindKey: bindKey("Down", "Down|Ctrl-N"),
|
||||
exec: function(editor, args) { editor.navigateDown(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectwordleft",
|
||||
bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectWordLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotowordleft",
|
||||
bindKey: bindKey("Ctrl-Left", "Option-Left"),
|
||||
exec: function(editor) { editor.navigateWordLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttolinestart",
|
||||
bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotolinestart",
|
||||
bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"),
|
||||
exec: function(editor) { editor.navigateLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectleft",
|
||||
bindKey: bindKey("Shift-Left", "Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoleft",
|
||||
bindKey: bindKey("Left", "Left|Ctrl-B"),
|
||||
exec: function(editor, args) { editor.navigateLeft(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectwordright",
|
||||
bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectWordRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotowordright",
|
||||
bindKey: bindKey("Ctrl-Right", "Option-Right"),
|
||||
exec: function(editor) { editor.navigateWordRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttolineend",
|
||||
bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotolineend",
|
||||
bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"),
|
||||
exec: function(editor) { editor.navigateLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectright",
|
||||
bindKey: bindKey("Shift-Right", "Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoright",
|
||||
bindKey: bindKey("Right", "Right|Ctrl-F"),
|
||||
exec: function(editor, args) { editor.navigateRight(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectpagedown",
|
||||
bindKey: "Shift-PageDown",
|
||||
exec: function(editor) { editor.selectPageDown(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "pagedown",
|
||||
bindKey: bindKey(null, "Option-PageDown"),
|
||||
exec: function(editor) { editor.scrollPageDown(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotopagedown",
|
||||
bindKey: bindKey("PageDown", "PageDown|Ctrl-V"),
|
||||
exec: function(editor) { editor.gotoPageDown(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectpageup",
|
||||
bindKey: "Shift-PageUp",
|
||||
exec: function(editor) { editor.selectPageUp(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "pageup",
|
||||
bindKey: bindKey(null, "Option-PageUp"),
|
||||
exec: function(editor) { editor.scrollPageUp(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotopageup",
|
||||
bindKey: "PageUp",
|
||||
exec: function(editor) { editor.gotoPageUp(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "scrollup",
|
||||
bindKey: bindKey("Ctrl-Up", null),
|
||||
exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "scrolldown",
|
||||
bindKey: bindKey("Ctrl-Down", null),
|
||||
exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectlinestart",
|
||||
bindKey: "Shift-Home",
|
||||
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectlineend",
|
||||
bindKey: "Shift-End",
|
||||
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "togglerecording",
|
||||
bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"),
|
||||
exec: function(editor) { editor.commands.toggleRecording(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "replaymacro",
|
||||
bindKey: bindKey("Ctrl-Shift-E", "Command-Shift-E"),
|
||||
exec: function(editor) { editor.commands.replay(editor); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "jumptomatching",
|
||||
bindKey: bindKey("Ctrl-P", "Ctrl-P"),
|
||||
exec: function(editor) { editor.jumpToMatching(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttomatching",
|
||||
bindKey: bindKey("Ctrl-Shift-P", "Ctrl-Shift-P"),
|
||||
exec: function(editor) { editor.jumpToMatching(true); },
|
||||
readOnly: true
|
||||
},
|
||||
|
||||
// commands disabled in readOnly mode
|
||||
{
|
||||
name: "cut",
|
||||
exec: function(editor) {
|
||||
var range = editor.getSelectionRange();
|
||||
editor._emit("cut", range);
|
||||
|
||||
if (!editor.selection.isEmpty()) {
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
}
|
||||
},
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removeline",
|
||||
bindKey: bindKey("Ctrl-D", "Command-D"),
|
||||
exec: function(editor) { editor.removeLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "duplicateSelection",
|
||||
bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"),
|
||||
exec: function(editor) { editor.duplicateSelection(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "togglecomment",
|
||||
bindKey: bindKey("Ctrl-/", "Command-/"),
|
||||
exec: function(editor) { editor.toggleCommentLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "replace",
|
||||
bindKey: bindKey("Ctrl-R", "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});
|
||||
}
|
||||
}, {
|
||||
name: "undo",
|
||||
bindKey: bindKey("Ctrl-Z", "Command-Z"),
|
||||
exec: function(editor) { editor.undo(); }
|
||||
}, {
|
||||
name: "redo",
|
||||
bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"),
|
||||
exec: function(editor) { editor.redo(); }
|
||||
}, {
|
||||
name: "copylinesup",
|
||||
bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"),
|
||||
exec: function(editor) { editor.copyLinesUp(); }
|
||||
}, {
|
||||
name: "movelinesup",
|
||||
bindKey: bindKey("Alt-Up", "Option-Up"),
|
||||
exec: function(editor) { editor.moveLinesUp(); }
|
||||
}, {
|
||||
name: "copylinesdown",
|
||||
bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"),
|
||||
exec: function(editor) { editor.copyLinesDown(); }
|
||||
}, {
|
||||
name: "movelinesdown",
|
||||
bindKey: bindKey("Alt-Down", "Option-Down"),
|
||||
exec: function(editor) { editor.moveLinesDown(); }
|
||||
}, {
|
||||
name: "del",
|
||||
bindKey: bindKey("Delete", "Delete|Ctrl-D"),
|
||||
exec: function(editor) { editor.remove("right"); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "backspace",
|
||||
bindKey: bindKey(
|
||||
"Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
|
||||
"Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H"
|
||||
),
|
||||
exec: function(editor) { editor.remove("left"); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removetolinestart",
|
||||
bindKey: bindKey("Alt-Backspace", "Command-Backspace"),
|
||||
exec: function(editor) { editor.removeToLineStart(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removetolineend",
|
||||
bindKey: bindKey("Alt-Delete", "Ctrl-K"),
|
||||
exec: function(editor) { editor.removeToLineEnd(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removewordleft",
|
||||
bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"),
|
||||
exec: function(editor) { editor.removeWordLeft(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removewordright",
|
||||
bindKey: bindKey("Ctrl-Delete", "Alt-Delete"),
|
||||
exec: function(editor) { editor.removeWordRight(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "outdent",
|
||||
bindKey: bindKey("Shift-Tab", "Shift-Tab"),
|
||||
exec: function(editor) { editor.blockOutdent(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "indent",
|
||||
bindKey: bindKey("Tab", "Tab"),
|
||||
exec: function(editor) { editor.indent(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "insertstring",
|
||||
exec: function(editor, str) { editor.insert(str); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "inserttext",
|
||||
exec: function(editor, args) {
|
||||
editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
|
||||
},
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "splitline",
|
||||
bindKey: bindKey(null, "Ctrl-O"),
|
||||
exec: function(editor) { editor.splitLine(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "transposeletters",
|
||||
bindKey: bindKey("Ctrl-T", "Ctrl-T"),
|
||||
exec: function(editor) { editor.transposeLetters(); },
|
||||
multiSelectAction: function(editor) {editor.transposeSelections(1); }
|
||||
}, {
|
||||
name: "touppercase",
|
||||
bindKey: bindKey("Ctrl-U", "Ctrl-U"),
|
||||
exec: function(editor) { editor.toUpperCase(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "tolowercase",
|
||||
bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"),
|
||||
exec: function(editor) { editor.toLowerCase(); },
|
||||
multiSelectAction: "forEach"
|
||||
}];
|
||||
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
// commands to enter multiselect mode
|
||||
exports.defaultCommands = [{
|
||||
name: "addCursorAbove",
|
||||
exec: function(editor) { editor.selectMoreLines(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelow",
|
||||
exec: function(editor) { editor.selectMoreLines(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorAboveSkipCurrent",
|
||||
exec: function(editor) { editor.selectMoreLines(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelowSkipCurrent",
|
||||
exec: function(editor) { editor.selectMoreLines(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreBefore",
|
||||
exec: function(editor) { editor.selectMore(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreAfter",
|
||||
exec: function(editor) { editor.selectMore(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextBefore",
|
||||
exec: function(editor) { editor.selectMore(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextAfter",
|
||||
exec: function(editor) { editor.selectMore(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "splitIntoLines",
|
||||
exec: function(editor) { editor.multiSelect.splitIntoLines(); },
|
||||
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"},
|
||||
readonly: true
|
||||
}];
|
||||
|
||||
// commands active in multiselect mode
|
||||
exports.multiSelectCommands = [{
|
||||
name: "singleSelection",
|
||||
bindKey: "esc",
|
||||
exec: function(editor) { editor.exitMultiSelectMode(); },
|
||||
readonly: true,
|
||||
isAvailable: function(editor) {return editor && editor.inMultiSelectMode}
|
||||
}];
|
||||
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
exports.keyboardHandler = new HashHandler(exports.multiSelectCommands);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,124 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"no use strict";
|
||||
|
||||
var lang = require("./lib/lang");
|
||||
|
||||
var global = (function() {
|
||||
return this;
|
||||
})();
|
||||
|
||||
var options = {
|
||||
packaged: false,
|
||||
workerPath: "",
|
||||
modePath: "",
|
||||
themePath: "",
|
||||
suffix: ".js"
|
||||
};
|
||||
|
||||
exports.get = function(key) {
|
||||
if (!options.hasOwnProperty(key))
|
||||
throw new Error("Unknown config key: " + key);
|
||||
|
||||
return options[key];
|
||||
};
|
||||
|
||||
exports.set = function(key, value) {
|
||||
if (!options.hasOwnProperty(key))
|
||||
throw new Error("Unknown config key: " + key);
|
||||
|
||||
options[key] = value;
|
||||
};
|
||||
|
||||
exports.all = function() {
|
||||
return lang.copyObject(options);
|
||||
};
|
||||
|
||||
exports.init = function() {
|
||||
options.packaged = require.packaged || module.packaged || (global.define && define.packaged);
|
||||
|
||||
if (!global.document)
|
||||
return "";
|
||||
|
||||
var scriptOptions = {};
|
||||
var scriptUrl = "";
|
||||
|
||||
var scripts = document.getElementsByTagName("script");
|
||||
for (var i=0; i<scripts.length; i++) {
|
||||
var script = scripts[i];
|
||||
|
||||
var src = script.src || script.getAttribute("src");
|
||||
if (!src) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var attributes = script.attributes;
|
||||
for (var j=0, l=attributes.length; j < l; j++) {
|
||||
var attr = attributes[j];
|
||||
if (attr.name.indexOf("data-ace-") === 0) {
|
||||
scriptOptions[deHyphenate(attr.name.replace(/^data-ace-/, ""))] = attr.value;
|
||||
}
|
||||
}
|
||||
|
||||
var m = src.match(/^(.*)\/ace(\-\w+)?\.js(\?|$)/);
|
||||
if (m)
|
||||
scriptUrl = m[1];
|
||||
}
|
||||
|
||||
if (scriptUrl) {
|
||||
scriptOptions.base = scriptOptions.base || scriptUrl;
|
||||
scriptOptions.packaged = true;
|
||||
}
|
||||
|
||||
scriptOptions.workerPath = scriptOptions.workerPath || scriptOptions.base;
|
||||
scriptOptions.modePath = scriptOptions.modePath || scriptOptions.base;
|
||||
scriptOptions.themePath = scriptOptions.themePath || scriptOptions.base;
|
||||
delete scriptOptions.base;
|
||||
|
||||
for (var key in scriptOptions)
|
||||
if (typeof scriptOptions[key] !== "undefined")
|
||||
exports.set(key, scriptOptions[key]);
|
||||
};
|
||||
|
||||
function deHyphenate(str) {
|
||||
return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); });
|
||||
}
|
||||
|
||||
});
|
||||
|
After Width: | Height: | Size: 759 B |
@@ -0,0 +1,327 @@
|
||||
.ace_editor {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Droid Sans Mono', 'Consolas', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ace_scroller {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ace_content {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.ace_gutter {
|
||||
position: absolute;
|
||||
overflow : hidden;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.ace_scroller.horscroll {
|
||||
box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;
|
||||
}
|
||||
|
||||
.ace_gutter-cell {
|
||||
padding-left: 19px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
.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-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-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_info {
|
||||
background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQAAAAAAEFBQVJSUl5eXmRkZGtra39/f4WFhYmJiZGRkaampry8vMPDw8zMzNXV1dzc3OTk5Orq6vDw8P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABQALAAAAAAQABAAAAUuICWOZGmeaBml5XGwFCQSBGyXRSAwtqQIiRuiwIM5BoYVbEFIyGCQoeJGrVptIQA7");
|
||||
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=");
|
||||
}
|
||||
|
||||
.ace_editor .ace_sb {
|
||||
position: absolute;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ace_editor .ace_sb div {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ace_editor .ace_print_margin_layer {
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ace_editor .ace_print_margin {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ace_editor > textarea {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
width: 0.5em;
|
||||
height: 1em;
|
||||
opacity: 0;
|
||||
background: transparent;
|
||||
appearance: none;
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
resize: none;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ace_editor > textarea.ace_composition {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 1000;
|
||||
opacity: 1;
|
||||
border: solid lightgray 1px;
|
||||
margin: -1px
|
||||
}
|
||||
|
||||
.ace_layer {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
/* setting pointer-events: auto; on node under the mouse, which changes
|
||||
during scroll, will break mouse wheel scrolling in Safari */
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ace_gutter .ace_layer {
|
||||
position: relative;
|
||||
min-width: 40px;
|
||||
width: auto;
|
||||
text-align: right;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.ace_text-layer {
|
||||
color: black;
|
||||
font: inherit !important;
|
||||
}
|
||||
|
||||
.ace_cjk {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ace_cursor-layer {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.ace_cursor {
|
||||
z-index: 4;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.ace_cursor.ace_hidden {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.ace_editor.multiselect .ace_cursor {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.ace_line {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_step {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_selection {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_bracket {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_active_line {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_selected_word {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ace_line .ace_fold {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
|
||||
display: inline-block;
|
||||
height: 11px;
|
||||
margin-top: -2px;
|
||||
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");
|
||||
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;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.ace_dark .ace_fold {
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.ace_dragging .ace_content {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.ace_folding-enabled > .ace_gutter-cell {
|
||||
padding-right: 13px;
|
||||
}
|
||||
|
||||
.ace_fold-widget {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
|
||||
margin: 0 -12px 1px 1px;
|
||||
display: inline-block;
|
||||
height: 14px;
|
||||
width: 11px;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
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-repeat: no-repeat;
|
||||
background-position: center 4px;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.ace_fold-widget.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");
|
||||
}
|
||||
|
||||
.ace_fold-widget.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");
|
||||
}
|
||||
|
||||
.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);
|
||||
background-position: center 4px;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
/**
|
||||
* Dark version for fold widgets
|
||||
*/
|
||||
.ace_dark .ace_fold-widget {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");
|
||||
}
|
||||
.ace_dark .ace_fold-widget.end {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");
|
||||
}
|
||||
.ace_dark .ace_fold-widget.closed {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");
|
||||
}
|
||||
.ace_dark .ace_fold-widget:hover {
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
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.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;
|
||||
}
|
||||
|
After Width: | Height: | Size: 290 B |
@@ -0,0 +1,617 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
var Range = require("./range").Range;
|
||||
var Anchor = require("./anchor").Anchor;
|
||||
|
||||
/**
|
||||
* class Document
|
||||
*
|
||||
* Contains the text of the document. Documents are controlled by a single [[EditSession `EditSession`]]. At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new Document([text])
|
||||
* - text (String | Array): The starting text
|
||||
*
|
||||
* Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty.
|
||||
*
|
||||
**/
|
||||
var Document = function(text) {
|
||||
this.$lines = [];
|
||||
|
||||
// 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) {
|
||||
this.$lines = [""];
|
||||
} else if (Array.isArray(text)) {
|
||||
this.insertLines(0, text);
|
||||
} else {
|
||||
this.insert({row: 0, column:0}, text);
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
/**
|
||||
* Document.setValue(text) -> Void
|
||||
* - text (String): The text to use
|
||||
*
|
||||
* Replaces all the lines in the current `Document` with the value of `text`.
|
||||
**/
|
||||
this.setValue = function(text) {
|
||||
var len = this.getLength();
|
||||
this.remove(new Range(0, 0, len, this.getLine(len-1).length));
|
||||
this.insert({row: 0, column:0}, text);
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getValue() -> String
|
||||
*
|
||||
* Returns all the lines in the document as a single string, split by the new line character.
|
||||
**/
|
||||
this.getValue = function() {
|
||||
return this.getAllLines().join(this.getNewLineCharacter());
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.createAnchor(row, column) -> Anchor
|
||||
* - row (Number): The row number to use
|
||||
* - column (Number): The column number to use
|
||||
*
|
||||
* Creates a new `Anchor` to define a floating point in the document.
|
||||
**/
|
||||
this.createAnchor = function(row, column) {
|
||||
return new Anchor(this, row, column);
|
||||
};
|
||||
|
||||
/** internal, hide
|
||||
* Document.$split(text) -> [String]
|
||||
* - text (String): The text to work with
|
||||
* + ([String]): A String array, with each index containing a piece of the original `text` string.
|
||||
*
|
||||
* Splits a string of text on any newline (`\n`) or carriage-return ('\r') characters.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
// check for IE split bug
|
||||
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/);
|
||||
};
|
||||
|
||||
|
||||
/** internal, hide
|
||||
* Document.$detectNewLine(text) -> Void
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.$detectNewLine = function(text) {
|
||||
var match = text.match(/^.*?(\r\n|\r|\n)/m);
|
||||
if (match) {
|
||||
this.$autoNewLine = match[1];
|
||||
} else {
|
||||
this.$autoNewLine = "\n";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getNewLineCharacter() -> String
|
||||
* + (String): If `newLineMode == windows`, `\r\n` is returned.<br/>
|
||||
* If `newLineMode == unix`, `\n` is returned.<br/>
|
||||
* If `newLineMode == auto`, the value of `autoNewLine` is returned.
|
||||
*
|
||||
* Returns the newline character that's being used, depending on the value of `newLineMode`.
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getNewLineCharacter = function() {
|
||||
switch (this.$newLineMode) {
|
||||
case "windows":
|
||||
return "\r\n";
|
||||
|
||||
case "unix":
|
||||
return "\n";
|
||||
|
||||
case "auto":
|
||||
return this.$autoNewLine;
|
||||
}
|
||||
};
|
||||
|
||||
this.$autoNewLine = "\n";
|
||||
this.$newLineMode = "auto";
|
||||
/**
|
||||
* Document.setNewLineMode(newLineMode) -> Void
|
||||
* - newLineMode(String): [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param}
|
||||
*
|
||||
* [Sets the new line mode.]{: #Document.setNewLineMode.desc}
|
||||
**/
|
||||
this.setNewLineMode = function(newLineMode) {
|
||||
if (this.$newLineMode === newLineMode)
|
||||
return;
|
||||
|
||||
this.$newLineMode = newLineMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getNewLineMode() -> String
|
||||
*
|
||||
* [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode}
|
||||
*
|
||||
**/
|
||||
this.getNewLineMode = function() {
|
||||
return this.$newLineMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.isNewLine(text) -> Boolean
|
||||
* - text (String): The text to check
|
||||
*
|
||||
* Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`).
|
||||
*
|
||||
**/
|
||||
this.isNewLine = function(text) {
|
||||
return (text == "\r\n" || text == "\r" || text == "\n");
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getLine(row) -> String
|
||||
* - row (Number): The row index to retrieve
|
||||
*
|
||||
* Returns a verbatim copy of the given line as it is in the document
|
||||
*
|
||||
**/
|
||||
this.getLine = function(row) {
|
||||
return this.$lines[row] || "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getLines(firstRow, lastRow) -> [String]
|
||||
* - firstRow (Number): The first row index to retrieve
|
||||
* - lastRow (Number): The final row index to retrieve
|
||||
*
|
||||
* Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`.
|
||||
*
|
||||
**/
|
||||
this.getLines = function(firstRow, lastRow) {
|
||||
return this.$lines.slice(firstRow, lastRow + 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getAllLines() -> [String]
|
||||
*
|
||||
* Returns all lines in the document as string array. Warning: The caller should not modify this array!
|
||||
**/
|
||||
this.getAllLines = function() {
|
||||
return this.getLines(0, this.getLength());
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getLength() -> Number
|
||||
*
|
||||
* Returns the number of rows in the document.
|
||||
**/
|
||||
this.getLength = function() {
|
||||
return this.$lines.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getTextRange(range) -> String
|
||||
* - range (Range): The range to work with
|
||||
*
|
||||
* [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc}
|
||||
**/
|
||||
this.getTextRange = function(range) {
|
||||
if (range.start.row == range.end.row) {
|
||||
return this.$lines[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));
|
||||
return lines.join(this.getNewLineCharacter());
|
||||
}
|
||||
};
|
||||
|
||||
/** internal, hide
|
||||
* Document.$clipPosition(position) -> Number
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.$clipPosition = function(position) {
|
||||
var length = this.getLength();
|
||||
if (position.row >= length) {
|
||||
position.row = Math.max(0, length - 1);
|
||||
position.column = this.getLine(length-1).length;
|
||||
}
|
||||
return position;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.insert(position, text) -> Number
|
||||
* - position (Number): The position to start inserting at
|
||||
* - text (String): A chunk of text to insert
|
||||
* + (Number): The position of the last line of `text`. If the length of `text` is 0, this function simply returns `position`.
|
||||
* Inserts a block of `text` and the indicated `position`.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.insert = function(position, text) {
|
||||
if (!text || text.length === 0)
|
||||
return position;
|
||||
|
||||
position = this.$clipPosition(position);
|
||||
|
||||
// only detect new lines if the document has no line break yet
|
||||
if (this.getLength() <= 1)
|
||||
this.$detectNewLine(text);
|
||||
|
||||
var lines = this.$split(text);
|
||||
var firstLine = lines.splice(0, 1)[0];
|
||||
var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
|
||||
|
||||
position = this.insertInLine(position, firstLine);
|
||||
if (lastLine !== null) {
|
||||
position = this.insertNewLine(position); // terminate first line
|
||||
position = this.insertLines(position.row, lines);
|
||||
position = this.insertInLine(position, lastLine || "");
|
||||
}
|
||||
return position;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.insertLines(row, lines) -> Object
|
||||
* - row (Number): The index of the row to insert at
|
||||
* - lines (Array): An array of strings
|
||||
* + (Object): Returns an object containing the final row and column, like this:<br/>
|
||||
* ```{row: endRow, column: 0}```<br/>
|
||||
* If `lines` is empty, this function returns an object containing the current row, and column, like this:<br/>
|
||||
* ```{row: row, column: 0}```
|
||||
*
|
||||
* Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
**/
|
||||
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);
|
||||
}
|
||||
|
||||
var args = [row, 0];
|
||||
args.push.apply(args, lines);
|
||||
this.$lines.splice.apply(this.$lines, args);
|
||||
|
||||
var range = new Range(row, 0, row + lines.length, 0);
|
||||
var delta = {
|
||||
action: "insertLines",
|
||||
range: range,
|
||||
lines: lines
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
return end || range.end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.insertNewLine(position) -> Object
|
||||
* - position (String): The position to insert at
|
||||
* + (Object): Returns an object containing the final row and column, like this:<br/>
|
||||
* ```{row: endRow, column: 0}```
|
||||
*
|
||||
* Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.insertNewLine = function(position) {
|
||||
position = this.$clipPosition(position);
|
||||
var line = this.$lines[position.row] || "";
|
||||
|
||||
this.$lines[position.row] = line.substring(0, position.column);
|
||||
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
|
||||
|
||||
var end = {
|
||||
row : position.row + 1,
|
||||
column : 0
|
||||
};
|
||||
|
||||
var delta = {
|
||||
action: "insertText",
|
||||
range: Range.fromPoints(position, end),
|
||||
text: this.getNewLineCharacter()
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.insertInLine(position, text) -> Object | Number
|
||||
* - position (Number): The position to insert at
|
||||
* - text (String): A chunk of text
|
||||
* + (Object): Returns an object containing the final row and column, like this:<br/>
|
||||
* ```{row: endRow, column: 0}```
|
||||
* + (Number): If `text` is empty, this function returns the value of `position`
|
||||
*
|
||||
* Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.insertInLine = function(position, text) {
|
||||
if (text.length == 0)
|
||||
return position;
|
||||
|
||||
var line = this.$lines[position.row] || "";
|
||||
|
||||
this.$lines[position.row] = line.substring(0, position.column) + text
|
||||
+ line.substring(position.column);
|
||||
|
||||
var end = {
|
||||
row : position.row,
|
||||
column : position.column + text.length
|
||||
};
|
||||
|
||||
var delta = {
|
||||
action: "insertText",
|
||||
range: Range.fromPoints(position, end),
|
||||
text: text
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.remove(range) -> Object
|
||||
* - range (Range): A specified Range to remove
|
||||
* + (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`.
|
||||
*
|
||||
* Removes the `range` from the document.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.remove = function(range) {
|
||||
// clip to document
|
||||
range.start = this.$clipPosition(range.start);
|
||||
range.end = this.$clipPosition(range.end);
|
||||
|
||||
if (range.isEmpty())
|
||||
return range.start;
|
||||
|
||||
var firstRow = range.start.row;
|
||||
var lastRow = range.end.row;
|
||||
|
||||
if (range.isMultiLine()) {
|
||||
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
|
||||
var lastFullRow = lastRow - 1;
|
||||
|
||||
if (range.end.column > 0)
|
||||
this.removeInLine(lastRow, 0, range.end.column);
|
||||
|
||||
if (lastFullRow >= firstFullRow)
|
||||
this.removeLines(firstFullRow, lastFullRow);
|
||||
|
||||
if (firstFullRow != firstRow) {
|
||||
this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
|
||||
this.removeNewLine(range.start.row);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.removeInLine(firstRow, range.start.column, range.end.column);
|
||||
}
|
||||
return range.start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.removeInLine(row, startColumn, endColumn) -> Object
|
||||
* - row (Number): The row to remove from
|
||||
* - startColumn (Number): The column to start removing at
|
||||
* - endColumn (Number): The column to stop removing at
|
||||
* + (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.
|
||||
*
|
||||
* Removes the specified columns from the `row`. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.removeInLine = function(row, startColumn, endColumn) {
|
||||
if (startColumn == endColumn)
|
||||
return;
|
||||
|
||||
var range = new Range(row, startColumn, row, endColumn);
|
||||
var line = this.getLine(row);
|
||||
var removed = line.substring(startColumn, endColumn);
|
||||
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
|
||||
this.$lines.splice(row, 1, newLine);
|
||||
|
||||
var delta = {
|
||||
action: "removeText",
|
||||
range: range,
|
||||
text: removed
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
return range.start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.removeLines(firstRow, lastRow) -> [String]
|
||||
* - firstRow (Number): The first row to be removed
|
||||
* - lastRow (Number): The last row to be removed
|
||||
* + ([String]): Returns all the removed lines.
|
||||
*
|
||||
* Removes a range of full lines. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.removeLines = function(firstRow, lastRow) {
|
||||
var range = new Range(firstRow, 0, lastRow + 1, 0);
|
||||
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
|
||||
|
||||
var delta = {
|
||||
action: "removeLines",
|
||||
range: range,
|
||||
nl: this.getNewLineCharacter(),
|
||||
lines: removed
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
return removed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.removeNewLine(row) -> Void
|
||||
* - row (Number): The row to check
|
||||
*
|
||||
* Removes the new line between `row` and the row immediately following it. This method also triggers the `'change'` event.
|
||||
*
|
||||
**/
|
||||
this.removeNewLine = function(row) {
|
||||
var firstLine = this.getLine(row);
|
||||
var secondLine = this.getLine(row+1);
|
||||
|
||||
var range = new Range(row, firstLine.length, row+1, 0);
|
||||
var line = firstLine + secondLine;
|
||||
|
||||
this.$lines.splice(row, 2, line);
|
||||
|
||||
var delta = {
|
||||
action: "removeText",
|
||||
range: range,
|
||||
text: this.getNewLineCharacter()
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.replace(range, text) -> Object
|
||||
* - range (Range): A specified Range to replace
|
||||
* - text (String): The new text to use as a replacement
|
||||
* + (Object): Returns an object containing the final row and column, like this:
|
||||
* {row: endRow, column: 0}
|
||||
* 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.
|
||||
*
|
||||
* Replaces a range in the document with the new `text`.
|
||||
*
|
||||
**/
|
||||
this.replace = function(range, text) {
|
||||
if (text.length == 0 && range.isEmpty())
|
||||
return range.start;
|
||||
|
||||
// Shortcut: If the text we want to insert is the same as it is already
|
||||
// in the document, we don't have to replace anything.
|
||||
if (text == this.getTextRange(range))
|
||||
return range.end;
|
||||
|
||||
this.remove(range);
|
||||
if (text) {
|
||||
var end = this.insert(range.start, text);
|
||||
}
|
||||
else {
|
||||
end = range.start;
|
||||
}
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.applyDeltas(deltas) -> Void
|
||||
*
|
||||
* Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
**/
|
||||
this.applyDeltas = function(deltas) {
|
||||
for (var i=0; i<deltas.length; i++) {
|
||||
var delta = deltas[i];
|
||||
var range = Range.fromPoints(delta.range.start, delta.range.end);
|
||||
|
||||
if (delta.action == "insertLines")
|
||||
this.insertLines(range.start.row, delta.lines);
|
||||
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);
|
||||
else if (delta.action == "removeText")
|
||||
this.remove(range);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.revertDeltas(deltas) -> Void
|
||||
*
|
||||
* Reverts any changes previously applied. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
**/
|
||||
this.revertDeltas = function(deltas) {
|
||||
for (var i=deltas.length-1; i>=0; i--) {
|
||||
var delta = deltas[i];
|
||||
|
||||
var range = Range.fromPoints(delta.range.start, delta.range.end);
|
||||
|
||||
if (delta.action == "insertLines")
|
||||
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);
|
||||
else if (delta.action == "removeText")
|
||||
this.insert(range.start, delta.text);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(Document.prototype);
|
||||
|
||||
exports.Document = Document;
|
||||
});
|
||||
@@ -0,0 +1,314 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Document = require("./document").Document;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test: insert text in line" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insert({row: 0, column: 1}, "juhu");
|
||||
assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert new line" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insertNewLine({row: 0, column: 1});
|
||||
assert.equal(doc.getValue(), ["1", "2", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1", "2", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert lines at the beginning" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insertLines(0, ["aa", "bb"]);
|
||||
assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert lines at the end" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insertLines(2, ["aa", "bb"]);
|
||||
assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert lines in the middle" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insertLines(1, ["aa", "bb"]);
|
||||
assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert multi line string at the start" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insert({row: 0, column: 0}, "aa\nbb\ncc");
|
||||
assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert multi line string at the end" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insert({row: 2, column: 0}, "aa\nbb\ncc");
|
||||
assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert multi line string in the middle" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insert({row: 0, column: 1}, "aa\nbb\ncc");
|
||||
assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: delete in line" : function() {
|
||||
var doc = new Document(["1234", "5678"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.remove(new Range(0, 1, 0, 3));
|
||||
assert.equal(doc.getValue(), ["14", "5678"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1234", "5678"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["14", "5678"].join("\n"));
|
||||
},
|
||||
|
||||
"test: delete new line" : function() {
|
||||
var doc = new Document(["1234", "5678"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.remove(new Range(0, 4, 1, 0));
|
||||
assert.equal(doc.getValue(), ["12345678"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1234", "5678"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12345678"].join("\n"));
|
||||
},
|
||||
|
||||
"test: delete multi line range line" : function() {
|
||||
var doc = new Document(["1234", "5678", "abcd"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.remove(new Range(0, 2, 2, 2));
|
||||
assert.equal(doc.getValue(), ["12cd"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1234", "5678", "abcd"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12cd"].join("\n"));
|
||||
},
|
||||
|
||||
"test: delete full lines" : function() {
|
||||
var doc = new Document(["1234", "5678", "abcd"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.remove(new Range(1, 0, 3, 0));
|
||||
assert.equal(doc.getValue(), ["1234", ""].join("\n"));
|
||||
},
|
||||
|
||||
"test: remove lines should return the removed lines" : function() {
|
||||
var doc = new Document(["1234", "5678", "abcd"]);
|
||||
|
||||
var removed = doc.removeLines(1, 2);
|
||||
assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n"));
|
||||
},
|
||||
|
||||
"test: should handle unix style new lines" : function() {
|
||||
var doc = new Document(["1", "2", "3"]);
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: should handle windows style new lines" : function() {
|
||||
var doc = new Document(["1", "2", "3"].join("\r\n"));
|
||||
|
||||
doc.setNewLineMode("unix");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: set new line mode to 'windows' should use '\\r\\n' as new lines": function() {
|
||||
var doc = new Document(["1", "2", "3"].join("\n"));
|
||||
doc.setNewLineMode("windows");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n"));
|
||||
},
|
||||
|
||||
"test: set new line mode to 'unix' should use '\\n' as new lines": function() {
|
||||
var doc = new Document(["1", "2", "3"].join("\r\n"));
|
||||
|
||||
doc.setNewLineMode("unix");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: set new line mode to 'auto' should detect the incoming nl type": function() {
|
||||
var doc = new Document(["1", "2", "3"].join("\n"));
|
||||
|
||||
doc.setNewLineMode("auto");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
|
||||
|
||||
var doc = new Document(["1", "2", "3"].join("\r\n"));
|
||||
|
||||
doc.setNewLineMode("auto");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n"));
|
||||
|
||||
doc.replace(new Range(0, 0, 2, 1), ["4", "5", "6"].join("\n"));
|
||||
assert.equal(["4", "5", "6"].join("\n"), doc.getValue());
|
||||
},
|
||||
|
||||
"test: set value": function() {
|
||||
var doc = new Document("1");
|
||||
assert.equal("1", doc.getValue());
|
||||
|
||||
doc.setValue(doc.getValue());
|
||||
assert.equal("1", doc.getValue());
|
||||
|
||||
var doc = new Document("1\n2");
|
||||
assert.equal("1\n2", doc.getValue());
|
||||
|
||||
doc.setValue(doc.getValue());
|
||||
assert.equal("1\n2", doc.getValue());
|
||||
},
|
||||
|
||||
"test: empty document has to contain one line": function() {
|
||||
var doc = new Document("");
|
||||
assert.equal(doc.$lines.length, 1);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var TokenIterator = require("../token_iterator").TokenIterator;
|
||||
var Range = require("../range").Range;
|
||||
|
||||
/**
|
||||
* class BracketMatch
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new BracketMatch(position)
|
||||
* - platform (String): Identifier for the platform; must be either `'mac'` or `'win'`
|
||||
* - commands (Array): A list of commands
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
*
|
||||
**/
|
||||
function BracketMatch() {
|
||||
|
||||
/**
|
||||
* new findMatchingBracket(position)
|
||||
* - position (Number): Identifier for the platform; must be either `'mac'` or `'win'`
|
||||
* - commands (Array): A list of commands
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.findMatchingBracket = function(position) {
|
||||
if (position.column == 0) return null;
|
||||
|
||||
var charBeforeCursor = this.getLine(position.row).charAt(position.column-1);
|
||||
if (charBeforeCursor == "") return null;
|
||||
|
||||
var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/);
|
||||
if (!match)
|
||||
return null;
|
||||
|
||||
if (match[1])
|
||||
return this.$findClosingBracket(match[1], position);
|
||||
else
|
||||
return this.$findOpeningBracket(match[2], position);
|
||||
};
|
||||
|
||||
this.getBracketRange = function(pos) {
|
||||
var line = this.getLine(pos.row);
|
||||
var before = true, range;
|
||||
|
||||
var chr = line.charAt(pos.column-1);
|
||||
var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/);
|
||||
if (!match) {
|
||||
chr = line.charAt(pos.column);
|
||||
pos = {row: pos.row, column: pos.column + 1};
|
||||
match = chr && chr.match(/([\(\[\{])|([\)\]\}])/);
|
||||
before = false;
|
||||
}
|
||||
if (!match)
|
||||
return null;
|
||||
|
||||
if (match[1]) {
|
||||
var bracketPos = this.$findClosingBracket(match[1], pos);
|
||||
if (!bracketPos)
|
||||
return null;
|
||||
range = Range.fromPoints(pos, bracketPos);
|
||||
if (!before) {
|
||||
range.end.column++;
|
||||
range.start.column--;
|
||||
}
|
||||
range.cursor = range.end;
|
||||
} else {
|
||||
var bracketPos = this.$findOpeningBracket(match[2], pos);
|
||||
if (!bracketPos)
|
||||
return null;
|
||||
range = Range.fromPoints(bracketPos, pos);
|
||||
if (!before) {
|
||||
range.start.column++;
|
||||
range.end.column--;
|
||||
}
|
||||
range.cursor = range.start;
|
||||
}
|
||||
|
||||
return range;
|
||||
};
|
||||
|
||||
this.$brackets = {
|
||||
")": "(",
|
||||
"(": ")",
|
||||
"]": "[",
|
||||
"[": "]",
|
||||
"{": "}",
|
||||
"}": "{"
|
||||
};
|
||||
|
||||
this.$findOpeningBracket = function(bracket, position, typeRe) {
|
||||
var openBracket = this.$brackets[bracket];
|
||||
var depth = 1;
|
||||
|
||||
var iterator = new TokenIterator(this, position.row, position.column);
|
||||
var token = iterator.getCurrentToken();
|
||||
if (!token)
|
||||
token = iterator.stepForward();
|
||||
if (!token)
|
||||
return
|
||||
|
||||
if (!typeRe){
|
||||
typeRe = new RegExp(
|
||||
"(\\.?" +
|
||||
token.type.replace(".", "\\.").replace("rparen", ".paren")
|
||||
+ ")+"
|
||||
);
|
||||
}
|
||||
|
||||
// Start searching in token, just before the character at position.column
|
||||
var valueIndex = position.column - iterator.getCurrentTokenColumn() - 2;
|
||||
var value = token.value;
|
||||
|
||||
while (true) {
|
||||
|
||||
while (valueIndex >= 0) {
|
||||
var chr = value.charAt(valueIndex);
|
||||
if (chr == openBracket) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
return {row: iterator.getCurrentTokenRow(),
|
||||
column: valueIndex + iterator.getCurrentTokenColumn()};
|
||||
}
|
||||
}
|
||||
else if (chr == bracket) {
|
||||
depth += 1;
|
||||
}
|
||||
valueIndex -= 1;
|
||||
}
|
||||
|
||||
// Scan backward through the document, looking for the next token
|
||||
// whose type matches typeRe
|
||||
do {
|
||||
token = iterator.stepBackward();
|
||||
} while (token && !typeRe.test(token.type));
|
||||
|
||||
if (token == null)
|
||||
break;
|
||||
|
||||
value = token.value;
|
||||
valueIndex = value.length - 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
this.$findClosingBracket = function(bracket, position, typeRe) {
|
||||
var closingBracket = this.$brackets[bracket];
|
||||
var depth = 1;
|
||||
|
||||
var iterator = new TokenIterator(this, position.row, position.column);
|
||||
var token = iterator.getCurrentToken();
|
||||
if (!token)
|
||||
token = iterator.stepForward();
|
||||
if (!token)
|
||||
return
|
||||
|
||||
if (!typeRe){
|
||||
typeRe = new RegExp(
|
||||
"(\\.?" +
|
||||
token.type.replace(".", "\\.").replace("lparen", ".paren")
|
||||
+ ")+"
|
||||
);
|
||||
}
|
||||
|
||||
// Start searching in token, after the character at position.column
|
||||
var valueIndex = position.column - iterator.getCurrentTokenColumn();
|
||||
|
||||
while (true) {
|
||||
|
||||
var value = token.value;
|
||||
var valueLength = value.length;
|
||||
while (valueIndex < valueLength) {
|
||||
var chr = value.charAt(valueIndex);
|
||||
if (chr == closingBracket) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
return {row: iterator.getCurrentTokenRow(),
|
||||
column: valueIndex + iterator.getCurrentTokenColumn()};
|
||||
}
|
||||
}
|
||||
else if (chr == bracket) {
|
||||
depth += 1;
|
||||
}
|
||||
valueIndex += 1;
|
||||
}
|
||||
|
||||
// Scan forward through the document, looking for the next token
|
||||
// whose type matches typeRe
|
||||
do {
|
||||
token = iterator.stepForward();
|
||||
} while (token && !typeRe.test(token.type));
|
||||
|
||||
if (token == null)
|
||||
break;
|
||||
|
||||
valueIndex = 0;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
exports.BracketMatch = BracketMatch;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,116 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Simple fold-data struct.
|
||||
**/
|
||||
var Fold = exports.Fold = function(range, placeholder) {
|
||||
this.foldLine = null;
|
||||
this.placeholder = placeholder;
|
||||
this.range = range;
|
||||
this.start = range.start;
|
||||
this.end = range.end;
|
||||
|
||||
this.sameRow = range.start.row == range.end.row;
|
||||
this.subFolds = [];
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.toString = function() {
|
||||
return '"' + this.placeholder + '" ' + this.range.toString();
|
||||
};
|
||||
|
||||
this.setFoldLine = function(foldLine) {
|
||||
this.foldLine = foldLine;
|
||||
this.subFolds.forEach(function(fold) {
|
||||
fold.setFoldLine(foldLine);
|
||||
});
|
||||
};
|
||||
|
||||
this.clone = function() {
|
||||
var range = this.range.clone();
|
||||
var fold = new Fold(range, this.placeholder);
|
||||
this.subFolds.forEach(function(subFold) {
|
||||
fold.subFolds.push(subFold.clone());
|
||||
});
|
||||
return fold;
|
||||
};
|
||||
|
||||
this.addSubFold = function(fold) {
|
||||
if (this.range.isEqual(fold))
|
||||
return this;
|
||||
|
||||
if (!this.range.containsRange(fold))
|
||||
throw "A fold can't intersect already existing fold" + fold.range + this.range;
|
||||
|
||||
var row = fold.range.start.row, column = fold.range.start.column;
|
||||
for (var i = 0, cmp = -1; i < this.subFolds.length; i++) {
|
||||
cmp = this.subFolds[i].range.compare(row, column);
|
||||
if (cmp != 1)
|
||||
break;
|
||||
}
|
||||
var afterStart = this.subFolds[i];
|
||||
|
||||
if (cmp == 0)
|
||||
return afterStart.addSubFold(fold)
|
||||
|
||||
// cmp == -1
|
||||
var row = fold.range.end.row, column = fold.range.end.column;
|
||||
for (var j = i, cmp = -1; j < this.subFolds.length; j++) {
|
||||
cmp = this.subFolds[j].range.compare(row, column);
|
||||
if (cmp != 1)
|
||||
break;
|
||||
}
|
||||
var afterEnd = this.subFolds[j];
|
||||
|
||||
if (cmp == 0)
|
||||
throw "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);
|
||||
|
||||
return fold;
|
||||
}
|
||||
|
||||
}).call(Fold.prototype);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,276 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Range = require("../range").Range;
|
||||
|
||||
/*
|
||||
* If an array is passed in, the folds are expected to be sorted already.
|
||||
*/
|
||||
function FoldLine(foldData, folds) {
|
||||
this.foldData = foldData;
|
||||
if (Array.isArray(folds)) {
|
||||
this.folds = folds;
|
||||
} else {
|
||||
folds = this.folds = [ folds ];
|
||||
}
|
||||
|
||||
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;
|
||||
this.end = this.range.end;
|
||||
|
||||
this.folds.forEach(function(fold) {
|
||||
fold.setFoldLine(this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
(function() {
|
||||
/*
|
||||
* Note: This doesn't update wrapData!
|
||||
*/
|
||||
this.shiftRow = function(shift) {
|
||||
this.start.row += shift;
|
||||
this.end.row += shift;
|
||||
this.folds.forEach(function(fold) {
|
||||
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";
|
||||
}
|
||||
this.folds.push(fold);
|
||||
this.folds.sort(function(a, b) {
|
||||
return -a.range.compareEnd(b.start.row, b.start.column);
|
||||
});
|
||||
if (this.range.compareEnd(fold.start.row, fold.start.column) > 0) {
|
||||
this.end.row = fold.end.row;
|
||||
this.end.column = fold.end.column;
|
||||
} else if (this.range.compareStart(fold.end.row, fold.end.column) < 0) {
|
||||
this.start.row = fold.start.row;
|
||||
this.start.column = fold.start.column;
|
||||
}
|
||||
} else if (fold.start.row == this.end.row) {
|
||||
this.folds.push(fold);
|
||||
this.end.row = fold.end.row;
|
||||
this.end.column = fold.end.column;
|
||||
} else if (fold.end.row == this.start.row) {
|
||||
this.folds.unshift(fold);
|
||||
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";
|
||||
}
|
||||
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;
|
||||
|
||||
if (endRow == null) {
|
||||
endRow = this.end.row;
|
||||
endColumn = this.end.column;
|
||||
}
|
||||
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
fold = folds[i];
|
||||
|
||||
comp = fold.range.compareStart(endRow, endColumn);
|
||||
// This fold is after the endRow/Column.
|
||||
if (comp == -1) {
|
||||
callback(null, endRow, endColumn, lastEnd, isNewRow);
|
||||
return;
|
||||
}
|
||||
|
||||
stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow);
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note the new lastEnd might not be on the same line. However,
|
||||
// it's the callback's job to recognize this.
|
||||
isNewRow = !fold.sameRow;
|
||||
lastEnd = fold.end.column;
|
||||
}
|
||||
callback(null, endRow, endColumn, lastEnd, isNewRow);
|
||||
}
|
||||
|
||||
this.getNextFoldTo = function(row, column) {
|
||||
var fold, cmp;
|
||||
for (var i = 0; i < this.folds.length; i++) {
|
||||
fold = this.folds[i];
|
||||
cmp = fold.range.compareEnd(row, column);
|
||||
if (cmp == -1) {
|
||||
return {
|
||||
fold: fold,
|
||||
kind: "after"
|
||||
};
|
||||
} else if (cmp == 0) {
|
||||
return {
|
||||
fold: fold,
|
||||
kind: "inside"
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
this.addRemoveChars = function(row, column, len) {
|
||||
var ret = this.getNextFoldTo(row, column),
|
||||
fold, folds;
|
||||
if (ret) {
|
||||
fold = ret.fold;
|
||||
if (ret.kind == "inside"
|
||||
&& fold.start.column != column
|
||||
&& fold.start.row != row)
|
||||
{
|
||||
//throwing here breaks whole editor
|
||||
//@todo properly handle this
|
||||
window.console && window.console.log(row, column, fold);
|
||||
} else if (fold.start.row == row) {
|
||||
folds = this.folds;
|
||||
var i = folds.indexOf(fold);
|
||||
if (i == 0) {
|
||||
this.start.column += len;
|
||||
}
|
||||
for (i; i < folds.length; i++) {
|
||||
fold = folds[i];
|
||||
fold.start.column += len;
|
||||
if (!fold.sameRow) {
|
||||
return;
|
||||
}
|
||||
fold.end.column += len;
|
||||
}
|
||||
this.end.column += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.split = function(row, column) {
|
||||
var fold = this.getNextFoldTo(row, column).fold,
|
||||
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;
|
||||
this.end.column = foldBefore.end.column;
|
||||
|
||||
// Remove the folds after row/column and create a new FoldLine
|
||||
// containing these removed folds.
|
||||
folds = folds.splice(i, folds.length - i);
|
||||
|
||||
var newFoldLine = new FoldLine(foldData, folds);
|
||||
foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine);
|
||||
return newFoldLine;
|
||||
}
|
||||
|
||||
this.merge = function(foldLineNext) {
|
||||
var folds = foldLineNext.folds;
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
this.addFold(folds[i]);
|
||||
}
|
||||
// Remove the foldLineNext - no longer needed, as
|
||||
// it's merged now with foldLineNext.
|
||||
var foldData = this.foldData;
|
||||
foldData.splice(foldData.indexOf(foldLineNext), 1);
|
||||
}
|
||||
|
||||
this.toString = function() {
|
||||
var ret = [this.range.toString() + ": [" ];
|
||||
|
||||
this.folds.forEach(function(fold) {
|
||||
ret.push(" " + fold.toString());
|
||||
});
|
||||
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];
|
||||
|
||||
idx -= fold.start.column - lastFoldEndColumn;
|
||||
if (idx < 0) {
|
||||
return {
|
||||
row: fold.start.row,
|
||||
column: fold.start.column + idx
|
||||
};
|
||||
}
|
||||
|
||||
idx -= fold.placeholder.length;
|
||||
if (idx < 0) {
|
||||
return fold.start;
|
||||
}
|
||||
|
||||
lastFoldEndColumn = fold.end.column;
|
||||
}
|
||||
|
||||
return {
|
||||
row: this.end.row,
|
||||
column: this.end.column + idx
|
||||
};
|
||||
}
|
||||
}).call(FoldLine.prototype);
|
||||
|
||||
exports.FoldLine = FoldLine;
|
||||
});
|
||||
@@ -0,0 +1,759 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Range = require("../range").Range;
|
||||
var FoldLine = require("./fold_line").FoldLine;
|
||||
var Fold = require("./fold").Fold;
|
||||
var TokenIterator = require("../token_iterator").TokenIterator;
|
||||
|
||||
function Folding() {
|
||||
/*
|
||||
* Looks up a fold at a given row/column. Possible values for side:
|
||||
* -1: ignore a fold if fold.start = row/column
|
||||
* +1: ignore a fold if fold.end = row/column
|
||||
*/
|
||||
this.getFoldAt = function(row, column, side) {
|
||||
var foldLine = this.getFoldLine(row);
|
||||
if (!foldLine)
|
||||
return null;
|
||||
|
||||
var folds = foldLine.folds;
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
var fold = folds[i];
|
||||
if (fold.range.contains(row, column)) {
|
||||
if (side == 1 && fold.range.isEnd(row, column)) {
|
||||
continue;
|
||||
} else if (side == -1 && fold.range.isStart(row, column)) {
|
||||
continue;
|
||||
}
|
||||
return fold;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns all folds in the given range. Note, that this will return folds
|
||||
*
|
||||
*/
|
||||
this.getFoldsInRange = function(range) {
|
||||
range = range.clone();
|
||||
var start = range.start;
|
||||
var end = range.end;
|
||||
var foldLines = this.$foldData;
|
||||
var foundFolds = [];
|
||||
|
||||
start.column += 1;
|
||||
end.column -= 1;
|
||||
|
||||
for (var i = 0; i < foldLines.length; i++) {
|
||||
var cmp = foldLines[i].range.compareRange(range);
|
||||
if (cmp == 2) {
|
||||
// Range is before foldLine. No intersection. This means,
|
||||
// there might be other foldLines that intersect.
|
||||
continue;
|
||||
}
|
||||
else if (cmp == -2) {
|
||||
// Range is after foldLine. There can't be any other foldLines then,
|
||||
// so let's give up.
|
||||
break;
|
||||
}
|
||||
|
||||
var folds = foldLines[i].folds;
|
||||
for (var j = 0; j < folds.length; j++) {
|
||||
var fold = folds[j];
|
||||
cmp = fold.range.compareRange(range);
|
||||
if (cmp == -2) {
|
||||
break;
|
||||
} else if (cmp == 2) {
|
||||
continue;
|
||||
} else
|
||||
// WTF-state: Can happen due to -1/+1 to start/end column.
|
||||
if (cmp == 42) {
|
||||
break;
|
||||
}
|
||||
foundFolds.push(fold);
|
||||
}
|
||||
}
|
||||
return foundFolds;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns all folds in the document
|
||||
*/
|
||||
this.getAllFolds = function() {
|
||||
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]);
|
||||
|
||||
return folds;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns the string between folds at the given position.
|
||||
* E.g.
|
||||
* foo<fold>b|ar<fold>wolrd -> "bar"
|
||||
* foo<fold>bar<fold>wol|rd -> "world"
|
||||
* foo<fold>bar<fo|ld>wolrd -> <null>
|
||||
*
|
||||
* where | means the position of row/column
|
||||
*
|
||||
* The trim option determs if the return string should be trimed according
|
||||
* to the "side" passed with the trim value:
|
||||
*
|
||||
* E.g.
|
||||
* foo<fold>b|ar<fold>wolrd -trim=-1> "b"
|
||||
* foo<fold>bar<fold>wol|rd -trim=+1> "rld"
|
||||
* fo|o<fold>bar<fold>wolrd -trim=00> "foo"
|
||||
*/
|
||||
this.getFoldStringAt = function(row, column, trim, foldLine) {
|
||||
foldLine = foldLine || this.getFoldLine(row);
|
||||
if (!foldLine)
|
||||
return null;
|
||||
|
||||
var lastFold = {
|
||||
end: { column: 0 }
|
||||
};
|
||||
// TODO: Refactor to use getNextFoldTo function.
|
||||
var str, fold;
|
||||
for (var i = 0; i < foldLine.folds.length; i++) {
|
||||
fold = foldLine.folds[i];
|
||||
var cmp = fold.range.compareEnd(row, column);
|
||||
if (cmp == -1) {
|
||||
str = this
|
||||
.getLine(fold.start.row)
|
||||
.substring(lastFold.end.column, fold.start.column);
|
||||
break;
|
||||
}
|
||||
else if (cmp === 0) {
|
||||
return null;
|
||||
}
|
||||
lastFold = fold;
|
||||
}
|
||||
if (!str)
|
||||
str = this.getLine(fold.start.row).substring(lastFold.end.column);
|
||||
|
||||
if (trim == -1)
|
||||
return str.substring(0, column - lastFold.end.column);
|
||||
else if (trim == 1)
|
||||
return str.substring(column - lastFold.end.column);
|
||||
else
|
||||
return str;
|
||||
};
|
||||
|
||||
this.getFoldLine = function(docRow, startFoldLine) {
|
||||
var foldData = this.$foldData;
|
||||
var i = 0;
|
||||
if (startFoldLine)
|
||||
i = foldData.indexOf(startFoldLine);
|
||||
if (i == -1)
|
||||
i = 0;
|
||||
for (i; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i];
|
||||
if (foldLine.start.row <= docRow && foldLine.end.row >= docRow) {
|
||||
return foldLine;
|
||||
} else if (foldLine.end.row > docRow) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// returns the fold which starts after or contains docRow
|
||||
this.getNextFoldLine = function(docRow, startFoldLine) {
|
||||
var foldData = this.$foldData;
|
||||
var i = 0;
|
||||
if (startFoldLine)
|
||||
i = foldData.indexOf(startFoldLine);
|
||||
if (i == -1)
|
||||
i = 0;
|
||||
for (i; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i];
|
||||
if (foldLine.end.row >= docRow) {
|
||||
return foldLine;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.getFoldedRowCount = function(first, last) {
|
||||
var foldData = this.$foldData, rowCount = last-first+1;
|
||||
for (var i = 0; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i],
|
||||
end = foldLine.end.row,
|
||||
start = foldLine.start.row;
|
||||
if (end >= last) {
|
||||
if(start < last) {
|
||||
if(start >= first)
|
||||
rowCount -= last-start;
|
||||
else
|
||||
rowCount = 0;//in one fold
|
||||
}
|
||||
break;
|
||||
} else if(end >= first){
|
||||
if (start >= first) //fold inside range
|
||||
rowCount -= end-start;
|
||||
else
|
||||
rowCount -= end-first+1;
|
||||
}
|
||||
}
|
||||
return rowCount;
|
||||
};
|
||||
|
||||
this.$addFoldLine = function(foldLine) {
|
||||
this.$foldData.push(foldLine);
|
||||
this.$foldData.sort(function(a, b) {
|
||||
return a.start.row - b.start.row;
|
||||
});
|
||||
return foldLine;
|
||||
};
|
||||
|
||||
/*
|
||||
* Adds a new fold.
|
||||
*
|
||||
* @returns
|
||||
* The new created Fold object or an existing fold object in case the
|
||||
* passed in range fits an existing fold exactly.
|
||||
*/
|
||||
this.addFold = function(placeholder, range) {
|
||||
var foldData = this.$foldData;
|
||||
var added = false;
|
||||
var fold;
|
||||
|
||||
if (placeholder instanceof Fold)
|
||||
fold = placeholder;
|
||||
else
|
||||
fold = new Fold(range, placeholder);
|
||||
|
||||
this.$clipRangeToDocument(fold.range);
|
||||
|
||||
var startRow = fold.start.row;
|
||||
var startColumn = fold.start.column;
|
||||
var endRow = fold.end.row;
|
||||
var endColumn = fold.end.column;
|
||||
|
||||
// --- Some checking ---
|
||||
if (fold.placeholder.length < 2)
|
||||
throw "Placeholder has to be at least 2 characters";
|
||||
|
||||
if (startRow == endRow && endColumn - startColumn < 2)
|
||||
throw "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;
|
||||
}
|
||||
|
||||
// Check if there are folds in the range we create the new fold for.
|
||||
var folds = this.getFoldsInRange(fold.range);
|
||||
if (folds.length > 0) {
|
||||
// Remove the folds from fold data.
|
||||
this.removeFolds(folds);
|
||||
// Add the removed folds as subfolds on the new fold.
|
||||
fold.subFolds = folds;
|
||||
}
|
||||
|
||||
for (var i = 0; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i];
|
||||
if (endRow == foldLine.start.row) {
|
||||
foldLine.addFold(fold);
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
else if (startRow == foldLine.end.row) {
|
||||
foldLine.addFold(fold);
|
||||
added = true;
|
||||
if (!fold.sameRow) {
|
||||
// Check if we might have to merge two FoldLines.
|
||||
var foldLineNext = foldData[i + 1];
|
||||
if (foldLineNext && foldLineNext.start.row == endRow) {
|
||||
// We need to merge!
|
||||
foldLine.merge(foldLineNext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (endRow <= foldLine.start.row) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!added)
|
||||
foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold));
|
||||
|
||||
if (this.$useWrapMode)
|
||||
this.$updateWrapData(foldLine.start.row, foldLine.start.row);
|
||||
else
|
||||
this.$updateRowLengthCache(foldLine.start.row, foldLine.start.row);
|
||||
|
||||
// Notify that fold data has changed.
|
||||
this.$modified = true;
|
||||
this._emit("changeFold", { data: fold });
|
||||
|
||||
return fold;
|
||||
};
|
||||
|
||||
this.addFolds = function(folds) {
|
||||
folds.forEach(function(fold) {
|
||||
this.addFold(fold);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.removeFold = function(fold) {
|
||||
var foldLine = fold.foldLine;
|
||||
var startRow = foldLine.start.row;
|
||||
var endRow = foldLine.end.row;
|
||||
|
||||
var foldLines = this.$foldData;
|
||||
var folds = foldLine.folds;
|
||||
// Simple case where there is only one fold in the FoldLine such that
|
||||
// the entire fold line can get removed directly.
|
||||
if (folds.length == 1) {
|
||||
foldLines.splice(foldLines.indexOf(foldLine), 1);
|
||||
} else
|
||||
// If the fold is the last fold of the foldLine, just remove it.
|
||||
if (foldLine.range.isEnd(fold.end.row, fold.end.column)) {
|
||||
folds.pop();
|
||||
foldLine.end.row = folds[folds.length - 1].end.row;
|
||||
foldLine.end.column = folds[folds.length - 1].end.column;
|
||||
} else
|
||||
// If the fold is the first fold of the foldLine, just remove it.
|
||||
if (foldLine.range.isStart(fold.start.row, fold.start.column)) {
|
||||
folds.shift();
|
||||
foldLine.start.row = folds[0].start.row;
|
||||
foldLine.start.column = folds[0].start.column;
|
||||
} else
|
||||
// We know there are more then 2 folds and the fold is not at the edge.
|
||||
// This means, the fold is somewhere in between.
|
||||
//
|
||||
// If the fold is in one row, we just can remove it.
|
||||
if (fold.sameRow) {
|
||||
folds.splice(folds.indexOf(fold), 1);
|
||||
} else
|
||||
// The fold goes over more then one row. This means remvoing this fold
|
||||
// will cause the fold line to get splitted up. newFoldLine is the second part
|
||||
{
|
||||
var newFoldLine = foldLine.split(fold.start.row, fold.start.column);
|
||||
folds = newFoldLine.folds;
|
||||
folds.shift();
|
||||
newFoldLine.start.row = folds[0].start.row;
|
||||
newFoldLine.start.column = folds[0].start.column;
|
||||
}
|
||||
|
||||
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.removeFolds = function(folds) {
|
||||
// We need to clone the folds array passed in as it might be the folds
|
||||
// array of a fold line and as we call this.removeFold(fold), folds
|
||||
// are removed from folds and changes the current index.
|
||||
var cloneFolds = [];
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
cloneFolds.push(folds[i]);
|
||||
}
|
||||
|
||||
cloneFolds.forEach(function(fold) {
|
||||
this.removeFold(fold);
|
||||
}, this);
|
||||
this.$modified = true;
|
||||
};
|
||||
|
||||
this.expandFold = function(fold) {
|
||||
this.removeFold(fold);
|
||||
fold.subFolds.forEach(function(fold) {
|
||||
this.addFold(fold);
|
||||
}, this);
|
||||
fold.subFolds = [];
|
||||
};
|
||||
|
||||
this.expandFolds = function(folds) {
|
||||
folds.forEach(function(fold) {
|
||||
this.expandFold(fold);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.unfold = function(location, expandInner) {
|
||||
var range, folds;
|
||||
if (location == null)
|
||||
range = new Range(0, 0, this.getLength(), 0);
|
||||
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);
|
||||
if (expandInner) {
|
||||
this.removeFolds(folds);
|
||||
} else {
|
||||
// TODO: might need to remove and add folds in one go instead of using
|
||||
// expandFolds several times.
|
||||
while (folds.length) {
|
||||
this.expandFolds(folds);
|
||||
folds = this.getFoldsInRange(range);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Checks if a given documentRow is folded. This is true if there are some
|
||||
* folded parts such that some parts of the line is still visible.
|
||||
**/
|
||||
this.isRowFolded = function(docRow, startFoldRow) {
|
||||
return !!this.getFoldLine(docRow, startFoldRow);
|
||||
};
|
||||
|
||||
this.getRowFoldEnd = function(docRow, startFoldRow) {
|
||||
var foldLine = this.getFoldLine(docRow, startFoldRow);
|
||||
return (foldLine
|
||||
? foldLine.end.row
|
||||
: docRow);
|
||||
};
|
||||
|
||||
this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) {
|
||||
if (startRow == null) {
|
||||
startRow = foldLine.start.row;
|
||||
startColumn = 0;
|
||||
}
|
||||
|
||||
if (endRow == null) {
|
||||
endRow = foldLine.end.row;
|
||||
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) {
|
||||
return;
|
||||
} else if (row == startRow) {
|
||||
if (column < startColumn) {
|
||||
return;
|
||||
}
|
||||
lastColumn = Math.max(startColumn, lastColumn);
|
||||
}
|
||||
if (placeholder) {
|
||||
textLine += placeholder;
|
||||
} else {
|
||||
textLine += doc.getLine(row).substring(lastColumn, column);
|
||||
}
|
||||
}.bind(this), endRow, endColumn);
|
||||
return textLine;
|
||||
};
|
||||
|
||||
this.getDisplayLine = function(row, endColumn, startRow, startColumn) {
|
||||
var foldLine = this.getFoldLine(row);
|
||||
|
||||
if (!foldLine) {
|
||||
var line;
|
||||
line = this.doc.getLine(row);
|
||||
return line.substring(startColumn || 0, endColumn || line.length);
|
||||
} else {
|
||||
return this.getFoldDisplayLine(
|
||||
foldLine, row, endColumn, startRow, startColumn);
|
||||
}
|
||||
};
|
||||
|
||||
this.$cloneFoldData = function() {
|
||||
var fd = [];
|
||||
fd = this.$foldData.map(function(foldLine) {
|
||||
var folds = foldLine.folds.map(function(fold) {
|
||||
return fold.clone();
|
||||
});
|
||||
return new FoldLine(fd, folds);
|
||||
});
|
||||
|
||||
return fd;
|
||||
};
|
||||
|
||||
this.toggleFold = function(tryToUnfold) {
|
||||
var selection = this.selection;
|
||||
var range = selection.getRange();
|
||||
var fold;
|
||||
var bracketPos;
|
||||
|
||||
if (range.isEmpty()) {
|
||||
var cursor = range.start;
|
||||
fold = this.getFoldAt(cursor.row, cursor.column);
|
||||
|
||||
if (fold) {
|
||||
this.expandFold(fold);
|
||||
return;
|
||||
}
|
||||
else if (bracketPos = this.findMatchingBracket(cursor)) {
|
||||
if (range.comparePoint(bracketPos) == 1) {
|
||||
range.end = bracketPos;
|
||||
}
|
||||
else {
|
||||
range.start = bracketPos;
|
||||
range.start.column++;
|
||||
range.end.column--;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
range = this.getCommentFoldRange(cursor.row, cursor.column) || range;
|
||||
}
|
||||
} else {
|
||||
var folds = this.getFoldsInRange(range);
|
||||
if (tryToUnfold && folds.length) {
|
||||
this.expandFolds(folds);
|
||||
return;
|
||||
}
|
||||
else if (folds.length == 1 ) {
|
||||
fold = folds[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!fold)
|
||||
fold = this.getFoldAt(range.start.row, range.start.column);
|
||||
|
||||
if (fold && fold.range.toString() == range.toString()) {
|
||||
this.expandFold(fold);
|
||||
return;
|
||||
}
|
||||
|
||||
var placeholder = "...";
|
||||
if (!range.isMultiLine()) {
|
||||
placeholder = this.getTextRange(range);
|
||||
if(placeholder.length < 4)
|
||||
return;
|
||||
placeholder = placeholder.trim().substring(0, 2) + "..";
|
||||
}
|
||||
|
||||
this.addFold(placeholder, range);
|
||||
};
|
||||
|
||||
this.getCommentFoldRange = function(row, column) {
|
||||
var iterator = new TokenIterator(this, row, column);
|
||||
var token = iterator.getCurrentToken();
|
||||
if (token && /^comment|string/.test(token.type)) {
|
||||
var range = new Range();
|
||||
var re = new RegExp(token.type.replace(/\..*/, "\\."));
|
||||
do {
|
||||
token = iterator.stepBackward();
|
||||
} while(token && re.test(token.type));
|
||||
|
||||
iterator.stepForward();
|
||||
range.start.row = iterator.getCurrentTokenRow();
|
||||
range.start.column = iterator.getCurrentTokenColumn() + 2;
|
||||
|
||||
iterator = new TokenIterator(this, row, column);
|
||||
|
||||
do {
|
||||
token = iterator.stepForward();
|
||||
} while(token && re.test(token.type));
|
||||
|
||||
token = iterator.stepBackward();
|
||||
|
||||
range.end.row = iterator.getCurrentTokenRow();
|
||||
range.end.column = iterator.getCurrentTokenColumn() + token.value.length;
|
||||
return range;
|
||||
}
|
||||
};
|
||||
|
||||
this.foldAll = function(startRow, endRow) {
|
||||
var foldWidgets = this.foldWidgets;
|
||||
endRow = endRow || this.getLength();
|
||||
for (var row = startRow || 0; row < endRow; row++) {
|
||||
if (foldWidgets[row] == null)
|
||||
foldWidgets[row] = this.getFoldWidget(row);
|
||||
if (foldWidgets[row] != "start")
|
||||
continue;
|
||||
|
||||
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);
|
||||
} catch(e) {}
|
||||
}
|
||||
};
|
||||
|
||||
this.$foldStyles = {
|
||||
"manual": 1,
|
||||
"markbegin": 1,
|
||||
"markbeginend": 1
|
||||
};
|
||||
this.$foldStyle = "markbegin";
|
||||
this.setFoldStyle = function(style) {
|
||||
if (!this.$foldStyles[style])
|
||||
throw new Error("invalid fold style: " + style + "[" + Object.keys(this.$foldStyles).join(", ") + "]");
|
||||
|
||||
if (this.$foldStyle == style)
|
||||
return;
|
||||
|
||||
this.$foldStyle = style;
|
||||
|
||||
if (style == "manual")
|
||||
this.unfold();
|
||||
|
||||
// reset folding
|
||||
var mode = this.$foldMode;
|
||||
this.$setFolding(null);
|
||||
this.$setFolding(mode);
|
||||
};
|
||||
|
||||
// structured folding
|
||||
this.$setFolding = function(foldMode) {
|
||||
if (this.$foldMode == foldMode)
|
||||
return;
|
||||
|
||||
this.$foldMode = foldMode;
|
||||
|
||||
this.removeListener('change', this.$updateFoldWidgets);
|
||||
this._emit("changeAnnotation");
|
||||
|
||||
if (!foldMode || this.$foldStyle == "manual") {
|
||||
this.foldWidgets = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.foldWidgets = [];
|
||||
this.getFoldWidget = foldMode.getFoldWidget.bind(foldMode, this, this.$foldStyle);
|
||||
this.getFoldWidgetRange = foldMode.getFoldWidgetRange.bind(foldMode, this, this.$foldStyle);
|
||||
|
||||
this.$updateFoldWidgets = this.updateFoldWidgets.bind(this);
|
||||
this.on('change', this.$updateFoldWidgets);
|
||||
|
||||
};
|
||||
|
||||
this.onFoldWidgetClick = function(row, e) {
|
||||
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);
|
||||
|
||||
if (fold) {
|
||||
if (addSubfolds)
|
||||
this.removeFold(fold);
|
||||
else
|
||||
this.expandFold(fold);
|
||||
return;
|
||||
}
|
||||
|
||||
var range = this.getFoldWidgetRange(row);
|
||||
if (range) {
|
||||
// sometimes singleline folds can be missed by the code above
|
||||
if (!range.isMultiLine()) {
|
||||
fold = this.getFoldAt(range.start.row, range.start.column, 1);
|
||||
if (fold && range.isEqual(fold.range)) {
|
||||
this.removeFold(fold);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlySubfolds)
|
||||
this.addFold("...", range);
|
||||
|
||||
if (addSubfolds)
|
||||
this.foldAll(range.start.row + 1, range.end.row);
|
||||
} else {
|
||||
if (addSubfolds)
|
||||
this.foldAll(row + 1, this.getLength());
|
||||
e.target.className += " invalid"
|
||||
}
|
||||
};
|
||||
|
||||
this.updateFoldWidgets = function(e) {
|
||||
var delta = e.data;
|
||||
var range = delta.range;
|
||||
var firstRow = range.start.row;
|
||||
var len = range.end.row - firstRow;
|
||||
|
||||
if (len === 0) {
|
||||
this.foldWidgets[firstRow] = null;
|
||||
} else if (delta.action == "removeText" || delta.action == "removeLines") {
|
||||
this.foldWidgets.splice(firstRow, len + 1, null);
|
||||
} else {
|
||||
var args = Array(len + 1);
|
||||
args.unshift(firstRow, 1);
|
||||
this.foldWidgets.splice.apply(this.foldWidgets, args);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
exports.Folding = Folding;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,981 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var lang = require("./lib/lang");
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var UndoManager = require("./undomanager").UndoManager;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
|
||||
function createFoldTestSession() {
|
||||
var lines = [
|
||||
"function foo(items) {",
|
||||
" for (var i=0; i<items.length; i++) {",
|
||||
" alert(items[i] + \"juhu\");",
|
||||
" } // Real Tab.",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"));
|
||||
session.setUndoManager(new UndoManager());
|
||||
session.addFold("args...", new Range(0, 13, 0, 18));
|
||||
session.addFold("foo...", new Range(1, 10, 2, 10));
|
||||
session.addFold("bar...", new Range(2, 20, 2, 25));
|
||||
return session;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test: find matching opening bracket in Text mode" : function() {
|
||||
var session = new EditSession(["(()(", "())))"]);
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 3}), 0, 1);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 2}), 1, 0);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 3}), 0, 3);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 4}), 0, 0);
|
||||
assert.equal(session.findMatchingBracket({row: 1, column: 5}), null);
|
||||
},
|
||||
|
||||
"test: find matching closing bracket in Text mode" : function() {
|
||||
var session = new EditSession(["(()(", "())))"]);
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 1}), 1, 1);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 1}), 1, 1);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 4}), 1, 2);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 2}), 0, 2);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 1}), 1, 3);
|
||||
assert.equal(session.findMatchingBracket({row: 0, column: 0}), null);
|
||||
},
|
||||
|
||||
"test: find matching opening bracket in JavaScript mode" : function() {
|
||||
var lines = [
|
||||
"function foo() {",
|
||||
" var str = \"{ foo()\";",
|
||||
" if (debug) {",
|
||||
" // write str (a string) to the console",
|
||||
" console.log(str);",
|
||||
" }",
|
||||
" str += \" bar() }\";",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 14}), 0, 12);
|
||||
assert.position(session.findMatchingBracket({row: 7, column: 1}), 0, 15);
|
||||
assert.position(session.findMatchingBracket({row: 6, column: 20}), 1, 15);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 22}), 1, 20);
|
||||
assert.position(session.findMatchingBracket({row: 3, column: 31}), 3, 21);
|
||||
assert.position(session.findMatchingBracket({row: 4, column: 24}), 4, 19);
|
||||
assert.equal(session.findMatchingBracket({row: 0, column: 1}), null);
|
||||
},
|
||||
|
||||
"test: find matching closing bracket in JavaScript mode" : function() {
|
||||
var lines = [
|
||||
"function foo() {",
|
||||
" var str = \"{ foo()\";",
|
||||
" if (debug) {",
|
||||
" // write str (a string) to the console",
|
||||
" console.log(str);",
|
||||
" }",
|
||||
" str += \" bar() }\";",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 13}), 0, 13);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 16}), 7, 0);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 16}), 6, 19);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 21}), 1, 21);
|
||||
assert.position(session.findMatchingBracket({row: 3, column: 22}), 3, 30);
|
||||
assert.position(session.findMatchingBracket({row: 4, column: 20}), 4, 23);
|
||||
},
|
||||
|
||||
"test: handle unbalanced brackets in JavaScript mode" : function() {
|
||||
var lines = [
|
||||
"function foo() {",
|
||||
" var str = \"{ foo()\";",
|
||||
" if (debug) {",
|
||||
" // write str a string) to the console",
|
||||
" console.log(str);",
|
||||
" ",
|
||||
" str += \" bar() \";",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
assert.equal(session.findMatchingBracket({row: 0, column: 16}), null);
|
||||
assert.equal(session.findMatchingBracket({row: 3, column: 30}), null);
|
||||
assert.equal(session.findMatchingBracket({row: 1, column: 16}), null);
|
||||
},
|
||||
|
||||
"test: match different bracket types" : function() {
|
||||
var session = new EditSession(["({[", ")]}"]);
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 1}), 1, 0);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 2}), 1, 2);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 3}), 1, 1);
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 1}), 0, 0);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 2}), 0, 2);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 3}), 0, 1);
|
||||
},
|
||||
|
||||
"test: move lines down" : function() {
|
||||
var session = new EditSession(["a1", "a2", "a3", "a4"]);
|
||||
|
||||
session.moveLinesDown(0, 1);
|
||||
assert.equal(session.getValue(), ["a3", "a1", "a2", "a4"].join("\n"));
|
||||
|
||||
session.moveLinesDown(1, 2);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesDown(2, 3);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesDown(2, 2);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a2", "a1"].join("\n"));
|
||||
},
|
||||
|
||||
"test: move lines up" : function() {
|
||||
var session = new EditSession(["a1", "a2", "a3", "a4"]);
|
||||
|
||||
session.moveLinesUp(2, 3);
|
||||
assert.equal(session.getValue(), ["a1", "a3", "a4", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesUp(1, 2);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesUp(0, 1);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesUp(2, 2);
|
||||
assert.equal(session.getValue(), ["a3", "a1", "a4", "a2"].join("\n"));
|
||||
},
|
||||
|
||||
"test: duplicate lines" : function() {
|
||||
var session = new EditSession(["1", "2", "3", "4"]);
|
||||
|
||||
session.duplicateLines(1, 2);
|
||||
assert.equal(session.getValue(), ["1", "2", "3", "2", "3", "4"].join("\n"));
|
||||
},
|
||||
|
||||
"test: duplicate last line" : function() {
|
||||
var session = new EditSession(["1", "2", "3"]);
|
||||
|
||||
session.duplicateLines(2, 2);
|
||||
assert.equal(session.getValue(), ["1", "2", "3", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: duplicate first line" : function() {
|
||||
var session = new EditSession(["1", "2", "3"]);
|
||||
|
||||
session.duplicateLines(0, 0);
|
||||
assert.equal(session.getValue(), ["1", "1", "2", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: getScreenLastRowColumn": function() {
|
||||
var session = new EditSession([
|
||||
"juhu",
|
||||
"12\t\t34",
|
||||
"ぁぁa"
|
||||
]);
|
||||
|
||||
assert.equal(session.getScreenLastRowColumn(0), 4);
|
||||
assert.equal(session.getScreenLastRowColumn(1), 10);
|
||||
assert.equal(session.getScreenLastRowColumn(2), 5);
|
||||
},
|
||||
|
||||
"test: convert document to screen coordinates" : function() {
|
||||
var session = new EditSession("01234\t567890\t1234");
|
||||
session.setTabSize(4);
|
||||
|
||||
assert.equal(session.documentToScreenColumn(0, 0), 0);
|
||||
assert.equal(session.documentToScreenColumn(0, 4), 4);
|
||||
assert.equal(session.documentToScreenColumn(0, 5), 5);
|
||||
assert.equal(session.documentToScreenColumn(0, 6), 8);
|
||||
assert.equal(session.documentToScreenColumn(0, 12), 14);
|
||||
assert.equal(session.documentToScreenColumn(0, 13), 16);
|
||||
|
||||
session.setTabSize(2);
|
||||
|
||||
assert.equal(session.documentToScreenColumn(0, 0), 0);
|
||||
assert.equal(session.documentToScreenColumn(0, 4), 4);
|
||||
assert.equal(session.documentToScreenColumn(0, 5), 5);
|
||||
assert.equal(session.documentToScreenColumn(0, 6), 6);
|
||||
assert.equal(session.documentToScreenColumn(0, 7), 7);
|
||||
assert.equal(session.documentToScreenColumn(0, 12), 12);
|
||||
assert.equal(session.documentToScreenColumn(0, 13), 14);
|
||||
},
|
||||
|
||||
"test: convert document to screen coordinates with leading tabs": function() {
|
||||
var session = new EditSession("\t\t123");
|
||||
session.setTabSize(4);
|
||||
|
||||
assert.equal(session.documentToScreenColumn(0, 0), 0);
|
||||
assert.equal(session.documentToScreenColumn(0, 1), 4);
|
||||
assert.equal(session.documentToScreenColumn(0, 2), 8);
|
||||
assert.equal(session.documentToScreenColumn(0, 3), 9);
|
||||
},
|
||||
|
||||
"test: documentToScreen without soft wrap": function() {
|
||||
var session = new EditSession([
|
||||
"juhu",
|
||||
"12\t\t34",
|
||||
"ぁぁa"
|
||||
]);
|
||||
|
||||
assert.position(session.documentToScreenPosition(0, 3), 0, 3);
|
||||
assert.position(session.documentToScreenPosition(1, 3), 1, 4);
|
||||
assert.position(session.documentToScreenPosition(1, 4), 1, 8);
|
||||
assert.position(session.documentToScreenPosition(2, 2), 2, 4);
|
||||
},
|
||||
|
||||
"test: documentToScreen with soft wrap": function() {
|
||||
var session = new EditSession(["foo bar foo bar"]);
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(12, 12);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.position(session.documentToScreenPosition(0, 11), 0, 11);
|
||||
assert.position(session.documentToScreenPosition(0, 12), 1, 0);
|
||||
},
|
||||
|
||||
"test: documentToScreen with soft wrap and multibyte characters": function() {
|
||||
var session = new EditSession(["ぁぁa"]);
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(2, 2);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.position(session.documentToScreenPosition(0, 1), 1, 0);
|
||||
assert.position(session.documentToScreenPosition(0, 2), 2, 0);
|
||||
assert.position(session.documentToScreenPosition(0, 4), 2, 1);
|
||||
},
|
||||
|
||||
"test: documentToScreen should clip position to the document boundaries": function() {
|
||||
var session = new EditSession("foo bar\njuhu kinners");
|
||||
|
||||
assert.position(session.documentToScreenPosition(-1, 4), 0, 0);
|
||||
assert.position(session.documentToScreenPosition(3, 0), 1, 12);
|
||||
},
|
||||
|
||||
"test: convert screen to document coordinates" : function() {
|
||||
var session = new EditSession("01234\t567890\t1234");
|
||||
session.setTabSize(4);
|
||||
|
||||
assert.equal(session.screenToDocumentColumn(0, 0), 0);
|
||||
assert.equal(session.screenToDocumentColumn(0, 4), 4);
|
||||
assert.equal(session.screenToDocumentColumn(0, 5), 5);
|
||||
assert.equal(session.screenToDocumentColumn(0, 6), 5);
|
||||
assert.equal(session.screenToDocumentColumn(0, 7), 5);
|
||||
assert.equal(session.screenToDocumentColumn(0, 8), 6);
|
||||
assert.equal(session.screenToDocumentColumn(0, 9), 7);
|
||||
assert.equal(session.screenToDocumentColumn(0, 15), 12);
|
||||
assert.equal(session.screenToDocumentColumn(0, 19), 16);
|
||||
|
||||
session.setTabSize(2);
|
||||
|
||||
assert.equal(session.screenToDocumentColumn(0, 0), 0);
|
||||
assert.equal(session.screenToDocumentColumn(0, 4), 4);
|
||||
assert.equal(session.screenToDocumentColumn(0, 5), 5);
|
||||
assert.equal(session.screenToDocumentColumn(0, 6), 6);
|
||||
assert.equal(session.screenToDocumentColumn(0, 12), 12);
|
||||
assert.equal(session.screenToDocumentColumn(0, 13), 12);
|
||||
assert.equal(session.screenToDocumentColumn(0, 14), 13);
|
||||
},
|
||||
|
||||
"test: screenToDocument with soft wrap": function() {
|
||||
var session = new EditSession(["foo bar foo bar"]);
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(12, 12);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.position(session.screenToDocumentPosition(1, 0), 0, 12);
|
||||
assert.position(session.screenToDocumentPosition(0, 11), 0, 11);
|
||||
// Check if the position is clamped the right way.
|
||||
assert.position(session.screenToDocumentPosition(0, 12), 0, 11);
|
||||
assert.position(session.screenToDocumentPosition(0, 20), 0, 11);
|
||||
},
|
||||
|
||||
"test: screenToDocument with soft wrap and multi byte characters": function() {
|
||||
var session = new EditSession(["ぁ a"]);
|
||||
session.setUseWrapMode(true);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.position(session.screenToDocumentPosition(0, 1), 0, 0);
|
||||
assert.position(session.screenToDocumentPosition(0, 2), 0, 1);
|
||||
assert.position(session.screenToDocumentPosition(0, 3), 0, 2);
|
||||
assert.position(session.screenToDocumentPosition(0, 4), 0, 3);
|
||||
assert.position(session.screenToDocumentPosition(0, 5), 0, 3);
|
||||
},
|
||||
|
||||
"test: screenToDocument should clip position to the document boundaries": function() {
|
||||
var session = new EditSession("foo bar\njuhu kinners");
|
||||
|
||||
assert.position(session.screenToDocumentPosition(-1, 4), 0, 0);
|
||||
assert.position(session.screenToDocumentPosition(0, -1), 0, 0);
|
||||
assert.position(session.screenToDocumentPosition(0, 30), 0, 7);
|
||||
assert.position(session.screenToDocumentPosition(2, 4), 1, 12);
|
||||
assert.position(session.screenToDocumentPosition(1, 30), 1, 12);
|
||||
assert.position(session.screenToDocumentPosition(20, 50), 1, 12);
|
||||
assert.position(session.screenToDocumentPosition(20, 5), 1, 12);
|
||||
|
||||
// and the same for folded rows
|
||||
session.addFold("...", new Range(0,1,1,3));
|
||||
assert.position(session.screenToDocumentPosition(1, 2), 1, 12);
|
||||
// for wrapped rows
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(5,5);
|
||||
assert.position(session.screenToDocumentPosition(4, 1), 1, 12);
|
||||
},
|
||||
|
||||
"test: wrapLine split function" : function() {
|
||||
function computeAndAssert(line, assertEqual, wrapLimit, tabSize) {
|
||||
wrapLimit = wrapLimit || 12;
|
||||
tabSize = tabSize || 4;
|
||||
line = lang.stringTrimRight(line);
|
||||
var tokens = EditSession.prototype.$getDisplayTokens(line);
|
||||
var splits = EditSession.prototype.$computeWrapSplits(tokens, wrapLimit, tabSize);
|
||||
// console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
|
||||
assert.ok(splits.length == assertEqual.length);
|
||||
for (var i = 0; i < splits.length; i++) {
|
||||
assert.ok(splits[i] == assertEqual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Basic splitting.
|
||||
computeAndAssert("foo bar foo bar", [ 12 ]);
|
||||
computeAndAssert("foo bar f bar", [ 12 ]);
|
||||
computeAndAssert("foo bar f r", [ 14 ]);
|
||||
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.
|
||||
computeAndAssert("foo foo foo \t \t", [ ]);
|
||||
|
||||
// If there is no space to split, force split.
|
||||
computeAndAssert("foooooooooooooo", [ 12 ]);
|
||||
computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]);
|
||||
computeAndAssert("foo bar fooooooooooobooooooo", [8, 20]);
|
||||
|
||||
// Basic splitting + tabs.
|
||||
computeAndAssert("foo \t\tbar", [ 6 ]);
|
||||
computeAndAssert("foo \t \tbar", [ 7 ]);
|
||||
|
||||
// Ignore spaces/tabs at beginning of split.
|
||||
computeAndAssert("foo \t \t \t \t bar", [ 14 ]);
|
||||
|
||||
// Test wrapping for asian characters.
|
||||
computeAndAssert("ぁぁ", [1], 2);
|
||||
computeAndAssert(" ぁぁ", [1, 2], 2);
|
||||
computeAndAssert(" ぁ\tぁ", [1, 3], 2);
|
||||
computeAndAssert(" ぁぁ\tぁ", [1, 4], 4);
|
||||
|
||||
// Test wrapping for punctuation.
|
||||
computeAndAssert(" ab.c;ef++", [1, 3, 5, 7, 8], 2);
|
||||
computeAndAssert(" a.b", [1, 2, 3], 1);
|
||||
computeAndAssert("#>>", [1, 2], 1);
|
||||
},
|
||||
|
||||
"test get longest line" : function() {
|
||||
var session = new EditSession(["12"]);
|
||||
session.setTabSize(4);
|
||||
assert.equal(session.getScreenWidth(), 2);
|
||||
|
||||
session.doc.insertNewLine({row: 0, column: Infinity});
|
||||
session.doc.insertLines(1, ["123"]);
|
||||
assert.equal(session.getScreenWidth(), 3);
|
||||
|
||||
session.doc.insertNewLine({row: 0, column: Infinity});
|
||||
session.doc.insertLines(1, ["\t\t"]);
|
||||
|
||||
assert.equal(session.getScreenWidth(), 8);
|
||||
|
||||
session.setTabSize(2);
|
||||
assert.equal(session.getScreenWidth(), 4);
|
||||
},
|
||||
|
||||
"test getDisplayString": function() {
|
||||
var session = new EditSession(["12"]);
|
||||
session.setTabSize(4);
|
||||
|
||||
assert.equal(session.$getDisplayTokens("\t").length, 4);
|
||||
assert.equal(session.$getDisplayTokens("abc").length, 3);
|
||||
assert.equal(session.$getDisplayTokens("abc\t").length, 4);
|
||||
},
|
||||
|
||||
"test issue 83": function() {
|
||||
var session = new EditSession("");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
var document = session.getDocument();
|
||||
|
||||
session.setUseWrapMode(true);
|
||||
|
||||
document.insertLines(0, ["a", "b"]);
|
||||
document.insertLines(2, ["c", "d"]);
|
||||
document.removeLines(1, 2);
|
||||
},
|
||||
|
||||
"test wrapMode init has to create wrapData array": function() {
|
||||
var session = new EditSession("foo bar\nfoo bar");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
var document = session.getDocument();
|
||||
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(3, 3);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
// Test if wrapData is there and was computed.
|
||||
assert.equal(session.$wrapData.length, 2);
|
||||
assert.equal(session.$wrapData[0].length, 1);
|
||||
assert.equal(session.$wrapData[1].length, 1);
|
||||
},
|
||||
|
||||
"test first line blank with wrap": function() {
|
||||
var session = new EditSession("\nfoo");
|
||||
session.setUseWrapMode(true);
|
||||
assert.equal(session.doc.getValue(), ["", "foo"].join("\n"));
|
||||
},
|
||||
|
||||
"test first line blank with wrap 2" : function() {
|
||||
var session = new EditSession("");
|
||||
session.setUseWrapMode(true);
|
||||
session.setValue("\nfoo");
|
||||
|
||||
assert.equal(session.doc.getValue(), ["", "foo"].join("\n"));
|
||||
},
|
||||
|
||||
"test fold getFoldDisplayLine": function() {
|
||||
var session = createFoldTestSession();
|
||||
function assertDisplayLine(foldLine, str) {
|
||||
var line = session.getLine(foldLine.end.row);
|
||||
var displayLine =
|
||||
session.getFoldDisplayLine(foldLine, foldLine.end.row, line.length);
|
||||
assert.equal(displayLine, str);
|
||||
}
|
||||
|
||||
assertDisplayLine(session.$foldData[0], "function foo(args...) {")
|
||||
assertDisplayLine(session.$foldData[1], " for (vfoo...ert(items[bar...\"juhu\");");
|
||||
},
|
||||
|
||||
"test foldLine idxToPosition": function() {
|
||||
var session = createFoldTestSession();
|
||||
|
||||
function assertIdx2Pos(foldLineIdx, idx, row, column) {
|
||||
var foldLine = session.$foldData[foldLineIdx];
|
||||
assert.position(foldLine.idxToPosition(idx), row, column);
|
||||
}
|
||||
|
||||
// "function foo(items) {",
|
||||
// " for (var i=0; i<items.length; i++) {",
|
||||
// " alert(items[i] + \"juhu\");",
|
||||
// " } // Real Tab.",
|
||||
// "}"
|
||||
|
||||
assertIdx2Pos(0, 12, 0, 12);
|
||||
assertIdx2Pos(0, 13, 0, 13);
|
||||
assertIdx2Pos(0, 14, 0, 13);
|
||||
assertIdx2Pos(0, 19, 0, 13);
|
||||
assertIdx2Pos(0, 20, 0, 18);
|
||||
|
||||
assertIdx2Pos(1, 10, 1, 10);
|
||||
assertIdx2Pos(1, 11, 1, 10);
|
||||
assertIdx2Pos(1, 15, 1, 10);
|
||||
assertIdx2Pos(1, 16, 2, 10);
|
||||
assertIdx2Pos(1, 26, 2, 20);
|
||||
assertIdx2Pos(1, 27, 2, 20);
|
||||
assertIdx2Pos(1, 32, 2, 25);
|
||||
},
|
||||
|
||||
"test fold documentToScreen": function() {
|
||||
var session = createFoldTestSession();
|
||||
function assertDoc2Screen(docRow, docCol, screenRow, screenCol) {
|
||||
assert.position(
|
||||
session.documentToScreenPosition(docRow, docCol),
|
||||
screenRow, screenCol
|
||||
);
|
||||
}
|
||||
|
||||
// One fold ending in the same row.
|
||||
assertDoc2Screen(0, 0, 0, 0);
|
||||
assertDoc2Screen(0, 13, 0, 13);
|
||||
assertDoc2Screen(0, 14, 0, 13);
|
||||
assertDoc2Screen(0, 17, 0, 13);
|
||||
assertDoc2Screen(0, 18, 0, 20);
|
||||
|
||||
// Fold ending on some other row.
|
||||
assertDoc2Screen(1, 0, 1, 0);
|
||||
assertDoc2Screen(1, 10, 1, 10);
|
||||
assertDoc2Screen(1, 11, 1, 10);
|
||||
assertDoc2Screen(1, 99, 1, 10);
|
||||
|
||||
assertDoc2Screen(2, 0, 1, 10);
|
||||
assertDoc2Screen(2, 9, 1, 10);
|
||||
assertDoc2Screen(2, 10, 1, 16);
|
||||
assertDoc2Screen(2, 11, 1, 17);
|
||||
|
||||
// Fold in the same row with fold over more then one row in the same row.
|
||||
assertDoc2Screen(2, 19, 1, 25);
|
||||
assertDoc2Screen(2, 20, 1, 26);
|
||||
assertDoc2Screen(2, 21, 1, 26);
|
||||
|
||||
assertDoc2Screen(2, 24, 1, 26);
|
||||
assertDoc2Screen(2, 25, 1, 32);
|
||||
assertDoc2Screen(2, 26, 1, 33);
|
||||
assertDoc2Screen(2, 99, 1, 40);
|
||||
|
||||
// Test one position after the folds. Should be all like normal.
|
||||
assertDoc2Screen(3, 0, 2, 0);
|
||||
},
|
||||
|
||||
"test fold screenToDocument": function() {
|
||||
var session = createFoldTestSession();
|
||||
function assertScreen2Doc(docRow, docCol, screenRow, screenCol) {
|
||||
assert.position(
|
||||
session.screenToDocumentPosition(screenRow, screenCol),
|
||||
docRow, docCol
|
||||
);
|
||||
}
|
||||
|
||||
// One fold ending in the same row.
|
||||
assertScreen2Doc(0, 0, 0, 0);
|
||||
assertScreen2Doc(0, 13, 0, 13);
|
||||
assertScreen2Doc(0, 13, 0, 14);
|
||||
assertScreen2Doc(0, 18, 0, 20);
|
||||
assertScreen2Doc(0, 19, 0, 21);
|
||||
|
||||
// Fold ending on some other row.
|
||||
assertScreen2Doc(1, 0, 1, 0);
|
||||
assertScreen2Doc(1, 10, 1, 10);
|
||||
assertScreen2Doc(1, 10, 1, 11);
|
||||
|
||||
assertScreen2Doc(1, 10, 1, 15);
|
||||
assertScreen2Doc(2, 10, 1, 16);
|
||||
assertScreen2Doc(2, 11, 1, 17);
|
||||
|
||||
// Fold in the same row with fold over more then one row in the same row.
|
||||
assertScreen2Doc(2, 19, 1, 25);
|
||||
assertScreen2Doc(2, 20, 1, 26);
|
||||
assertScreen2Doc(2, 20, 1, 27);
|
||||
|
||||
assertScreen2Doc(2, 20, 1, 31);
|
||||
assertScreen2Doc(2, 25, 1, 32);
|
||||
assertScreen2Doc(2, 26, 1, 33);
|
||||
assertScreen2Doc(2, 33, 1, 99);
|
||||
|
||||
// Test one position after the folds. Should be all like normal.
|
||||
assertScreen2Doc(3, 0, 2, 0);
|
||||
},
|
||||
|
||||
"test getFoldsInRange()": function() {
|
||||
var session = createFoldTestSession();
|
||||
var foldLines = session.$foldData;
|
||||
var folds = foldLines[0].folds.concat(foldLines[1].folds);
|
||||
|
||||
function test(startRow, startColumn, endColumn, endRow, folds) {
|
||||
var r = new Range(startRow, startColumn, endColumn, endRow);
|
||||
var retFolds = session.getFoldsInRange(r);
|
||||
|
||||
assert.ok(retFolds.length == folds.length);
|
||||
for (var i = 0; i < retFolds.length; i++) {
|
||||
assert.equal(retFolds[i].range + "", folds[i].range + "");
|
||||
}
|
||||
}
|
||||
|
||||
test(0, 0, 0, 13, [ ]);
|
||||
test(0, 0, 0, 14, [ folds[0] ]);
|
||||
test(0, 0, 0, 18, [ folds[0] ]);
|
||||
test(0, 0, 1, 10, [ folds[0] ]);
|
||||
test(0, 0, 1, 11, [ folds[0], folds[1] ]);
|
||||
test(0, 18, 1, 11, [ folds[1] ]);
|
||||
test(2, 0, 2, 13, [ folds[1] ]);
|
||||
test(2, 10, 2, 20, [ ]);
|
||||
test(2, 10, 2, 11, [ ]);
|
||||
test(2, 19, 2, 20, [ ]);
|
||||
},
|
||||
|
||||
"test fold one-line text insert": function() {
|
||||
// These are mostly test for the FoldLine.addRemoveChars function.
|
||||
var session = createFoldTestSession();
|
||||
var undoManager = session.getUndoManager();
|
||||
var foldLines = session.$foldData;
|
||||
|
||||
function insert(row, column, text) {
|
||||
session.insert({row: row, column: column}, text);
|
||||
|
||||
// Force the session to store all changes made to the document NOW
|
||||
// on the undoManager's queue. Otherwise we can't undo in separate
|
||||
// steps later.
|
||||
session.$syncInformUndoManager();
|
||||
}
|
||||
|
||||
var foldLine, fold, folds;
|
||||
// First line.
|
||||
foldLine = session.$foldData[0];
|
||||
fold = foldLine.folds[0];
|
||||
|
||||
insert(0, 0, "0");
|
||||
assert.range(foldLine.range, 0, 14, 0, 19);
|
||||
assert.range(fold.range, 0, 14, 0, 19);
|
||||
insert(0, 14, "1");
|
||||
assert.range(foldLine.range, 0, 15, 0, 20);
|
||||
assert.range(fold.range, 0, 15, 0, 20);
|
||||
insert(0, 20, "2");
|
||||
assert.range(foldLine.range, 0, 15, 0, 20);
|
||||
assert.range(fold.range, 0, 15, 0, 20);
|
||||
|
||||
// Second line.
|
||||
foldLine = session.$foldData[1];
|
||||
folds = foldLine.folds;
|
||||
|
||||
insert(1, 0, "3");
|
||||
assert.range(foldLine.range, 1, 11, 2, 25);
|
||||
assert.range(folds[0].range, 1, 11, 2, 10);
|
||||
assert.range(folds[1].range, 2, 20, 2, 25);
|
||||
|
||||
insert(1, 11, "4");
|
||||
assert.range(foldLine.range, 1, 12, 2, 25);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 20, 2, 25);
|
||||
|
||||
insert(2, 10, "5");
|
||||
assert.range(foldLine.range, 1, 12, 2, 26);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 21, 2, 26);
|
||||
|
||||
insert(2, 21, "6");
|
||||
assert.range(foldLine.range, 1, 12, 2, 27);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 22, 2, 27);
|
||||
|
||||
insert(2, 27, "7");
|
||||
assert.range(foldLine.range, 1, 12, 2, 27);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 22, 2, 27);
|
||||
|
||||
// UNDO = REMOVE
|
||||
undoManager.undo(); // 6
|
||||
assert.range(foldLine.range, 1, 12, 2, 27);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 22, 2, 27);
|
||||
|
||||
undoManager.undo(); // 5
|
||||
assert.range(foldLine.range, 1, 12, 2, 26);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 21, 2, 26);
|
||||
|
||||
undoManager.undo(); // 4
|
||||
assert.range(foldLine.range, 1, 12, 2, 25);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 20, 2, 25);
|
||||
|
||||
undoManager.undo(); // 3
|
||||
assert.range(foldLine.range, 1, 11, 2, 25);
|
||||
assert.range(folds[0].range, 1, 11, 2, 10);
|
||||
assert.range(folds[1].range, 2, 20, 2, 25);
|
||||
|
||||
undoManager.undo(); // Beginning first line.
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 0, 15, 0, 20);
|
||||
assert.range(foldLines[1].range, 1, 10, 2, 25);
|
||||
|
||||
foldLine = session.$foldData[0];
|
||||
fold = foldLine.folds[0];
|
||||
|
||||
undoManager.undo(); // 2
|
||||
assert.range(foldLine.range, 0, 15, 0, 20);
|
||||
assert.range(fold.range, 0, 15, 0, 20);
|
||||
|
||||
undoManager.undo(); // 1
|
||||
assert.range(foldLine.range, 0, 14, 0, 19);
|
||||
assert.range(fold.range, 0, 14, 0, 19);
|
||||
|
||||
undoManager.undo(); // 0
|
||||
assert.range(foldLine.range, 0, 13, 0, 18);
|
||||
assert.range(fold.range, 0, 13, 0, 18);
|
||||
},
|
||||
|
||||
"test fold multi-line insert/remove": function() {
|
||||
var session = createFoldTestSession(),
|
||||
undoManager = session.getUndoManager(),
|
||||
foldLines = session.$foldData;
|
||||
function insert(row, column, text) {
|
||||
session.insert({row: row, column: column}, text);
|
||||
// Force the session to store all changes made to the document NOW
|
||||
// on the undoManager's queue. Otherwise we can't undo in separate
|
||||
// steps later.
|
||||
session.$syncInformUndoManager();
|
||||
}
|
||||
|
||||
var foldLines = session.$foldData, foldLine, fold, folds;
|
||||
|
||||
insert(0, 0, "\nfo0");
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 2, 10, 3, 25);
|
||||
|
||||
insert(2, 0, "\nba1");
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 3, 13, 4, 25);
|
||||
|
||||
insert(3, 10, "\nfo2");
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 25);
|
||||
|
||||
insert(5, 10, "\nba3");
|
||||
assert.equal(foldLines.length, 3);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 10);
|
||||
assert.range(foldLines[2].range, 6, 13, 6, 18);
|
||||
|
||||
insert(6, 18, "\nfo4");
|
||||
assert.equal(foldLines.length, 3);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 10);
|
||||
assert.range(foldLines[2].range, 6, 13, 6, 18);
|
||||
|
||||
undoManager.undo(); // 3
|
||||
assert.equal(foldLines.length, 3);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 10);
|
||||
assert.range(foldLines[2].range, 6, 13, 6, 18);
|
||||
|
||||
undoManager.undo(); // 2
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 25);
|
||||
|
||||
undoManager.undo(); // 1
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 3, 13, 4, 25);
|
||||
|
||||
undoManager.undo(); // 0
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 2, 10, 3, 25);
|
||||
|
||||
undoManager.undo(); // Beginning
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 0, 13, 0, 18);
|
||||
assert.range(foldLines[1].range, 1, 10, 2, 25);
|
||||
// TODO: Add test for inseration inside of folds.
|
||||
},
|
||||
|
||||
"test fold wrap data compution": function() {
|
||||
function assertArray(a, b) {
|
||||
assert.ok(a.length == b.length);
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
assert.equal(a[i], b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function assertWrap(line0, line1, line2) {
|
||||
line0 && assertArray(wrapData[0], line0);
|
||||
line1 && assertArray(wrapData[1], line1);
|
||||
line2 && assertArray(wrapData[2], line2);
|
||||
}
|
||||
|
||||
function removeFoldAssertWrap(docRow, docColumn, line0, line1, line2) {
|
||||
session.removeFold(session.getFoldAt(docRow, docColumn));
|
||||
assertWrap(line0, line1, line2);
|
||||
}
|
||||
|
||||
var lines = [
|
||||
"foo bar foo bar",
|
||||
"foo bar foo bar",
|
||||
"foo bar foo bar"
|
||||
];
|
||||
|
||||
var session = new EditSession(lines.join("\n"));
|
||||
session.setUseWrapMode(true);
|
||||
session.$wrapLimit = 7;
|
||||
session.$updateWrapData(0, 2);
|
||||
var wrapData = session.$wrapData;
|
||||
|
||||
// Do a simple assertion without folds to check basic functionallity.
|
||||
assertWrap([8], [8], [8]);
|
||||
|
||||
// --- Do in line folding ---
|
||||
|
||||
// Adding a fold. The split position is inside of the fold. As placeholder
|
||||
// are not splitable, the split should be before the split.
|
||||
session.addFold("woot", new Range(0, 4, 0, 15));
|
||||
assertWrap([4], [8], [8]);
|
||||
|
||||
// Remove the fold again which should reset the wrapData.
|
||||
removeFoldAssertWrap(0, 4, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot", new Range(0, 6, 0, 9));
|
||||
assertWrap([6, 13], [8], [8]);
|
||||
removeFoldAssertWrap(0, 6, [8], [8], [8]);
|
||||
|
||||
// The fold fits into the wrap limit - no split expected.
|
||||
session.addFold("woot", new Range(0, 3, 0, 15));
|
||||
assertWrap([], [8], [8]);
|
||||
removeFoldAssertWrap(0, 4, [8], [8], [8]);
|
||||
|
||||
// Fold after split position should be all fine.
|
||||
session.addFold("woot", new Range(0, 8, 0, 15));
|
||||
assertWrap([8], [8], [8]);
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
// Fold's placeholder is far too long for wrapSplit.
|
||||
session.addFold("woot0123456789", new Range(0, 8, 0, 15));
|
||||
assertWrap([8], [8], [8]);
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
// Fold's placeholder is far too long for wrapSplit
|
||||
// + content at the end of the line
|
||||
session.addFold("woot0123456789", new Range(0, 6, 0, 8));
|
||||
assertWrap([6, 20], [8], [8]);
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot0123456789", new Range(0, 6, 0, 8));
|
||||
session.addFold("woot0123456789", new Range(0, 8, 0, 10));
|
||||
assertWrap([6, 20, 34], [8], [8]);
|
||||
session.removeFold(session.getFoldAt(0, 7));
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot0123456789", new Range(0, 7, 0, 9));
|
||||
session.addFold("woot0123456789", new Range(0, 13, 0, 15));
|
||||
assertWrap([7, 21, 25], [8], [8]);
|
||||
session.removeFold(session.getFoldAt(0, 7));
|
||||
removeFoldAssertWrap(0, 14, [8], [8], [8]);
|
||||
|
||||
// --- Do some multiline folding ---
|
||||
|
||||
// Add a fold over two lines. Note, that the wrapData[1] stays the
|
||||
// same. This is an implementation detail and expected behavior.
|
||||
session.addFold("woot", new Range(0, 8, 1, 15));
|
||||
assertWrap([8], [8 /* See comments */], [8]);
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot", new Range(0, 9, 1, 11));
|
||||
assertWrap([8, 14], [8 /* See comments */], [8]);
|
||||
removeFoldAssertWrap(0, 9, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot", new Range(0, 9, 1, 15));
|
||||
assertWrap([8], [8 /* See comments */], [8]);
|
||||
removeFoldAssertWrap(0, 9, [8], [8], [8]);
|
||||
|
||||
return session;
|
||||
},
|
||||
|
||||
"test add fold": function() {
|
||||
var session = createFoldTestSession();
|
||||
var fold;
|
||||
|
||||
function tryAddFold(placeholder, range, shouldFail) {
|
||||
var fail = false;
|
||||
try {
|
||||
fold = session.addFold(placeholder, range);
|
||||
} catch (e) {
|
||||
fail = true;
|
||||
}
|
||||
if (fail != shouldFail) {
|
||||
throw "Expected to get an exception";
|
||||
}
|
||||
}
|
||||
|
||||
tryAddFold("foo", new Range(0, 13, 0, 17), false);
|
||||
tryAddFold("foo", new Range(0, 14, 0, 18), true);
|
||||
tryAddFold("foo", new Range(0, 13, 0, 18), false);
|
||||
assert.equal(session.$foldData[0].folds.length, 1);
|
||||
|
||||
tryAddFold("f", new Range(0, 13, 0, 18), true);
|
||||
tryAddFold("foo", new Range(0, 18, 0, 21), false);
|
||||
assert.equal(session.$foldData[0].folds.length, 2);
|
||||
session.removeFold(fold);
|
||||
|
||||
tryAddFold("foo", new Range(0, 18, 0, 22), false);
|
||||
tryAddFold("foo", new Range(0, 18, 0, 19), true);
|
||||
tryAddFold("foo", new Range(0, 22, 1, 10), false);
|
||||
},
|
||||
|
||||
"test add subfolds": function() {
|
||||
var session = createFoldTestSession();
|
||||
var fold, oldFold;
|
||||
var foldData = session.$foldData;
|
||||
|
||||
oldFold = foldData[0].folds[0];
|
||||
|
||||
fold = session.addFold("fold0", new Range(0, 10, 0, 21));
|
||||
assert.equal(foldData[0].folds.length, 1);
|
||||
assert.equal(fold.subFolds.length, 1);
|
||||
assert.equal(fold.subFolds[0], oldFold);
|
||||
|
||||
session.expandFold(fold);
|
||||
assert.equal(foldData[0].folds.length, 1);
|
||||
assert.equal(foldData[0].folds[0], oldFold);
|
||||
assert.equal(fold.subFolds.length, 0);
|
||||
|
||||
fold = session.addFold("fold0", new Range(0, 13, 2, 10));
|
||||
assert.equal(foldData.length, 1);
|
||||
assert.equal(fold.subFolds.length, 2);
|
||||
assert.equal(fold.subFolds[0], oldFold);
|
||||
|
||||
session.expandFold(fold);
|
||||
assert.equal(foldData.length, 2);
|
||||
assert.equal(foldData[0].folds.length, 1);
|
||||
assert.equal(foldData[0].folds[0], oldFold);
|
||||
assert.equal(fold.subFolds.length, 0);
|
||||
|
||||
session.unfold(null, true);
|
||||
fold = session.addFold("fold0", new Range(0, 0, 0, 21));
|
||||
session.addFold("fold0", new Range(0, 1, 0, 5));
|
||||
session.addFold("fold0", new Range(0, 6, 0, 8));
|
||||
assert.equal(fold.subFolds.length, 2);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var Text = require("./mode/text").Mode;
|
||||
var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
var CssMode = require("./mode/css").Mode;
|
||||
var HtmlMode = require("./mode/html").Mode;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
setUp : function(next) {
|
||||
this.session1 = new EditSession(["abc", "def"]);
|
||||
this.session2 = new EditSession(["ghi", "jkl"]);
|
||||
|
||||
|
||||
this.editor = new Editor(new MockRenderer());
|
||||
next();
|
||||
},
|
||||
|
||||
"test: change document" : function() {
|
||||
this.editor.setSession(this.session1);
|
||||
assert.equal(this.editor.getSession(), this.session1);
|
||||
|
||||
this.editor.setSession(this.session2);
|
||||
assert.equal(this.editor.getSession(), this.session2);
|
||||
},
|
||||
|
||||
"test: only changes to the new document should have effect" : function() {
|
||||
var called = false;
|
||||
this.editor.onDocumentChange = function() {
|
||||
called = true;
|
||||
};
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
this.editor.setSession(this.session2);
|
||||
|
||||
this.session1.duplicateLines(0, 0);
|
||||
assert.notOk(called);
|
||||
|
||||
this.session2.duplicateLines(0, 0);
|
||||
assert.ok(called);
|
||||
},
|
||||
|
||||
"test: should use cursor of new document" : function() {
|
||||
this.session1.getSelection().moveCursorTo(0, 1);
|
||||
this.session2.getSelection().moveCursorTo(1, 0);
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
assert.position(this.editor.getCursorPosition(), 0, 1);
|
||||
|
||||
this.editor.setSession(this.session2);
|
||||
assert.position(this.editor.getCursorPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test: only changing the cursor of the new doc should not have an effect" : function() {
|
||||
this.editor.onCursorChange = function() {
|
||||
called = true;
|
||||
};
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
this.editor.setSession(this.session2);
|
||||
assert.position(this.editor.getCursorPosition(), 0, 0);
|
||||
|
||||
var called = false;
|
||||
this.session1.getSelection().moveCursorTo(0, 1);
|
||||
assert.position(this.editor.getCursorPosition(), 0, 0);
|
||||
assert.notOk(called);
|
||||
|
||||
this.session2.getSelection().moveCursorTo(1, 1);
|
||||
assert.position(this.editor.getCursorPosition(), 1, 1);
|
||||
assert.ok(called);
|
||||
},
|
||||
|
||||
"test: should use selection of new document" : function() {
|
||||
this.session1.getSelection().selectTo(0, 1);
|
||||
this.session2.getSelection().selectTo(1, 0);
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 0, 1);
|
||||
|
||||
this.editor.setSession(this.session2);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 1, 0);
|
||||
},
|
||||
|
||||
"test: only changing the selection of the new doc should not have an effect" : function() {
|
||||
this.editor.onSelectionChange = function() {
|
||||
called = true;
|
||||
};
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
this.editor.setSession(this.session2);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 0, 0);
|
||||
|
||||
var called = false;
|
||||
this.session1.getSelection().selectTo(0, 1);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 0, 0);
|
||||
assert.notOk(called);
|
||||
|
||||
this.session2.getSelection().selectTo(1, 1);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 1, 1);
|
||||
assert.ok(called);
|
||||
},
|
||||
|
||||
"test: should use mode of new document" : function() {
|
||||
this.editor.onChangeMode = function() {
|
||||
called = true;
|
||||
};
|
||||
this.editor.setSession(this.session1);
|
||||
this.editor.setSession(this.session2);
|
||||
|
||||
var called = false;
|
||||
this.session1.setMode(new Text());
|
||||
assert.notOk(called);
|
||||
|
||||
this.session2.setMode(new JavaScriptMode());
|
||||
assert.ok(called);
|
||||
},
|
||||
|
||||
"test: should use stop worker of old document" : function(next) {
|
||||
var self = this;
|
||||
|
||||
// 1. Open an editor and set the session to CssMode
|
||||
self.editor.setSession(self.session1);
|
||||
self.session1.setMode(new CssMode());
|
||||
|
||||
// 2. Add a line or two of valid CSS.
|
||||
self.session1.setValue("DIV { color: red; }");
|
||||
|
||||
// 3. Clear the session value.
|
||||
self.session1.setValue("");
|
||||
|
||||
// 4. Set the session to HtmlMode
|
||||
self.session1.setMode(new HtmlMode());
|
||||
|
||||
// 5. Try to type valid HTML
|
||||
self.session1.insert({row: 0, column: 0}, "<html></html>");
|
||||
|
||||
setTimeout(function() {
|
||||
assert.equal(Object.keys(self.session1.getAnnotations()).length, 0);
|
||||
next();
|
||||
}, 600);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mihai Sucan.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
var lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
|
||||
"Mauris at arcu mi, eu lobortis mauris. Quisque ut libero eget " +
|
||||
"diam congue vehicula. Quisque ut odio ut mi aliquam tincidunt. " +
|
||||
"Duis lacinia aliquam lorem eget eleifend. Morbi eget felis mi. " +
|
||||
"Duis quam ligula, consequat vitae convallis volutpat, blandit " +
|
||||
"nec neque. Nulla facilisi. Etiam suscipit lorem ac justo " +
|
||||
"sollicitudin tristique. Phasellus ut posuere nunc. Aliquam " +
|
||||
"scelerisque mollis felis non gravida. Vestibulum lacus sem, " +
|
||||
"posuere non bibendum id, luctus non dolor. Aenean id metus " +
|
||||
"lorem, vel dapibus est. Donec gravida feugiat augue nec " +
|
||||
"accumsan.Lorem ipsum dolor sit amet, consectetur adipiscing " +
|
||||
"elit. Nulla vulputate, velit vitae tincidunt congue, nunc " +
|
||||
"augue accumsan velit, eu consequat turpis lectus ac orci. " +
|
||||
"Pellentesque ornare dolor feugiat dui auctor eu varius nulla " +
|
||||
"fermentum. Sed aliquam odio at velit lacinia vel fermentum " +
|
||||
"felis sodales. In dignissim magna eget nunc lobortis non " +
|
||||
"fringilla nibh ullamcorper. Donec facilisis malesuada elit " +
|
||||
"at egestas. Etiam bibendum, diam vitae tempor aliquet, dui " +
|
||||
"libero vehicula odio, eget bibendum mauris velit eu lorem.\n" +
|
||||
"consectetur";
|
||||
|
||||
function callHighlighterUpdate(session, firstRow, lastRow) {
|
||||
var rangeCount = 0;
|
||||
var mockMarkerLayer = { drawSingleLineMarker: function() {rangeCount++;} }
|
||||
session.$searchHighlight.update([], mockMarkerLayer, session, {
|
||||
firstRow: firstRow,
|
||||
lastRow: lastRow
|
||||
});
|
||||
return rangeCount;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setUp: function(next) {
|
||||
this.session = new EditSession(lipsum);
|
||||
this.editor = new Editor(new MockRenderer(), this.session);
|
||||
this.selection = this.session.getSelection();
|
||||
this.search = this.editor.$search;
|
||||
next();
|
||||
},
|
||||
|
||||
"test: highlight selected words by default": function() {
|
||||
assert.equal(this.editor.getHighlightSelectedWord(), true);
|
||||
},
|
||||
|
||||
"test: highlight a word": function() {
|
||||
this.editor.moveCursorTo(0, 9);
|
||||
this.selection.selectWord();
|
||||
|
||||
var highlighter = this.editor.session.$searchHighlight;
|
||||
assert.ok(highlighter != null);
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "ipsum");
|
||||
assert.equal(highlighter.cache.length, 0);
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 2);
|
||||
},
|
||||
|
||||
"test: highlight a word and clear highlight": function() {
|
||||
this.editor.moveCursorTo(0, 8);
|
||||
this.selection.selectWord();
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "ipsum");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 2);
|
||||
|
||||
this.session.highlight("");
|
||||
assert.equal(this.session.$searchHighlight.cache.length, 0);
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: highlight another word": function() {
|
||||
this.selection.moveCursorTo(0, 14);
|
||||
this.selection.selectWord();
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "dolor");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 4);
|
||||
},
|
||||
|
||||
"test: no selection, no highlight": function() {
|
||||
this.selection.clearSelection();
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: select a word, no highlight": function() {
|
||||
this.selection.moveCursorTo(0, 14);
|
||||
this.selection.selectWord();
|
||||
|
||||
this.editor.setHighlightSelectedWord(false);
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "dolor");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: select a word with no matches": function() {
|
||||
this.editor.setHighlightSelectedWord(true);
|
||||
|
||||
var currentOptions = this.search.getOptions();
|
||||
var newOptions = {
|
||||
wrap: true,
|
||||
wholeWord: true,
|
||||
caseSensitive: true,
|
||||
needle: "Mauris"
|
||||
};
|
||||
this.search.set(newOptions);
|
||||
|
||||
var match = this.search.find(this.session);
|
||||
assert.notEqual(match, null, "found a match for 'Mauris'");
|
||||
|
||||
this.search.set(currentOptions);
|
||||
|
||||
this.selection.setSelectionRange(match);
|
||||
|
||||
assert.equal(this.session.getTextRange(match), "Mauris");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 1);
|
||||
},
|
||||
|
||||
"test: partial word selection 1": function() {
|
||||
this.selection.moveCursorTo(0, 14);
|
||||
this.selection.selectWord();
|
||||
this.selection.selectLeft();
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "dolo");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: partial word selection 2": function() {
|
||||
this.selection.moveCursorTo(0, 13);
|
||||
this.selection.selectWord();
|
||||
this.selection.selectRight();
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "dolor ");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: partial word selection 3": function() {
|
||||
this.selection.moveCursorTo(0, 14);
|
||||
this.selection.selectWord();
|
||||
this.selection.selectLeft();
|
||||
this.selection.shiftSelection(1);
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "olor");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: select last word": function() {
|
||||
this.selection.moveCursorTo(0, 1);
|
||||
|
||||
var currentOptions = this.search.getOptions();
|
||||
var newOptions = {
|
||||
wrap: true,
|
||||
wholeWord: true,
|
||||
caseSensitive: true,
|
||||
backwards: true,
|
||||
needle: "consectetur"
|
||||
};
|
||||
this.search.set(newOptions);
|
||||
|
||||
var match = this.search.find(this.session);
|
||||
assert.notEqual(match, null, "found a match for 'consectetur'");
|
||||
assert.position(match.start, 1, 0);
|
||||
|
||||
this.search.set(currentOptions);
|
||||
|
||||
this.selection.setSelectionRange(match);
|
||||
|
||||
assert.equal(this.session.getTextRange(match), "consectetur");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 1), 3);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
createEditSession : function(rows, cols) {
|
||||
var line = new Array(cols + 1).join("a");
|
||||
var text = new Array(rows).join(line + "\n") + line;
|
||||
return new EditSession(text);
|
||||
},
|
||||
|
||||
"test: navigate to end of file should scroll the last line into view" : function() {
|
||||
var doc = this.createEditSession(200, 10);
|
||||
var editor = new Editor(new MockRenderer(), doc);
|
||||
|
||||
editor.navigateFileEnd();
|
||||
var cursor = editor.getCursorPosition();
|
||||
|
||||
assert.ok(editor.getFirstVisibleRow() <= cursor.row);
|
||||
assert.ok(editor.getLastVisibleRow() >= cursor.row);
|
||||
},
|
||||
|
||||
"test: navigate to start of file should scroll the first row into view" : function() {
|
||||
var doc = this.createEditSession(200, 10);
|
||||
var editor = new Editor(new MockRenderer(), doc);
|
||||
|
||||
editor.moveCursorTo(editor.getLastVisibleRow() + 20);
|
||||
editor.navigateFileStart();
|
||||
|
||||
assert.equal(editor.getFirstVisibleRow(), 0);
|
||||
},
|
||||
|
||||
"test: goto hidden line should scroll the line into the middle of the viewport" : function() {
|
||||
var editor = new Editor(new MockRenderer(), this.createEditSession(200, 5));
|
||||
|
||||
editor.navigateTo(0, 0);
|
||||
editor.gotoLine(101);
|
||||
assert.position(editor.getCursorPosition(), 100, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 89);
|
||||
|
||||
editor.navigateTo(100, 0);
|
||||
editor.gotoLine(11);
|
||||
assert.position(editor.getCursorPosition(), 10, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 0);
|
||||
|
||||
editor.navigateTo(100, 0);
|
||||
editor.gotoLine(6);
|
||||
assert.position(editor.getCursorPosition(), 5, 0);
|
||||
assert.equal(0, editor.getFirstVisibleRow(), 0);
|
||||
|
||||
editor.navigateTo(100, 0);
|
||||
editor.gotoLine(1);
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 0);
|
||||
|
||||
editor.navigateTo(0, 0);
|
||||
editor.gotoLine(191);
|
||||
assert.position(editor.getCursorPosition(), 190, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 179);
|
||||
|
||||
editor.navigateTo(0, 0);
|
||||
editor.gotoLine(196);
|
||||
assert.position(editor.getCursorPosition(), 195, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 180);
|
||||
},
|
||||
|
||||
"test: goto visible line should only move the cursor and not scroll": function() {
|
||||
var editor = new Editor(new MockRenderer(), this.createEditSession(200, 5));
|
||||
|
||||
editor.navigateTo(0, 0);
|
||||
editor.gotoLine(12);
|
||||
assert.position(editor.getCursorPosition(), 11, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 0);
|
||||
|
||||
editor.navigateTo(30, 0);
|
||||
editor.gotoLine(33);
|
||||
assert.position(editor.getCursorPosition(), 32, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 30);
|
||||
},
|
||||
|
||||
"test: navigate from the end of a long line down to a short line and back should maintain the curser column": function() {
|
||||
var editor = new Editor(new MockRenderer(), new EditSession(["123456", "1"]));
|
||||
|
||||
editor.navigateTo(0, 6);
|
||||
assert.position(editor.getCursorPosition(), 0, 6);
|
||||
|
||||
editor.navigateDown();
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
|
||||
editor.navigateUp();
|
||||
assert.position(editor.getCursorPosition(), 0, 6);
|
||||
},
|
||||
|
||||
"test: reset desired column on navigate left or right": function() {
|
||||
var editor = new Editor(new MockRenderer(), new EditSession(["123456", "12"]));
|
||||
|
||||
editor.navigateTo(0, 6);
|
||||
assert.position(editor.getCursorPosition(), 0, 6);
|
||||
|
||||
editor.navigateDown();
|
||||
assert.position(editor.getCursorPosition(), 1, 2);
|
||||
|
||||
editor.navigateLeft();
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
|
||||
editor.navigateUp();
|
||||
assert.position(editor.getCursorPosition(), 0, 1);
|
||||
},
|
||||
|
||||
"test: typing text should update the desired column": function() {
|
||||
var editor = new Editor(new MockRenderer(), new EditSession(["1234", "1234567890"]));
|
||||
|
||||
editor.navigateTo(0, 3);
|
||||
editor.insert("juhu");
|
||||
|
||||
editor.navigateDown();
|
||||
assert.position(editor.getCursorPosition(), 1, 7);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,562 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
var UndoManager = require("./undomanager").UndoManager;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
"test: delete line from the middle" : function() {
|
||||
var session = new EditSession(["a", "b", "c", "d"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "a\nc\nd");
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "a\nd");
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "a");
|
||||
assert.position(editor.getCursorPosition(), 0, 1);
|
||||
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "");
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
},
|
||||
|
||||
"test: delete multiple selected lines" : function() {
|
||||
var session = new EditSession(["a", "b", "c", "d"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.removeLines();
|
||||
assert.equal(session.toString(), "a\nd");
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test: delete first line" : function() {
|
||||
var session = new EditSession(["a", "b", "c"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "b\nc");
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
},
|
||||
|
||||
"test: delete last should also delete the new line of the previous line" : function() {
|
||||
var session = new EditSession(["a", "b", "c", ""].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(3, 0);
|
||||
|
||||
editor.removeLines();
|
||||
assert.equal(session.toString(), "a\nb\nc");
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
|
||||
editor.removeLines();
|
||||
assert.equal(session.toString(), "a\nb");
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
},
|
||||
|
||||
"test: indent block" : function() {
|
||||
var session = new EditSession(["a12345", "b12345", "c12345"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 3);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.indent();
|
||||
|
||||
assert.equal(["a12345", " b12345", " c12345"].join("\n"), session.toString());
|
||||
|
||||
assert.position(editor.getCursorPosition(), 2, 7);
|
||||
|
||||
var range = editor.getSelectionRange();
|
||||
assert.position(range.start, 1, 7);
|
||||
assert.position(range.end, 2, 7);
|
||||
},
|
||||
|
||||
"test: indent selected lines" : function() {
|
||||
var session = new EditSession(["a12345", "b12345", "c12345"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.indent();
|
||||
assert.equal(["a12345", " b12345", "c12345"].join("\n"), session.toString());
|
||||
},
|
||||
|
||||
"test: no auto indent if cursor is before the {" : function() {
|
||||
var session = new EditSession("{", new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 0);
|
||||
editor.onTextInput("\n");
|
||||
assert.equal(["", "{"].join("\n"), session.toString());
|
||||
},
|
||||
|
||||
"test: outdent block" : function() {
|
||||
var session = new EditSession([" a12345", " b12345", " c12345"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 5);
|
||||
editor.getSelection().selectDown();
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.blockOutdent();
|
||||
assert.equal(session.toString(), [" a12345", "b12345", " c12345"].join("\n"));
|
||||
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
|
||||
var range = editor.getSelectionRange();
|
||||
assert.position(range.start, 0, 1);
|
||||
assert.position(range.end, 2, 1);
|
||||
|
||||
editor.blockOutdent();
|
||||
assert.equal(session.toString(), ["a12345", "b12345", "c12345"].join("\n"));
|
||||
|
||||
var range = editor.getSelectionRange();
|
||||
assert.position(range.start, 0, 0);
|
||||
assert.position(range.end, 2, 0);
|
||||
},
|
||||
|
||||
"test: outent without a selection should update cursor" : function() {
|
||||
var session = new EditSession(" 12");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 3);
|
||||
editor.blockOutdent(" ");
|
||||
|
||||
assert.equal(session.toString(), " 12");
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
},
|
||||
|
||||
"test: comment lines should perserve selection" : function() {
|
||||
var session = new EditSession([" abc", "cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 2);
|
||||
editor.getSelection().selectDown();
|
||||
editor.toggleCommentLines();
|
||||
|
||||
assert.equal(["// abc", "//cde"].join("\n"), session.toString());
|
||||
|
||||
var selection = editor.getSelectionRange();
|
||||
assert.position(selection.start, 0, 4);
|
||||
assert.position(selection.end, 1, 4);
|
||||
},
|
||||
|
||||
"test: uncomment lines should perserve selection" : function() {
|
||||
var session = new EditSession(["// abc", "//cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 1);
|
||||
editor.getSelection().selectDown();
|
||||
editor.getSelection().selectRight();
|
||||
editor.getSelection().selectRight();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
|
||||
assert.equal([" abc", "cde"].join("\n"), session.toString());
|
||||
assert.range(editor.getSelectionRange(), 0, 0, 1, 1);
|
||||
},
|
||||
|
||||
"test: toggle comment lines twice should return the original text" : function() {
|
||||
var session = new EditSession([" abc", "cde", "fg"], new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 0);
|
||||
editor.getSelection().selectDown();
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
editor.toggleCommentLines();
|
||||
|
||||
assert.equal([" abc", "cde", "fg"].join("\n"), session.toString());
|
||||
},
|
||||
|
||||
|
||||
"test: comment lines - if the selection end is at the line start it should stay there": function() {
|
||||
//select down
|
||||
var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 0);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
assert.range(editor.getSelectionRange(), 0, 2, 1, 0);
|
||||
|
||||
// select up
|
||||
var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.getSelection().selectUp();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
assert.range(editor.getSelectionRange(), 0, 2, 1, 0);
|
||||
},
|
||||
|
||||
"test: move lines down should select moved lines" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
},
|
||||
|
||||
"test: move lines up should select moved lines" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(2, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
"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);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.clearSelection();
|
||||
|
||||
editor.moveLinesDown();
|
||||
assert.equal(["11", "33", "22", "44"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
|
||||
editor.clearSelection();
|
||||
|
||||
editor.moveLinesUp();
|
||||
assert.equal(["11", "22", "33", "44"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
},
|
||||
|
||||
"test: copy lines down should select lines and place cursor at the selection start" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
"test: copy lines up should select lines and place cursor at the selection start" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
"test: input a tab with soft tab should convert it to spaces" : function() {
|
||||
var session = new EditSession("");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
session.setTabSize(2);
|
||||
session.setUseSoftTabs(true);
|
||||
|
||||
editor.onTextInput("\t");
|
||||
assert.equal(session.toString(), " ");
|
||||
|
||||
session.setTabSize(5);
|
||||
editor.onTextInput("\t");
|
||||
assert.equal(session.toString(), " ");
|
||||
},
|
||||
|
||||
"test: input tab without soft tabs should keep the tab character" : function() {
|
||||
var session = new EditSession("");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
session.setUseSoftTabs(false);
|
||||
|
||||
editor.onTextInput("\t");
|
||||
assert.equal(session.toString(), "\t");
|
||||
},
|
||||
|
||||
"test: undo/redo for delete line" : function() {
|
||||
var session = new EditSession(["111", "222", "333"]);
|
||||
var undoManager = new UndoManager();
|
||||
session.setUndoManager(undoManager);
|
||||
|
||||
var initialText = session.toString();
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.removeLines();
|
||||
var step1 = session.toString();
|
||||
assert.equal(step1, "222\n333");
|
||||
session.$syncInformUndoManager();
|
||||
|
||||
editor.removeLines();
|
||||
var step2 = session.toString();
|
||||
assert.equal(step2, "333");
|
||||
session.$syncInformUndoManager();
|
||||
|
||||
editor.removeLines();
|
||||
var step3 = session.toString();
|
||||
assert.equal(step3, "");
|
||||
session.$syncInformUndoManager();
|
||||
|
||||
undoManager.undo();
|
||||
session.$syncInformUndoManager();
|
||||
assert.equal(session.toString(), step2);
|
||||
|
||||
undoManager.undo();
|
||||
session.$syncInformUndoManager();
|
||||
assert.equal(session.toString(), step1);
|
||||
|
||||
undoManager.undo();
|
||||
session.$syncInformUndoManager();
|
||||
assert.equal(session.toString(), initialText);
|
||||
|
||||
undoManager.undo();
|
||||
session.$syncInformUndoManager();
|
||||
assert.equal(session.toString(), initialText);
|
||||
},
|
||||
|
||||
"test: remove left should remove character left of the cursor" : function() {
|
||||
var session = new EditSession(["123", "456"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.remove("left");
|
||||
assert.equal(session.toString(), "123\n56");
|
||||
},
|
||||
|
||||
"test: remove left should remove line break if cursor is at line start" : function() {
|
||||
var session = new EditSession(["123", "456"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.remove("left");
|
||||
assert.equal(session.toString(), "123456");
|
||||
},
|
||||
|
||||
"test: remove left should remove tabsize spaces if cursor is on a tab stop and preceeded by spaces" : function() {
|
||||
var session = new EditSession(["123", " 456"]);
|
||||
session.setUseSoftTabs(true);
|
||||
session.setTabSize(4);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 8);
|
||||
editor.remove("left");
|
||||
assert.equal(session.toString(), "123\n 456");
|
||||
},
|
||||
|
||||
"test: transpose at line start should be a noop": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.transposeLetters();
|
||||
|
||||
assert.equal(session.getValue(), ["123", "4567", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transpose in line should swap the charaters before and after the cursor": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 2);
|
||||
editor.transposeLetters();
|
||||
|
||||
assert.equal(session.getValue(), ["123", "4657", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transpose at line end should swap the last two characters": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 4);
|
||||
editor.transposeLetters();
|
||||
|
||||
assert.equal(session.getValue(), ["123", "4576", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transpose with non empty selection should be a noop": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.getSelection().selectRight();
|
||||
editor.transposeLetters();
|
||||
|
||||
assert.equal(session.getValue(), ["123", "4567", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transpose should move the cursor behind the last swapped character": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 2);
|
||||
editor.transposeLetters();
|
||||
assert.position(editor.getCursorPosition(), 1, 3);
|
||||
},
|
||||
|
||||
"test: remove to line end": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 2);
|
||||
editor.removeToLineEnd();
|
||||
assert.equal(session.getValue(), ["123", "45", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: remove to line end at line end should remove the new line": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 4);
|
||||
editor.removeToLineEnd();
|
||||
assert.position(editor.getCursorPosition(), 1, 4);
|
||||
assert.equal(session.getValue(), ["123", "456789"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transform selection to uppercase": function() {
|
||||
var session = new EditSession(["ajax", "dot", "org"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.getSelection().selectLineEnd();
|
||||
editor.toUpperCase()
|
||||
assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transform word to uppercase": function() {
|
||||
var session = new EditSession(["ajax", "dot", "org"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.toUpperCase()
|
||||
assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n"));
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test: transform selection to lowercase": function() {
|
||||
var session = new EditSession(["AJAX", "DOT", "ORG"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.getSelection().selectLineEnd();
|
||||
editor.toLowerCase()
|
||||
assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transform word to lowercase": function() {
|
||||
var session = new EditSession(["AJAX", "DOT", "ORG"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.toLowerCase()
|
||||
assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n"));
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
.ace_editor {
|
||||
font-family: 'Monaco', 'Menlo', 'Droid Sans Mono', 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ace_editor .ace_gutter {
|
||||
width: 25px !important;
|
||||
display: block;
|
||||
float: left;
|
||||
text-align: right;
|
||||
padding: 0 3px 0 0;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.ace_line { clear: both; }
|
||||
|
||||
*.ace_gutter-cell {
|
||||
-moz-user-select: -moz-none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jan Jongboom <fabian AT ajax DOT org>
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("../edit_session").EditSession;
|
||||
var TextLayer = require("../layer/text").Text;
|
||||
var baseStyles = require("../requirejs/text!./static.css");
|
||||
|
||||
/* 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) {
|
||||
lineStart = parseInt(lineStart || 1, 10);
|
||||
|
||||
var session = new EditSession("");
|
||||
session.setMode(mode);
|
||||
session.setUseWorker(false);
|
||||
|
||||
var textLayer = new TextLayer(document.createElement("div"));
|
||||
textLayer.setSession(session);
|
||||
textLayer.config = {
|
||||
characterWidth: 10,
|
||||
lineHeight: 20
|
||||
};
|
||||
|
||||
session.setValue(input);
|
||||
|
||||
var stringBuilder = [];
|
||||
var length = session.getLength();
|
||||
|
||||
for(var ix = 0; ix < length; ix++) {
|
||||
var lineTokens = session.getTokens(ix);
|
||||
stringBuilder.push("<div class='ace_line'>");
|
||||
if (!disableGutter)
|
||||
stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + (ix + lineStart) + "</span>");
|
||||
textLayer.$renderLine(stringBuilder, 0, lineTokens, true);
|
||||
stringBuilder.push("</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(""));
|
||||
|
||||
textLayer.destroy();
|
||||
|
||||
return {
|
||||
css: baseStyles + theme.cssText,
|
||||
html: html
|
||||
};
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("../test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var highlighter = require("./static_highlight");
|
||||
var JavaScriptMode = require("../mode/javascript").Mode;
|
||||
|
||||
// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite
|
||||
module.exports = {
|
||||
timeout: 10000,
|
||||
|
||||
"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 mode = new JavaScriptMode();
|
||||
|
||||
var isError = false, result;
|
||||
try {
|
||||
result = highlighter.render(snippet, mode, theme);
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
isError = true;
|
||||
}
|
||||
// todo: write something more meaningful
|
||||
assert.equal(isError, false);
|
||||
|
||||
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 mode = new JavaScriptMode();
|
||||
|
||||
var isError = false, result;
|
||||
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) {
|
||||
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 mode = new JavaScriptMode();
|
||||
|
||||
var isError = false, result;
|
||||
result = highlighter.render(snippet, mode, theme);
|
||||
assert.equal(!!result.html.match(/<div class='ace-tomorrow'>/), true);
|
||||
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
@@ -0,0 +1,536 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kevin Dangoor (kdangoor@mozilla.com)
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
* Harutyun Amirjanyan [harutyun@c9.io]
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var event = require("../lib/event");
|
||||
var UA = require("../lib/useragent");
|
||||
var net = require("../lib/net");
|
||||
var ace = require("../ace");
|
||||
|
||||
require("ace/theme/textmate");
|
||||
|
||||
module.exports = exports = ace;
|
||||
|
||||
/*
|
||||
* Returns the CSS property of element.
|
||||
* 1) If the CSS property is on the style object of the element, use it, OR
|
||||
* 2) Compute the CSS property
|
||||
*
|
||||
* If the property can't get computed, is 'auto' or 'intrinsic', the former
|
||||
* calculated property is used (this can happen in cases where the textarea
|
||||
* is hidden and has no dimension styles).
|
||||
*/
|
||||
var getCSSProperty = function(element, container, property) {
|
||||
var ret = element.style[property];
|
||||
|
||||
if (!ret) {
|
||||
if (window.getComputedStyle) {
|
||||
ret = window.getComputedStyle(element, '').getPropertyValue(property);
|
||||
} else {
|
||||
ret = element.currentStyle[property];
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret || ret == 'auto' || ret == 'intrinsic') {
|
||||
ret = container.style[property];
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
function applyStyles(elm, styles) {
|
||||
for (var style in styles) {
|
||||
elm.style[style] = styles[style];
|
||||
}
|
||||
}
|
||||
|
||||
function setupContainer(element, getValue) {
|
||||
if (element.type != 'textarea') {
|
||||
throw "Textarea required!";
|
||||
}
|
||||
|
||||
var parentNode = element.parentNode;
|
||||
|
||||
// This will hold the editor.
|
||||
var container = document.createElement('div');
|
||||
|
||||
// To put Ace in the place of the textarea, we have to copy a few of the
|
||||
// textarea's style attributes to the div container.
|
||||
//
|
||||
// The problem is that the properties have to get computed (they might be
|
||||
// defined by a CSS file on the page - you can't access such rules that
|
||||
// apply to an element via elm.style). Computed properties are converted to
|
||||
// pixels although the dimension might be given as percentage. When the
|
||||
// window resizes, the dimensions defined by percentages changes, so the
|
||||
// properties have to get recomputed to get the new/true pixels.
|
||||
var resizeEvent = function() {
|
||||
var style = 'position:relative;';
|
||||
[
|
||||
'margin-top', 'margin-left', 'margin-right', 'margin-bottom'
|
||||
].forEach(function(item) {
|
||||
style += item + ':' +
|
||||
getCSSProperty(element, container, item) + ';';
|
||||
});
|
||||
|
||||
// Calculating the width/height of the textarea is somewhat tricky. To
|
||||
// do it right, you have to include the paddings to the sides as well
|
||||
// (eg. width = width + padding-left, -right). This works well, as
|
||||
// long as the width of the element is not set or given in pixels. In
|
||||
// this case and after the textarea is hidden, getCSSProperty(element,
|
||||
// container, 'width') will still return pixel value. If the element
|
||||
// has realtiv dimensions (e.g. width='95<percent>')
|
||||
// getCSSProperty(...) will return pixel values only as long as the
|
||||
// textarea is visible. After it is hidden getCSSProperty will return
|
||||
// the relative dimensions as they are set on the element (in the case
|
||||
// of width, 95<percent>).
|
||||
// Making the sum of pixel vaules (e.g. padding) and realtive values
|
||||
// (e.g. <percent>) is not possible. As such the padding styles are
|
||||
// ignored.
|
||||
|
||||
// The complete width is the width of the textarea + the padding
|
||||
// to the left and right.
|
||||
var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px");
|
||||
var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px");
|
||||
style += 'height:' + height + ';width:' + width + ';';
|
||||
|
||||
// Set the display property to 'inline-block'.
|
||||
style += 'display:inline-block;';
|
||||
container.setAttribute('style', style);
|
||||
};
|
||||
event.addListener(window, 'resize', resizeEvent);
|
||||
|
||||
// Call the resizeEvent once, so that the size of the container is
|
||||
// calculated.
|
||||
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.
|
||||
while (parentNode !== document) {
|
||||
if (parentNode.tagName.toUpperCase() === 'FORM') {
|
||||
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.
|
||||
if (oldSumit) {
|
||||
oldSumit.call(this, evt);
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
parentNode = parentNode.parentNode;
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
exports.transformTextarea = function(element, loader) {
|
||||
var session;
|
||||
var container = setupContainer(element, function() {
|
||||
return session.getValue();
|
||||
});
|
||||
|
||||
// Hide the element.
|
||||
element.style.display = 'none';
|
||||
container.style.background = 'white';
|
||||
|
||||
//
|
||||
var editorDiv = document.createElement("div");
|
||||
applyStyles(editorDiv, {
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
right: "0px",
|
||||
bottom: "0px",
|
||||
border: "1px solid gray"
|
||||
});
|
||||
container.appendChild(editorDiv);
|
||||
|
||||
var settingOpener = document.createElement("div");
|
||||
applyStyles(settingOpener, {
|
||||
position: "absolute",
|
||||
width: "15px",
|
||||
right: "0px",
|
||||
bottom: "0px",
|
||||
background: "red",
|
||||
cursor: "nw-resize",
|
||||
borderStyle: "solid",
|
||||
borderWidth: "9px 8px 10px 9px",
|
||||
width: "2px",
|
||||
borderColor: "lightblue gray gray lightblue",
|
||||
zIndex: 101
|
||||
});
|
||||
|
||||
var settingDiv = document.createElement("div");
|
||||
var settingDivStyles = {
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
right: "0px",
|
||||
bottom: "0px",
|
||||
position: "absolute",
|
||||
padding: "5px",
|
||||
zIndex: 100,
|
||||
color: "white",
|
||||
display: "none",
|
||||
overflow: "auto",
|
||||
fontSize: "14px"
|
||||
};
|
||||
if (!UA.isOldIE) {
|
||||
settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
||||
} else {
|
||||
settingDivStyles.backgroundColor = "#333";
|
||||
}
|
||||
|
||||
applyStyles(settingDiv, settingDivStyles);
|
||||
container.appendChild(settingDiv);
|
||||
|
||||
// Power up ace on the textarea:
|
||||
var options = {};
|
||||
|
||||
var editor = ace.edit(editorDiv);
|
||||
session = editor.getSession();
|
||||
|
||||
session.setValue(element.value || element.innerHTML);
|
||||
editor.focus();
|
||||
|
||||
// Add the settingPanel opener to the editor's div.
|
||||
editorDiv.appendChild(settingOpener);
|
||||
|
||||
// Create the API.
|
||||
setupApi(editor, editorDiv, settingDiv, ace, options, loader);
|
||||
|
||||
// Create the setting's panel.
|
||||
setupSettingPanel(settingDiv, settingOpener, editor, options);
|
||||
|
||||
var state = "";
|
||||
event.addListener(settingOpener, "mousemove", function(e) {
|
||||
var rect = this.getBoundingClientRect();
|
||||
var x = e.clientX - rect.left, y = e.clientY - rect.top;
|
||||
if (x + y < (rect.width + rect.height)/2) {
|
||||
this.style.cursor = "pointer";
|
||||
state = "toggle";
|
||||
} else {
|
||||
state = "resize";
|
||||
this.style.cursor = "nw-resize";
|
||||
}
|
||||
});
|
||||
|
||||
event.addListener(settingOpener, "mousedown", function(e) {
|
||||
if (state == "toggle") {
|
||||
editor.setDisplaySettings();
|
||||
return;
|
||||
}
|
||||
container.style.zIndex = 100000;
|
||||
var rect = container.getBoundingClientRect();
|
||||
var startX = rect.width + rect.left - e.clientX;
|
||||
var startY = rect.height + rect.top - e.clientY;
|
||||
event.capture(settingOpener, function(e) {
|
||||
container.style.width = e.clientX - rect.left + startX + "px";
|
||||
container.style.height = e.clientY - rect.top + startY + "px";
|
||||
editor.resize();
|
||||
}, function() {});
|
||||
});
|
||||
|
||||
return editor;
|
||||
};
|
||||
|
||||
function load(url, module, callback) {
|
||||
net.loadScript(url, function() {
|
||||
require([module], callback);
|
||||
});
|
||||
}
|
||||
|
||||
function setupApi(editor, editorDiv, settingDiv, ace, options, loader) {
|
||||
var session = editor.getSession();
|
||||
var renderer = editor.renderer;
|
||||
loader = loader || load;
|
||||
|
||||
function toBool(value) {
|
||||
return value == "true";
|
||||
}
|
||||
|
||||
editor.setDisplaySettings = function(display) {
|
||||
if (display == null)
|
||||
display = settingDiv.style.display == "none";
|
||||
settingDiv.style.display = display ? "block" : "none";
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
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");
|
||||
}
|
||||
break;
|
||||
|
||||
case "fontSize":
|
||||
editorDiv.style.fontSize = value;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
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];
|
||||
};
|
||||
|
||||
editor.getOptions = function() {
|
||||
return options;
|
||||
};
|
||||
|
||||
for (var option in exports.options) {
|
||||
editor.setOption(option, exports.options[option]);
|
||||
}
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
function setupSettingPanel(settingDiv, settingOpener, editor, options) {
|
||||
var BOOL = {
|
||||
"true": true,
|
||||
"false": false
|
||||
};
|
||||
|
||||
var desc = {
|
||||
mode: "Mode:",
|
||||
gutter: "Display Gutter:",
|
||||
theme: "Theme:",
|
||||
fontSize: "Font Size:",
|
||||
softWrap: "Soft Wrap:",
|
||||
showPrintMargin: "Show Print Margin:",
|
||||
useSoftTabs: "Use Soft Tabs:",
|
||||
showInvisibles: "Show Invisibles"
|
||||
};
|
||||
|
||||
var optionValues = {
|
||||
mode: {
|
||||
text: "Plain",
|
||||
javascript: "JavaScript",
|
||||
xml: "XML",
|
||||
html: "HTML",
|
||||
css: "CSS",
|
||||
scss: "SCSS",
|
||||
python: "Python",
|
||||
php: "PHP",
|
||||
java: "Java",
|
||||
ruby: "Ruby",
|
||||
c_cpp: "C/C++",
|
||||
coffee: "CoffeeScript",
|
||||
json: "json",
|
||||
perl: "Perl",
|
||||
clojure: "Clojure",
|
||||
ocaml: "OCaml",
|
||||
csharp: "C#",
|
||||
haxe: "haXe",
|
||||
svg: "SVG",
|
||||
textile: "Textile",
|
||||
groovy: "Groovy",
|
||||
liquid: "Liquid",
|
||||
Scala: "Scala"
|
||||
},
|
||||
theme: {
|
||||
clouds: "Clouds",
|
||||
clouds_midnight: "Clouds Midnight",
|
||||
cobalt: "Cobalt",
|
||||
crimson_editor: "Crimson Editor",
|
||||
dawn: "Dawn",
|
||||
eclipse: "Eclipse",
|
||||
idle_fingers: "Idle Fingers",
|
||||
kr_theme: "Kr Theme",
|
||||
merbivore: "Merbivore",
|
||||
merbivore_soft: "Merbivore Soft",
|
||||
mono_industrial: "Mono Industrial",
|
||||
monokai: "Monokai",
|
||||
pastel_on_dark: "Pastel On Dark",
|
||||
solarized_dark: "Solarized Dark",
|
||||
solarized_light: "Solarized Light",
|
||||
textmate: "Textmate",
|
||||
twilight: "Twilight",
|
||||
vibrant_ink: "Vibrant Ink"
|
||||
},
|
||||
gutter: BOOL,
|
||||
fontSize: {
|
||||
"10px": "10px",
|
||||
"11px": "11px",
|
||||
"12px": "12px",
|
||||
"14px": "14px",
|
||||
"16px": "16px"
|
||||
},
|
||||
softWrap: {
|
||||
off: "Off",
|
||||
40: "40",
|
||||
80: "80",
|
||||
free: "Free"
|
||||
},
|
||||
showPrintMargin: BOOL,
|
||||
useSoftTabs: BOOL,
|
||||
showInvisibles: BOOL
|
||||
};
|
||||
|
||||
var table = [];
|
||||
table.push("<table><tr><th>Setting</th><th>Value</th></tr>");
|
||||
|
||||
function renderOption(builder, option, obj, cValue) {
|
||||
builder.push("<select title='" + option + "'>");
|
||||
for (var value in obj) {
|
||||
builder.push("<option value='" + value + "' ");
|
||||
|
||||
if (cValue == value) {
|
||||
builder.push(" selected ");
|
||||
}
|
||||
|
||||
builder.push(">",
|
||||
obj[value],
|
||||
"</option>");
|
||||
}
|
||||
builder.push("</select>");
|
||||
}
|
||||
|
||||
for (var option in options) {
|
||||
table.push("<tr><td>", desc[option], "</td>");
|
||||
table.push("<td>");
|
||||
renderOption(table, option, optionValues[option], options[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);
|
||||
};
|
||||
})();
|
||||
selects[i].onchange = onChange;
|
||||
}
|
||||
|
||||
var button = document.createElement("input");
|
||||
button.type = "button";
|
||||
button.value = "Hide";
|
||||
event.addListener(button, "click", function() {
|
||||
editor.setDisplaySettings(false);
|
||||
});
|
||||
settingDiv.appendChild(button);
|
||||
}
|
||||
|
||||
// Default startup options.
|
||||
exports.options = {
|
||||
mode: "text",
|
||||
theme: "textmate",
|
||||
gutter: "false",
|
||||
fontSize: "12px",
|
||||
softWrap: "off",
|
||||
showPrintMargin: "false",
|
||||
useSoftTabs: "true",
|
||||
showInvisibles: "true"
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,367 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck (julian.viereck@gmail.com)
|
||||
* Harutyun Amirjanyan (harutyun@c9.io)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
|
||||
var screenToTextBlockCoordinates = function(pageX, pageY) {
|
||||
var canvasPos = this.scroller.getBoundingClientRect();
|
||||
|
||||
var col = Math.floor(
|
||||
(pageX + this.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft()) / this.characterWidth
|
||||
);
|
||||
var row = Math.floor(
|
||||
(pageY + this.scrollTop - canvasPos.top - dom.getPageScrollTop()) / this.lineHeight
|
||||
);
|
||||
|
||||
return this.session.screenToDocumentPosition(row, col);
|
||||
};
|
||||
|
||||
var HashHandler = require("./hash_handler").HashHandler;
|
||||
exports.handler = new HashHandler();
|
||||
|
||||
var initialized = false;
|
||||
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;\
|
||||
-moz-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{\
|
||||
opacity: 1;\
|
||||
background-color: transparent;\
|
||||
}\
|
||||
.emacs-mode .ace_cursor.ace_overwrite {\
|
||||
opacity: 1;\
|
||||
background-color: transparent;\
|
||||
border-width: 0 0 2px 2px !important;\
|
||||
}\
|
||||
.emacs-mode .ace_text-layer {\
|
||||
z-index: 4\
|
||||
}\
|
||||
.emacs-mode .ace_cursor-layer {\
|
||||
z-index: 2\
|
||||
}', 'emacsMode'
|
||||
);
|
||||
}
|
||||
|
||||
editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates;
|
||||
editor.setStyle("emacs-mode");
|
||||
};
|
||||
|
||||
exports.handler.detach = function(editor) {
|
||||
delete editor.renderer.screenToTextCoordinates;
|
||||
editor.unsetStyle("emacs-mode");
|
||||
};
|
||||
|
||||
|
||||
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 hashId = 0;
|
||||
c.split("-").forEach(function(c){
|
||||
hashId = hashId | keys[eMods[c]];
|
||||
});
|
||||
eMods[hashId] = c.toLowerCase() + "-";
|
||||
});
|
||||
|
||||
exports.handler.bindKey = function(key, command) {
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
var ckb = this.commmandKeyBinding;
|
||||
key.split("|").forEach(function(keyPart) {
|
||||
keyPart = keyPart.toLowerCase();
|
||||
ckb[keyPart] = command;
|
||||
keyPart = keyPart.split(" ")[0];
|
||||
if (!ckb[keyPart])
|
||||
ckb[keyPart] = "null";
|
||||
}, this);
|
||||
};
|
||||
|
||||
|
||||
exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {
|
||||
if (hashId == -1) {
|
||||
if (data.count) {
|
||||
var str = 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) {
|
||||
var count = parseInt(key[key.length - 1]);
|
||||
if (count) {
|
||||
data.count = count;
|
||||
return {command: "null"};
|
||||
}
|
||||
}
|
||||
data.universalArgument = false;
|
||||
|
||||
if (modifier)
|
||||
key = modifier + key;
|
||||
|
||||
if (data.keyChain)
|
||||
key = data.keyChain += " " + key;
|
||||
|
||||
var command = this.commmandKeyBinding[key];
|
||||
data.keyChain = command == "null" ? key : "";
|
||||
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
if (command == "null")
|
||||
return {command: "null"};
|
||||
|
||||
if (command == "universalArgument") {
|
||||
data.universalArgument = true;
|
||||
return {command: "null"};
|
||||
}
|
||||
|
||||
if (typeof command != "string") {
|
||||
var args = command.args;
|
||||
command = command.command;
|
||||
}
|
||||
|
||||
if (typeof command == "string") {
|
||||
command = this.commands[command] || data.editor.commands.commands[command];
|
||||
}
|
||||
|
||||
if (!command.readonly && !command.isYank)
|
||||
data.lastCommand = null;
|
||||
|
||||
if (data.count) {
|
||||
var count = data.count;
|
||||
data.count = 0;
|
||||
return {
|
||||
args: args,
|
||||
command: {
|
||||
exec: function(editor, args) {
|
||||
for (var i = 0; i < count; i++)
|
||||
command.exec(editor, args);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {command: command, args: args};
|
||||
};
|
||||
|
||||
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",
|
||||
|
||||
// selection
|
||||
"S-Up|S-C-p" : "selectup",
|
||||
"S-Down|S-C-n" : "selectdown",
|
||||
"S-Left|S-C-b" : "selectleft",
|
||||
"S-Right|S-C-f" : "selectright",
|
||||
"S-C-Left|S-M-b" : "selectwordleft",
|
||||
"S-C-Right|S-M-f" : "selectwordright",
|
||||
"S-Home|S-C-a" : "selecttolinestart",
|
||||
"S-End|S-C-e" : "selecttolineend",
|
||||
"S-C-Home" : "selecttostart",
|
||||
"S-C-End" : "selecttoend",
|
||||
|
||||
"C-l|M-s" : "centerselection",
|
||||
"M-g": "gotoline",
|
||||
"C-x C-p": "selectall",
|
||||
|
||||
// todo fix these
|
||||
"C-Down": "gotopagedown",
|
||||
"C-Up": "gotopageup",
|
||||
"PageDown|C-v": "gotopagedown",
|
||||
"PageUp|M-v": "gotopageup",
|
||||
"S-C-Down": "selectpagedown",
|
||||
"S-C-Up": "selectpageup",
|
||||
"C-s": "findnext",
|
||||
"C-r": "findprevious",
|
||||
"M-C-s": "findnext",
|
||||
"M-C-r": "findprevious",
|
||||
"S-M-5": "replace",
|
||||
|
||||
// basic editing
|
||||
"Backspace": "backspace",
|
||||
"Delete|C-d": "del",
|
||||
"Return|C-m": {command: "insertstring", args: "\n"}, // "newline"
|
||||
"C-o": "splitline",
|
||||
|
||||
"M-d|C-Delete": {command: "killWord", args: "right"},
|
||||
"C-Backspace|M-Backspace|M-Delete": {command: "killWord", args: "left"},
|
||||
"C-k": "killLine",
|
||||
|
||||
"C-y|S-Delete": "yank",
|
||||
"M-y": "yankRotate",
|
||||
"C-g": "keyboardQuit",
|
||||
|
||||
"C-w": "killRegion",
|
||||
"M-w": "killRingSave",
|
||||
|
||||
"C-Space": "setMark",
|
||||
"C-x C-x": "exchangePointAndMark",
|
||||
|
||||
"C-t": "transposeletters",
|
||||
|
||||
"M-u": "touppercase",
|
||||
"M-l": "tolowercase",
|
||||
"M-/": "autocomplete",
|
||||
"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"
|
||||
|
||||
// todo
|
||||
// "M-x" "C-x C-t" "M-t" "M-c" "F11" "C-M- "M-q"
|
||||
};
|
||||
|
||||
|
||||
exports.handler.bindKeys(exports.emacsKeys);
|
||||
|
||||
exports.handler.addCommands({
|
||||
selectRectangularRegion: function(editor) {
|
||||
editor.multiSelect.toggleBlockSelection();
|
||||
},
|
||||
setMark: function() {
|
||||
},
|
||||
exchangePointAndMark: {
|
||||
exec: function(editor) {
|
||||
var range = editor.selection.getRange();
|
||||
editor.selection.setSelectionRange(range, !editor.selection.isBackwards());
|
||||
},
|
||||
readonly: true,
|
||||
multiselectAction: "forEach"
|
||||
},
|
||||
killWord: {
|
||||
exec: function(editor, dir) {
|
||||
editor.clearSelection();
|
||||
if (dir == "left")
|
||||
editor.selection.selectWordLeft();
|
||||
else
|
||||
editor.selection.selectWordRight();
|
||||
|
||||
var range = editor.getSelectionRange();
|
||||
var text = editor.session.getTextRange(range);
|
||||
exports.killRing.add(text);
|
||||
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
},
|
||||
multiselectAction: "forEach"
|
||||
},
|
||||
killLine: function(editor) {
|
||||
editor.selection.selectLine();
|
||||
var range = editor.getSelectionRange();
|
||||
var text = editor.session.getTextRange(range);
|
||||
exports.killRing.add(text);
|
||||
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
},
|
||||
yank: function(editor) {
|
||||
editor.onPaste(exports.killRing.get());
|
||||
editor.keyBinding.$data.lastCommand = "yank";
|
||||
},
|
||||
yankRotate: function(editor) {
|
||||
if (editor.keyBinding.$data.lastCommand != "yank")
|
||||
return;
|
||||
|
||||
editor.undo();
|
||||
editor.onPaste(exports.killRing.rotate());
|
||||
editor.keyBinding.$data.lastCommand = "yank";
|
||||
},
|
||||
killRegion: function(editor) {
|
||||
exports.killRing.add(editor.getCopyText());
|
||||
editor.cut();
|
||||
},
|
||||
killRingSave: function(editor) {
|
||||
exports.killRing.add(editor.getCopyText());
|
||||
}
|
||||
});
|
||||
|
||||
var commands = exports.handler.commands;
|
||||
commands.yank.isYank = true;
|
||||
commands.yankRotate.isYank = true;
|
||||
|
||||
exports.killRing = {
|
||||
$data: [],
|
||||
add: function(str) {
|
||||
str && this.$data.push(str);
|
||||
if (this.$data.length > 30)
|
||||
this.$data.shift();
|
||||
},
|
||||
get: function() {
|
||||
return this.$data[this.$data.length - 1] || "";
|
||||
},
|
||||
pop: function() {
|
||||
if (this.$data.length > 1)
|
||||
this.$data.pop();
|
||||
return this.get();
|
||||
},
|
||||
rotate: function() {
|
||||
this.$data.unshift(this.$data.pop());
|
||||
return this.get();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
@@ -0,0 +1,170 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck (julian.viereck@gmail.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keyUtil = require("../lib/keys");
|
||||
|
||||
function HashHandler(config, platform) {
|
||||
this.platform = platform;
|
||||
this.commands = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
this.addCommands(config);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.addCommand = function(command) {
|
||||
if (this.commands[command.name])
|
||||
this.removeCommand(command);
|
||||
|
||||
this.commands[command.name] = command;
|
||||
|
||||
if (command.bindKey)
|
||||
this._buildKeyHash(command);
|
||||
};
|
||||
|
||||
this.removeCommand = function(command) {
|
||||
var name = (typeof command === 'string' ? command : command.name);
|
||||
command = this.commands[name];
|
||||
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];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.bindKey = function(key, command) {
|
||||
if(!key)
|
||||
return;
|
||||
if (typeof command == "function") {
|
||||
this.addCommand({exec: command, bindKey: key, name: key});
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
this.addCommands = function(commands) {
|
||||
commands && Object.keys(commands).forEach(function(name) {
|
||||
var command = commands[name];
|
||||
if (typeof command === "string")
|
||||
return this.bindKey(command, name);
|
||||
|
||||
if (typeof command === "function")
|
||||
command = { exec: command };
|
||||
|
||||
if (!command.name)
|
||||
command.name = name;
|
||||
|
||||
this.addCommand(command);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.removeCommands = function(commands) {
|
||||
Object.keys(commands).forEach(function(name) {
|
||||
this.removeCommand(commands[name]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.bindKeys = function(keyList) {
|
||||
Object.keys(keyList).forEach(function(key) {
|
||||
this.bindKey(key, keyList[key]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
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.parseKeys = function(keys) {
|
||||
var key;
|
||||
var hashId = 0;
|
||||
var parts = keys.toLowerCase().trim().split(/\s*\-\s*/);
|
||||
|
||||
for (var i = 0, l = parts.length; i < l; i++) {
|
||||
if (keyUtil.KEY_MODS[parts[i]])
|
||||
hashId = hashId | keyUtil.KEY_MODS[parts[i]];
|
||||
else
|
||||
key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
|
||||
}
|
||||
|
||||
if (parts[0] == "text" && parts.length == 2) {
|
||||
hashId = -1;
|
||||
key = parts[1];
|
||||
}
|
||||
|
||||
return {
|
||||
key: key,
|
||||
hashId: hashId
|
||||
};
|
||||
};
|
||||
|
||||
this.findKeyCommand = function findKeyCommand(hashId, keyString) {
|
||||
var ckbr = this.commmandKeyBinding;
|
||||
return ckbr[hashId] && ckbr[hashId][keyString.toLowerCase()];
|
||||
};
|
||||
|
||||
this.handleKeyboard = function(data, hashId, keyString, keyCode) {
|
||||
return {
|
||||
command: this.findKeyCommand(hashId, keyString)
|
||||
};
|
||||
};
|
||||
|
||||
}).call(HashHandler.prototype)
|
||||
|
||||
exports.HashHandler = HashHandler;
|
||||
});
|
||||
@@ -0,0 +1,143 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
* Harutyun Amirjanyan <amirjanyan@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keyUtil = require("../lib/keys");
|
||||
var event = require("../lib/event");
|
||||
|
||||
var KeyBinding = function(editor) {
|
||||
this.$editor = editor;
|
||||
this.$data = { };
|
||||
this.$handlers = [];
|
||||
this.setDefaultHandler(editor.commands);
|
||||
};
|
||||
|
||||
(function() {
|
||||
this.setDefaultHandler = function(kb) {
|
||||
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)
|
||||
return;
|
||||
|
||||
while (this.$handlers[1])
|
||||
this.removeKeyboardHandler(this.$handlers[1]);
|
||||
|
||||
this.addKeyboardHandler(kb, 1);
|
||||
};
|
||||
|
||||
this.addKeyboardHandler = function(kb, pos) {
|
||||
if (!kb)
|
||||
return;
|
||||
var i = this.$handlers.indexOf(kb);
|
||||
if (i != -1)
|
||||
this.$handlers.splice(i, 1);
|
||||
|
||||
if (pos == undefined)
|
||||
this.$handlers.push(kb);
|
||||
else
|
||||
this.$handlers.splice(pos, 0, kb);
|
||||
|
||||
if (i == -1 && kb.attach)
|
||||
kb.attach(this.$editor);
|
||||
};
|
||||
|
||||
this.removeKeyboardHandler = function(kb) {
|
||||
var i = this.$handlers.indexOf(kb);
|
||||
if (i == -1)
|
||||
return false;
|
||||
this.$handlers.splice(i, 1);
|
||||
kb.detach && kb.detach(this.$editor);
|
||||
return true;
|
||||
};
|
||||
|
||||
this.getKeyboardHandler = function() {
|
||||
return this.$handlers[this.$handlers.length - 1];
|
||||
};
|
||||
|
||||
this.$callKeyboardHandlers = function (hashId, keyString, keyCode, e) {
|
||||
var toExecute;
|
||||
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;
|
||||
|
||||
// allow keyboardHandler to consume keys
|
||||
if (toExecute.command != "null")
|
||||
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)
|
||||
event.stopEvent(e);
|
||||
|
||||
return success;
|
||||
};
|
||||
|
||||
this.onCommandKey = function(e, hashId, keyCode) {
|
||||
var keyString = keyUtil.keyCodeToString(keyCode);
|
||||
this.$callKeyboardHandlers(hashId, keyString, keyCode, e);
|
||||
};
|
||||
|
||||
this.onTextInput = function(text) {
|
||||
var success = this.$callKeyboardHandlers(-1, text);
|
||||
if (!success)
|
||||
this.$editor.commands.exec("insertstring", this.$editor, text);
|
||||
};
|
||||
|
||||
}).call(KeyBinding.prototype);
|
||||
|
||||
exports.KeyBinding = KeyBinding;
|
||||
});
|
||||
@@ -0,0 +1,257 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck (julian.viereck@gmail.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
// If you're developing a new keymapping and want to get an idea what's going
|
||||
// on, then enable debugging.
|
||||
var DEBUG = false;
|
||||
|
||||
function StateHandler(keymapping) {
|
||||
this.keymapping = this.$buildKeymappingRegex(keymapping);
|
||||
}
|
||||
|
||||
StateHandler.prototype = {
|
||||
/*
|
||||
* Build the RegExp from the keymapping as RegExp can't stored directly
|
||||
* in the metadata JSON and as the RegExp used to match the keys/buffer
|
||||
* need to be adapted.
|
||||
*/
|
||||
$buildKeymappingRegex: function(keymapping) {
|
||||
for (var state in keymapping) {
|
||||
this.$buildBindingsRegex(keymapping[state]);
|
||||
}
|
||||
return keymapping;
|
||||
},
|
||||
|
||||
$buildBindingsRegex: function(bindings) {
|
||||
// Escape a given Regex string.
|
||||
bindings.forEach(function(binding) {
|
||||
if (binding.key) {
|
||||
binding.key = new RegExp('^' + binding.key + '$');
|
||||
} else if (Array.isArray(binding.regex)) {
|
||||
if (!('key' in binding))
|
||||
binding.key = new RegExp('^' + binding.regex[1] + '$');
|
||||
binding.regex = new RegExp(binding.regex.join('') + '$');
|
||||
} else if (binding.regex) {
|
||||
binding.regex = new RegExp(binding.regex + '$');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
$composeBuffer: function(data, hashId, key, e) {
|
||||
// Initialize the data object.
|
||||
if (data.state == null || data.buffer == null) {
|
||||
data.state = "start";
|
||||
data.buffer = "";
|
||||
}
|
||||
|
||||
var keyArray = [];
|
||||
if (hashId & 1) keyArray.push("ctrl");
|
||||
if (hashId & 8) keyArray.push("command");
|
||||
if (hashId & 2) keyArray.push("option");
|
||||
if (hashId & 4) keyArray.push("shift");
|
||||
if (key) keyArray.push(key);
|
||||
|
||||
var symbolicName = keyArray.join("-");
|
||||
var bufferToUse = data.buffer + symbolicName;
|
||||
|
||||
// Don't add the symbolic name to the key buffer if the alt_ key is
|
||||
// part of the symbolic name. If it starts with alt_, this means
|
||||
// that the user hit an alt keycombo and there will be a single,
|
||||
// new character detected after this event, which then will be
|
||||
// added to the buffer (e.g. alt_j will result in ∆).
|
||||
//
|
||||
// We test for 2 and not for & 2 as we only want to exclude the case where
|
||||
// the option key is pressed alone.
|
||||
if (hashId != 2) {
|
||||
data.buffer = bufferToUse;
|
||||
}
|
||||
|
||||
var bufferObj = {
|
||||
bufferToUse: bufferToUse,
|
||||
symbolicName: symbolicName
|
||||
};
|
||||
|
||||
if (e) {
|
||||
bufferObj.keyIdentifier = e.keyIdentifier
|
||||
}
|
||||
|
||||
return bufferObj;
|
||||
},
|
||||
|
||||
$find: function(data, buffer, symbolicName, hashId, key, keyIdentifier) {
|
||||
// Holds the command to execute and the args if a command matched.
|
||||
var result = {};
|
||||
|
||||
// Loop over all the bindings of the keymap until a match is found.
|
||||
this.keymapping[data.state].some(function(binding) {
|
||||
var match;
|
||||
|
||||
// Check if the key matches.
|
||||
if (binding.key && !binding.key.test(symbolicName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the regex matches.
|
||||
if (binding.regex && !(match = binding.regex.exec(buffer))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the match function matches.
|
||||
if (binding.match && !binding.match(buffer, hashId, key, symbolicName, keyIdentifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for disallowed matches.
|
||||
if (binding.disallowMatches) {
|
||||
for (var i = 0; i < binding.disallowMatches.length; i++) {
|
||||
if (!!match[binding.disallowMatches[i]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a command to execute, then figure out the
|
||||
// command and the arguments.
|
||||
if (binding.exec) {
|
||||
result.command = binding.exec;
|
||||
|
||||
// Build the arguments.
|
||||
if (binding.params) {
|
||||
var value;
|
||||
result.args = {};
|
||||
binding.params.forEach(function(param) {
|
||||
if (param.match != null && match != null) {
|
||||
value = match[param.match] || param.defaultValue;
|
||||
} else {
|
||||
value = param.defaultValue;
|
||||
}
|
||||
|
||||
if (param.type === 'number') {
|
||||
value = parseInt(value);
|
||||
}
|
||||
|
||||
result.args[param.name] = value;
|
||||
});
|
||||
}
|
||||
data.buffer = "";
|
||||
}
|
||||
|
||||
// Handle the 'then' property.
|
||||
if (binding.then) {
|
||||
data.state = binding.then;
|
||||
data.buffer = "";
|
||||
}
|
||||
|
||||
// If no command is set, then execute the "null" fake command.
|
||||
if (result.command == null) {
|
||||
result.command = "null";
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
console.log("KeyboardStateMapper#find", binding);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (result.command) {
|
||||
return result;
|
||||
} else {
|
||||
data.buffer = "";
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* This function is called by keyBinding.
|
||||
*/
|
||||
handleKeyboard: function(data, hashId, key, keyCode, e) {
|
||||
if (hashId == -1)
|
||||
hashId = 0
|
||||
// If we pressed any command key but no other key, then ignore the input.
|
||||
// Otherwise "shift-" is added to the buffer, and later on "shift-g"
|
||||
// which results in "shift-shift-g" which doesn't make sense.
|
||||
if (hashId != 0 && (key == "" || key == String.fromCharCode(0))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Compute the current value of the keyboard input buffer.
|
||||
var r = this.$composeBuffer(data, hashId, key, e);
|
||||
var buffer = r.bufferToUse;
|
||||
var symbolicName = r.symbolicName;
|
||||
var keyId = r.keyIdentifier;
|
||||
|
||||
r = this.$find(data, buffer, symbolicName, hashId, key, keyId);
|
||||
if (DEBUG) {
|
||||
console.log("KeyboardStateMapper#match", buffer, symbolicName, r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
* a normal character on the keyboard and no shortcut.
|
||||
*/
|
||||
exports.matchCharacterOnly = function(buffer, hashId, key, symbolicName) {
|
||||
// If no command keys are pressed, then catch the input.
|
||||
if (hashId == 0) {
|
||||
return true;
|
||||
}
|
||||
// If only the shift key is pressed and a character key, then
|
||||
// catch that input as well.
|
||||
else if ((hashId == 4) && key.length == 1) {
|
||||
return true;
|
||||
}
|
||||
// Otherwise, we let the input got through.
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
exports.StateHandler = StateHandler;
|
||||
});
|
||||
@@ -0,0 +1,315 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Mihai Sucan <mihai DOT sucan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var event = require("../lib/event");
|
||||
var useragent = require("../lib/useragent");
|
||||
var dom = require("../lib/dom");
|
||||
|
||||
var TextInput = function(parentNode, host) {
|
||||
var text = dom.createElement("textarea");
|
||||
/*/ 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.setAttribute("wrap", "off");
|
||||
|
||||
text.style.top = "-2em";
|
||||
parentNode.insertBefore(text, parentNode.firstChild);
|
||||
|
||||
var PLACEHOLDER = useragent.isIE ? "\x01" : "\x01";
|
||||
sendText();
|
||||
|
||||
var inCompostion = false;
|
||||
var copied = false;
|
||||
var pasted = false;
|
||||
var tempStyle = '';
|
||||
|
||||
function reset(full) {
|
||||
try {
|
||||
if (full) {
|
||||
text.value = PLACEHOLDER;
|
||||
text.selectionStart = 0;
|
||||
text.selectionEnd = 1;
|
||||
} else
|
||||
text.select();
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function sendText(valueToSend) {
|
||||
if (!copied) {
|
||||
var value = valueToSend || text.value;
|
||||
if (value) {
|
||||
if (value.length > 1) {
|
||||
if (value.charAt(0) == PLACEHOLDER)
|
||||
value = value.substr(1);
|
||||
else if (value.charAt(value.length - 1) == PLACEHOLDER)
|
||||
value = value.slice(0, -1);
|
||||
}
|
||||
|
||||
if (value && value != PLACEHOLDER) {
|
||||
if (pasted)
|
||||
host.onPaste(value);
|
||||
else
|
||||
host.onTextInput(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copied = false;
|
||||
pasted = false;
|
||||
|
||||
// Safari doesn't fire copy events if no text is selected
|
||||
reset(true);
|
||||
}
|
||||
|
||||
var onTextInput = function(e) {
|
||||
if (!inCompostion)
|
||||
sendText(e.data);
|
||||
setTimeout(function () {
|
||||
if (!inCompostion)
|
||||
reset(true);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var onPropertyChange = function(e) {
|
||||
setTimeout(function() {
|
||||
if (!inCompostion)
|
||||
sendText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
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 onCopy = function(e) {
|
||||
copied = true;
|
||||
var copyText = host.getCopyText();
|
||||
if(copyText)
|
||||
text.value = copyText;
|
||||
else
|
||||
e.preventDefault();
|
||||
reset();
|
||||
setTimeout(function () {
|
||||
sendText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var onCut = function(e) {
|
||||
copied = true;
|
||||
var copyText = host.getCopyText();
|
||||
if(copyText) {
|
||||
text.value = copyText;
|
||||
host.onCut();
|
||||
} else
|
||||
e.preventDefault();
|
||||
reset();
|
||||
setTimeout(function () {
|
||||
sendText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
|
||||
event.addListener(text, "input", useragent.isIE ? onPropertyChange : onTextInput);
|
||||
|
||||
event.addListener(text, "paste", function(e) {
|
||||
// Mark that the next input text comes from past.
|
||||
pasted = true;
|
||||
// Some browsers support the event.clipboardData API. Use this to get
|
||||
// the pasted content which increases speed if pasting a lot of lines.
|
||||
if (e.clipboardData && e.clipboardData.getData) {
|
||||
sendText(e.clipboardData.getData("text/plain"));
|
||||
e.preventDefault();
|
||||
}
|
||||
else {
|
||||
// If a browser doesn't support any of the things above, use the regular
|
||||
// method to detect the pasted input.
|
||||
onPropertyChange();
|
||||
}
|
||||
});
|
||||
|
||||
if ("onbeforecopy" in text && typeof clipboardData !== "undefined") {
|
||||
event.addListener(text, "beforecopy", function(e) {
|
||||
if (tempStyle)
|
||||
return; // without this text is copied when contextmenu is shown
|
||||
var copyText = host.getCopyText();
|
||||
if (copyText)
|
||||
clipboardData.setData("Text", copyText);
|
||||
else
|
||||
e.preventDefault();
|
||||
});
|
||||
event.addListener(parentNode, "keydown", function(e) {
|
||||
if (e.ctrlKey && e.keyCode == 88) {
|
||||
var copyText = host.getCopyText();
|
||||
if (copyText) {
|
||||
clipboardData.setData("Text", copyText);
|
||||
host.onCut();
|
||||
}
|
||||
event.preventDefault(e);
|
||||
}
|
||||
});
|
||||
event.addListener(text, "cut", onCut); // for ie9 context menu
|
||||
}
|
||||
else if (useragent.isOpera) {
|
||||
event.addListener(parentNode, "keydown", function(e) {
|
||||
if ((useragent.isMac && !e.metaKey) || !e.ctrlKey)
|
||||
return;
|
||||
|
||||
if ((e.keyCode == 88 || e.keyCode == 67)) {
|
||||
var copyText = host.getCopyText();
|
||||
if (copyText) {
|
||||
text.value = copyText;
|
||||
text.select();
|
||||
if (e.keyCode == 88)
|
||||
host.onCut();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
event.addListener(text, "copy", onCopy);
|
||||
event.addListener(text, "cut", onCut);
|
||||
}
|
||||
|
||||
event.addListener(text, "compositionstart", onCompositionStart);
|
||||
if (useragent.isGecko) {
|
||||
event.addListener(text, "text", onCompositionUpdate);
|
||||
}
|
||||
if (useragent.isWebKit) {
|
||||
event.addListener(text, "keyup", onCompositionUpdate);
|
||||
}
|
||||
event.addListener(text, "compositionend", onCompositionEnd);
|
||||
|
||||
event.addListener(text, "blur", function() {
|
||||
host.onBlur();
|
||||
});
|
||||
|
||||
event.addListener(text, "focus", function() {
|
||||
host.onFocus();
|
||||
reset();
|
||||
});
|
||||
|
||||
this.focus = function() {
|
||||
reset();
|
||||
text.focus();
|
||||
};
|
||||
|
||||
this.blur = function() {
|
||||
text.blur();
|
||||
};
|
||||
|
||||
function isFocused() {
|
||||
return document.activeElement === text;
|
||||
}
|
||||
this.isFocused = isFocused;
|
||||
|
||||
this.getElement = function() {
|
||||
return text;
|
||||
};
|
||||
|
||||
this.onContextMenu = function(e) {
|
||||
if (!tempStyle)
|
||||
tempStyle = text.style.cssText;
|
||||
|
||||
text.style.cssText =
|
||||
"position:fixed; z-index:100000;" + //"background:rgba(250, 0, 0, 0.3); opacity:1;" +
|
||||
"left:" + (e.clientX - 2) + "px; top:" + (e.clientY - 2) + "px;";
|
||||
|
||||
if (host.selection.isEmpty())
|
||||
text.value = "";
|
||||
|
||||
if (e.type != "mousedown")
|
||||
return;
|
||||
|
||||
if (host.renderer.$keepTextAreaAtCursor)
|
||||
host.renderer.$keepTextAreaAtCursor = null;
|
||||
|
||||
// on windows context menu is opened after mouseup
|
||||
if (useragent.isGecko && useragent.isWin)
|
||||
event.capture(host.container, function(e) {
|
||||
text.style.left = e.clientX - 2 + "px";
|
||||
text.style.top = e.clientY - 2 + "px";
|
||||
}, onContextMenuClose);
|
||||
};
|
||||
|
||||
function onContextMenuClose() {
|
||||
setTimeout(function () {
|
||||
if (tempStyle) {
|
||||
text.style.cssText = tempStyle;
|
||||
tempStyle = '';
|
||||
}
|
||||
sendText();
|
||||
if (host.renderer.$keepTextAreaAtCursor == null) {
|
||||
host.renderer.$keepTextAreaAtCursor = true;
|
||||
host.renderer.$moveTextAreaToCursor();
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
this.onContextMenuClose = onContextMenuClose;
|
||||
|
||||
// firefox fires contextmenu event after opening it
|
||||
if (!useragent.isGecko)
|
||||
event.addListener(text, "contextmenu", function(e) {
|
||||
host.textInput.onContextMenu(e);
|
||||
onContextMenuClose()
|
||||
});
|
||||
};
|
||||
|
||||
exports.TextInput = TextInput;
|
||||
});
|
||||
@@ -0,0 +1,122 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keyUtil = require("../lib/keys");
|
||||
var cmds = require("./vim/commands");
|
||||
var coreCommands = cmds.coreCommands;
|
||||
var util = require("./vim/maps/util");
|
||||
|
||||
var startCommands = {
|
||||
"i": {
|
||||
command: coreCommands.start
|
||||
},
|
||||
"I": {
|
||||
command: coreCommands.startBeginning
|
||||
},
|
||||
"a": {
|
||||
command: coreCommands.append
|
||||
},
|
||||
"A": {
|
||||
command: coreCommands.appendEnd
|
||||
},
|
||||
"ctrl-f": {
|
||||
command: "gotopagedown"
|
||||
},
|
||||
"ctrl-b": {
|
||||
command: "gotopageup"
|
||||
},
|
||||
};
|
||||
|
||||
exports.handler = {
|
||||
handleKeyboard: function(data, hashId, key, keyCode, e) {
|
||||
// ignore command keys (shift, ctrl etc.)
|
||||
if (hashId != 0 && (key == "" || key == "\x00"))
|
||||
return null;
|
||||
|
||||
if (hashId == 1)
|
||||
key = "ctrl-" + key;
|
||||
|
||||
if (data.state == "start") {
|
||||
if (hashId == -1 || hashId == 1) {
|
||||
if (cmds.inputBuffer.idle && startCommands[key])
|
||||
return startCommands[key];
|
||||
|
||||
return { command: {
|
||||
exec: function(editor) {cmds.inputBuffer.push(editor, key);}
|
||||
} };
|
||||
} // wait for input
|
||||
else if (key.length == 1 && (hashId == 0 || hashId == 4)) { //no modifier || shift
|
||||
return {command: "null", passEvent: true};
|
||||
} else if (key == "esc") {
|
||||
return {command: coreCommands.stop};
|
||||
}
|
||||
} else {
|
||||
if (key == "esc" || key == "ctrl-[") {
|
||||
data.state = "start";
|
||||
return {command: coreCommands.stop};
|
||||
} else if (key == "ctrl-w") {
|
||||
return {command: "removewordleft"};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
attach: function(editor) {
|
||||
editor.on("click", exports.onCursorMove);
|
||||
if (util.currentMode !== "insert")
|
||||
cmds.coreCommands.stop.exec(editor);
|
||||
},
|
||||
|
||||
detach: function(editor) {
|
||||
editor.removeListener("click", exports.onCursorMove);
|
||||
util.noMode(editor);
|
||||
util.currentMode = "normal";
|
||||
},
|
||||
|
||||
actions: cmds.actions
|
||||
};
|
||||
|
||||
|
||||
exports.onCursorMove = function(e) {
|
||||
cmds.onCursorMove(e.editor, e);
|
||||
exports.onCursorMove.scheduled = false;
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,556 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** 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.alignCursor(null, 0.5);
|
||||
break;
|
||||
case "t":
|
||||
editor.alignCursor(null, 0);
|
||||
break;
|
||||
case "b":
|
||||
editor.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: "",
|
||||
|
||||
// Types
|
||||
operator: null,
|
||||
motion: null,
|
||||
|
||||
lastInsertCommands: [],
|
||||
|
||||
push: function(editor, char, keyId) {
|
||||
this.idle = false;
|
||||
var wObj = this.waitingForParam;
|
||||
if (wObj) {
|
||||
this.exec(editor, wObj, char);
|
||||
}
|
||||
// If input is a number (that doesn't start with 0)
|
||||
else if (!(char === "0" && !this.currentCount.length) &&
|
||||
(char.match(/^\d+$/) && this.isAccepting(NUMBER))) {
|
||||
// Assuming that char is always of type String, and not Number
|
||||
this.currentCount += char;
|
||||
this.currentCmd = NUMBER;
|
||||
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
|
||||
}
|
||||
else if (!this.operator && this.isAccepting(OPERATOR) && operators[char]) {
|
||||
this.operator = {
|
||||
char: char,
|
||||
count: this.getCount()
|
||||
};
|
||||
this.currentCmd = OPERATOR;
|
||||
this.accepting = [NUMBER, MOTION, ACTION];
|
||||
this.exec(editor, { operator: this.operator });
|
||||
}
|
||||
else if (motions[char] && this.isAccepting(MOTION)) {
|
||||
this.currentCmd = MOTION;
|
||||
|
||||
var ctx = {
|
||||
operator: this.operator,
|
||||
motion: {
|
||||
char: char,
|
||||
count: this.getCount()
|
||||
}
|
||||
};
|
||||
|
||||
if (motions[char].param)
|
||||
this.waitForParam(ctx);
|
||||
else
|
||||
this.exec(editor, ctx);
|
||||
}
|
||||
else if (alias[char] && this.isAccepting(MOTION)) {
|
||||
alias[char].operator.count = this.getCount();
|
||||
this.exec(editor, alias[char]);
|
||||
}
|
||||
else if (actions[char] && this.isAccepting(ACTION)) {
|
||||
var actionObj = {
|
||||
action: {
|
||||
fn: actions[char].fn,
|
||||
count: this.getCount()
|
||||
}
|
||||
};
|
||||
|
||||
if (actions[char].param) {
|
||||
this.waitForParam(actionObj);
|
||||
}
|
||||
else {
|
||||
this.exec(editor, actionObj);
|
||||
}
|
||||
|
||||
if (actions[char].acceptsMotion)
|
||||
this.idle = false;
|
||||
}
|
||||
else if (this.operator) {
|
||||
this.exec(editor, { operator: this.operator }, char);
|
||||
}
|
||||
else {
|
||||
this.reset();
|
||||
}
|
||||
},
|
||||
|
||||
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.char].selFn) {
|
||||
operators[o.char].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 char 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.char].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.char];
|
||||
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.char].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.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;
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict"
|
||||
|
||||
define(function(require, exports, module) {
|
||||
module.exports = {
|
||||
"x": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "l",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"X": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "h",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"D": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "$",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"C": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "$",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"s": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "l",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"S": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
param: "c"
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,611 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict"
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
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(getRange, type){
|
||||
if (type == 'extend')
|
||||
var extend = true;
|
||||
else
|
||||
var reverse = type;
|
||||
|
||||
this.nav = function(editor) {
|
||||
var r = getRange(editor);
|
||||
if (!r)
|
||||
return;
|
||||
if (!r.end)
|
||||
var a = r;
|
||||
else if (reverse)
|
||||
var a = r.start;
|
||||
else
|
||||
var a = r.end;
|
||||
|
||||
editor.clearSelection();
|
||||
editor.moveCursorTo(a.row, a.column);
|
||||
}
|
||||
this.sel = function(editor){
|
||||
var r = getRange(editor);
|
||||
if (!r)
|
||||
return;
|
||||
if (extend)
|
||||
return editor.selection.setSelectionRange(r);
|
||||
|
||||
if (!r.end)
|
||||
var a = r;
|
||||
else if (reverse)
|
||||
var a = r.start;
|
||||
else
|
||||
var a = r.end;
|
||||
|
||||
editor.selection.selectTo(a.row, a.column);
|
||||
}
|
||||
}
|
||||
|
||||
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("ace/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("ace/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};
|
||||
}, true),
|
||||
"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();
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column + 1);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column + 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
"F": {
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
count = parseInt(count, 10) || 1;
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, cursor.column - column - 1);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, cursor.column - column - 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": {
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column);
|
||||
}
|
||||
}
|
||||
},
|
||||
"T": {
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, -column + cursor.column);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, -column + cursor.column);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"^": {
|
||||
nav: function(editor) {
|
||||
editor.navigateLineStart();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectLineStart();
|
||||
}
|
||||
},
|
||||
"$": {
|
||||
nav: function(editor) {
|
||||
editor.navigateLineEnd();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectLineEnd();
|
||||
}
|
||||
},
|
||||
"0": {
|
||||
nav: function(editor) {
|
||||
var ed = editor;
|
||||
ed.navigateTo(ed.selection.selectionLead.row, 0);
|
||||
},
|
||||
sel: function(editor) {
|
||||
var ed = editor;
|
||||
ed.selectTo(ed.selection.selectionLead.row, 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;
|
||||
}),
|
||||
"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"];
|
||||
|
||||
});
|
||||
@@ -0,0 +1,193 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** 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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,134 @@
|
||||
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.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("vimMode", "insert");
|
||||
// Record any movements, insertions in insert mode
|
||||
if(!editor.commands.recording)
|
||||
editor.commands.toggleRecording();
|
||||
}
|
||||
},
|
||||
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("changeVimMode", "normal");
|
||||
// Save recorded keystrokes
|
||||
if (editor.commands.recording) {
|
||||
editor.commands.toggleRecording();
|
||||
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("changeVimMode", "visual");
|
||||
if (lineMode) {
|
||||
this.onVisualLineMode = true;
|
||||
} else {
|
||||
this.onVisualMode = true;
|
||||
this.onVisualLineMode = false;
|
||||
}
|
||||
},
|
||||
getRightNthChar: function(editor, cursor, char, n) {
|
||||
var line = editor.getSession().getLine(cursor.row);
|
||||
var matches = line.substr(cursor.column + 1).split(char);
|
||||
|
||||
return n < matches.length ? matches.slice(0, n).join(char).length : null;
|
||||
},
|
||||
getLeftNthChar: function(editor, cursor, char, n) {
|
||||
var line = editor.getSession().getLine(cursor.row);
|
||||
var matches = line.substr(0, cursor.column).split(char);
|
||||
|
||||
return n < matches.length ? matches.slice(-1 * n).join(char).length : null;
|
||||
},
|
||||
toRealChar: function(char) {
|
||||
if (char.length === 1)
|
||||
return char;
|
||||
|
||||
if (/^shift-./.test(char))
|
||||
return char[char.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);
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
"never use strict";
|
||||
|
||||
module.exports = {
|
||||
_default: {
|
||||
text: "",
|
||||
isLine: false
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,202 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
|
||||
var Cursor = function(parentEl) {
|
||||
this.element = dom.createElement("div");
|
||||
this.element.className = "ace_layer ace_cursor-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
|
||||
this.isVisible = false;
|
||||
|
||||
this.cursors = [];
|
||||
this.cursor = this.addCursor();
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.$padding = 0;
|
||||
this.setPadding = function(padding) {
|
||||
this.$padding = padding;
|
||||
};
|
||||
|
||||
this.setSession = function(session) {
|
||||
this.session = session;
|
||||
};
|
||||
|
||||
this.addCursor = function() {
|
||||
var el = dom.createElement("div");
|
||||
var className = "ace_cursor";
|
||||
if (!this.isVisible)
|
||||
className += " ace_hidden";
|
||||
if (this.overwrite)
|
||||
className += " ace_overwrite";
|
||||
|
||||
el.className = className;
|
||||
this.element.appendChild(el);
|
||||
this.cursors.push(el);
|
||||
return el;
|
||||
};
|
||||
|
||||
this.removeCursor = function() {
|
||||
if (this.cursors.length > 1) {
|
||||
var el = this.cursors.pop();
|
||||
el.parentNode.removeChild(el);
|
||||
return el;
|
||||
}
|
||||
};
|
||||
|
||||
this.hideCursor = function() {
|
||||
this.isVisible = false;
|
||||
for (var i = this.cursors.length; i--; )
|
||||
dom.addCssClass(this.cursors[i], "ace_hidden");
|
||||
clearInterval(this.blinkId);
|
||||
};
|
||||
|
||||
this.showCursor = function() {
|
||||
this.isVisible = true;
|
||||
for (var i = this.cursors.length; i--; )
|
||||
dom.removeCssClass(this.cursors[i], "ace_hidden");
|
||||
|
||||
this.element.style.visibility = "";
|
||||
this.restartTimer();
|
||||
};
|
||||
|
||||
this.restartTimer = function() {
|
||||
clearInterval(this.blinkId);
|
||||
if (!this.isVisible)
|
||||
return;
|
||||
|
||||
var element = this.cursors.length == 1 ? this.cursor : this.element;
|
||||
this.blinkId = setInterval(function() {
|
||||
element.style.visibility = "hidden";
|
||||
setTimeout(function() {
|
||||
element.style.visibility = "";
|
||||
}, 400);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
this.getPixelPosition = function(position, onScreen) {
|
||||
if (!this.config || !this.session) {
|
||||
return {
|
||||
left : 0,
|
||||
top : 0
|
||||
};
|
||||
}
|
||||
|
||||
if (!position)
|
||||
position = this.session.selection.getCursor();
|
||||
var pos = this.session.documentToScreenPosition(position);
|
||||
var cursorLeft = Math.round(this.$padding +
|
||||
pos.column * this.config.characterWidth);
|
||||
var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) *
|
||||
this.config.lineHeight;
|
||||
|
||||
return {
|
||||
left : cursorLeft,
|
||||
top : cursorTop
|
||||
};
|
||||
};
|
||||
|
||||
this.update = function(config) {
|
||||
this.config = config;
|
||||
|
||||
if (this.session.selectionMarkerCount > 0) {
|
||||
var selections = this.session.$selectionMarkers;
|
||||
var i = 0, sel, cursorIndex = 0;
|
||||
|
||||
for (var i = selections.length; i--; ) {
|
||||
sel = selections[i];
|
||||
var pixelPos = this.getPixelPosition(sel.cursor, true);
|
||||
|
||||
var style = (this.cursors[cursorIndex++] || this.addCursor()).style;
|
||||
|
||||
style.left = pixelPos.left + "px";
|
||||
style.top = pixelPos.top + "px";
|
||||
style.width = config.characterWidth + "px";
|
||||
style.height = config.lineHeight + "px";
|
||||
}
|
||||
if (cursorIndex > 1)
|
||||
while (this.cursors.length > cursorIndex)
|
||||
this.removeCursor();
|
||||
} else {
|
||||
var pixelPos = this.getPixelPosition(null, true);
|
||||
var style = this.cursor.style;
|
||||
style.left = pixelPos.left + "px";
|
||||
style.top = pixelPos.top + "px";
|
||||
style.width = config.characterWidth + "px";
|
||||
style.height = config.lineHeight + "px";
|
||||
|
||||
while (this.cursors.length > 1)
|
||||
this.removeCursor();
|
||||
}
|
||||
|
||||
var overwrite = this.session.getOverwrite();
|
||||
if (overwrite != this.overwrite)
|
||||
this.$setOverite(overwrite);
|
||||
|
||||
// cache for textarea and gutter highlight
|
||||
this.$pixelPos = pixelPos;
|
||||
|
||||
this.restartTimer();
|
||||
};
|
||||
|
||||
this.$setOverite = function(overwrite) {
|
||||
this.overwrite = overwrite;
|
||||
for (var i = this.cursors.length; i--; ) {
|
||||
if (overwrite)
|
||||
dom.addCssClass(this.cursors[i], "ace_overwrite");
|
||||
else
|
||||
dom.removeCssClass(this.cursors[i], "ace_overwrite");
|
||||
}
|
||||
};
|
||||
|
||||
this.destroy = function() {
|
||||
clearInterval(this.blinkId);
|
||||
}
|
||||
|
||||
}).call(Cursor.prototype);
|
||||
|
||||
exports.Cursor = Cursor;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,187 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
var oop = require("../lib/oop");
|
||||
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
||||
|
||||
var Gutter = function(parentEl) {
|
||||
this.element = dom.createElement("div");
|
||||
this.element.className = "ace_layer ace_gutter-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
this.setShowFoldWidgets(this.$showFoldWidgets);
|
||||
|
||||
this.gutterWidth = 0;
|
||||
|
||||
this.$breakpoints = [];
|
||||
this.$annotations = [];
|
||||
this.$decorations = [];
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.setSession = function(session) {
|
||||
this.session = session;
|
||||
};
|
||||
|
||||
this.addGutterDecoration = function(row, className){
|
||||
if (!this.$decorations[row])
|
||||
this.$decorations[row] = "";
|
||||
this.$decorations[row] += " " + className;
|
||||
};
|
||||
|
||||
this.removeGutterDecoration = function(row, className){
|
||||
this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, "");
|
||||
};
|
||||
|
||||
this.setAnnotations = function(annotations) {
|
||||
// iterate over sparse array
|
||||
this.$annotations = [];
|
||||
for (var row in annotations) if (annotations.hasOwnProperty(row)) {
|
||||
var rowAnnotations = annotations[row];
|
||||
if (!rowAnnotations)
|
||||
continue;
|
||||
|
||||
var rowInfo = this.$annotations[row] = {
|
||||
text: []
|
||||
};
|
||||
for (var i=0; i<rowAnnotations.length; i++) {
|
||||
var annotation = rowAnnotations[i];
|
||||
var annoText = annotation.text.replace(/"/g, """).replace(/'/g, "’").replace(/</, "<");
|
||||
if (rowInfo.text.indexOf(annoText) === -1)
|
||||
rowInfo.text.push(annoText);
|
||||
var type = annotation.type;
|
||||
if (type == "error")
|
||||
rowInfo.className = "ace_error";
|
||||
else if (type == "warning" && rowInfo.className != "ace_error")
|
||||
rowInfo.className = "ace_warning";
|
||||
else if (type == "info" && (!rowInfo.className))
|
||||
rowInfo.className = "ace_info";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.update = function(config) {
|
||||
this.$config = config;
|
||||
|
||||
var emptyAnno = {className: "", text: []};
|
||||
var html = [];
|
||||
var i = config.firstRow;
|
||||
var lastRow = config.lastRow;
|
||||
var fold = this.session.getNextFoldLine(i);
|
||||
var foldStart = fold ? fold.start.row : Infinity;
|
||||
var foldWidgets = this.$showFoldWidgets && this.session.foldWidgets;
|
||||
var breakpoints = this.session.$breakpoints;
|
||||
|
||||
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 annotation = this.$annotations[i] || emptyAnno;
|
||||
html.push("<div class='ace_gutter-cell",
|
||||
this.$decorations[i] || "",
|
||||
breakpoints[i] ? " ace_breakpoint " : " ",
|
||||
annotation.className,
|
||||
"' title='", annotation.text.join("\n"),
|
||||
"' style='height:", this.session.getRowLength(i) * config.lineHeight, "px;'>", (i+1));
|
||||
|
||||
if (foldWidgets) {
|
||||
var c = foldWidgets[i];
|
||||
// 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 ", c,
|
||||
c == "start" && i == foldStart && i < fold.end.row ? " closed" : " open",
|
||||
"'></span>"
|
||||
);
|
||||
}
|
||||
|
||||
html.push("</div>");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (this.session.$useWrapMode)
|
||||
html.push(
|
||||
"<div class='ace_gutter-cell' style='pointer-events:none;opacity:0'>",
|
||||
this.session.getLength() - 1,
|
||||
"</div>"
|
||||
);
|
||||
|
||||
this.element = dom.setInnerHtml(this.element, html.join(""));
|
||||
this.element.style.height = config.minHeight + "px";
|
||||
|
||||
var gutterWidth = this.element.offsetWidth;
|
||||
if (gutterWidth !== this.gutterWidth) {
|
||||
this.gutterWidth = gutterWidth;
|
||||
this._emit("changeGutterWidth", gutterWidth);
|
||||
}
|
||||
};
|
||||
|
||||
this.$showFoldWidgets = true;
|
||||
this.setShowFoldWidgets = function(show) {
|
||||
if (show)
|
||||
dom.addCssClass(this.element, "ace_folding-enabled");
|
||||
else
|
||||
dom.removeCssClass(this.element, "ace_folding-enabled");
|
||||
|
||||
this.$showFoldWidgets = show;
|
||||
};
|
||||
|
||||
this.getShowFoldWidgets = function() {
|
||||
return this.$showFoldWidgets;
|
||||
};
|
||||
|
||||
}).call(Gutter.prototype);
|
||||
|
||||
exports.Gutter = Gutter;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,214 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Range = require("../range").Range;
|
||||
var dom = require("../lib/dom");
|
||||
|
||||
var Marker = function(parentEl) {
|
||||
this.element = dom.createElement("div");
|
||||
this.element.className = "ace_layer ace_marker-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.$padding = 0;
|
||||
|
||||
this.setPadding = function(padding) {
|
||||
this.$padding = padding;
|
||||
};
|
||||
this.setSession = function(session) {
|
||||
this.session = session;
|
||||
};
|
||||
|
||||
this.setMarkers = function(markers) {
|
||||
this.markers = markers;
|
||||
};
|
||||
|
||||
this.update = function(config) {
|
||||
var config = config || this.config;
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
this.config = config;
|
||||
|
||||
|
||||
var html = [];
|
||||
for (var key in this.markers) {
|
||||
var marker = this.markers[key];
|
||||
|
||||
if (!marker.range) {
|
||||
marker.update(html, this, this.session, config);
|
||||
continue;
|
||||
}
|
||||
|
||||
var range = marker.range.clipRows(config.firstRow, config.lastRow);
|
||||
if (range.isEmpty()) continue;
|
||||
|
||||
range = range.toScreenRange(this.session);
|
||||
if (marker.renderer) {
|
||||
var top = this.$getTop(range.start.row, config);
|
||||
var left = Math.round(
|
||||
this.$padding + range.start.column * config.characterWidth
|
||||
);
|
||||
marker.renderer(html, range, left, top, config);
|
||||
}
|
||||
else if (range.isMultiLine()) {
|
||||
if (marker.type == "text") {
|
||||
this.drawTextMarker(html, range, marker.clazz, config);
|
||||
} else {
|
||||
this.drawMultiLineMarker(
|
||||
html, range, marker.clazz, config,
|
||||
marker.type
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.drawSingleLineMarker(
|
||||
html, range, marker.clazz + " start", config,
|
||||
null, marker.type
|
||||
);
|
||||
}
|
||||
}
|
||||
this.element = dom.setInnerHtml(this.element, html.join(""));
|
||||
};
|
||||
|
||||
this.$getTop = function(row, layerConfig) {
|
||||
return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight;
|
||||
};
|
||||
|
||||
// Draws a marker, which spans a range of text on multiple lines
|
||||
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig) {
|
||||
// selection start
|
||||
var row = range.start.row;
|
||||
|
||||
var lineRange = new Range(
|
||||
row, range.start.column,
|
||||
row, this.session.getScreenLastRowColumn(row)
|
||||
);
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " start", layerConfig, 1, "text");
|
||||
|
||||
// selection end
|
||||
row = range.end.row;
|
||||
lineRange = new Range(row, 0, row, range.end.column);
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, "text");
|
||||
|
||||
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");
|
||||
}
|
||||
};
|
||||
|
||||
// Draws a multi line marker, where lines span the full width
|
||||
this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, type) {
|
||||
var padding = type === "background" ? 0 : this.$padding;
|
||||
// from selection start to the end of the line
|
||||
var height = config.lineHeight;
|
||||
var top = this.$getTop(range.start.row, config);
|
||||
var left = Math.round(padding + range.start.column * config.characterWidth);
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, " start' style='",
|
||||
"height:", height, "px;",
|
||||
"right:0;",
|
||||
"top:", top, "px;",
|
||||
"left:", left, "px;'></div>"
|
||||
);
|
||||
|
||||
// from start of the last line to the selection end
|
||||
top = this.$getTop(range.end.row, config);
|
||||
var width = Math.round(range.end.column * config.characterWidth);
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"width:", width, "px;",
|
||||
"top:", top, "px;",
|
||||
"left:", padding, "px;'></div>"
|
||||
);
|
||||
|
||||
// all the complete lines
|
||||
height = (range.end.row - range.start.row - 1) * config.lineHeight;
|
||||
if (height < 0)
|
||||
return;
|
||||
top = this.$getTop(range.start.row + 1, config);
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"right:0;",
|
||||
"top:", top, "px;",
|
||||
"left:", padding, "px;'></div>"
|
||||
);
|
||||
};
|
||||
|
||||
// Draws a marker which covers part or whole width of a single screen line
|
||||
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig, extraLength, type) {
|
||||
var padding = type === "background" ? 0 : this.$padding;
|
||||
var height = layerConfig.lineHeight;
|
||||
|
||||
if (type === "background")
|
||||
var width = layerConfig.width;
|
||||
else
|
||||
width = Math.round((range.end.column + (extraLength || 0) - range.start.column) * layerConfig.characterWidth);
|
||||
|
||||
var top = this.$getTop(range.start.row, layerConfig);
|
||||
var left = Math.round(
|
||||
padding + range.start.column * layerConfig.characterWidth
|
||||
);
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"width:", width, "px;",
|
||||
"top:", top, "px;",
|
||||
"left:", left,"px;'></div>"
|
||||
);
|
||||
};
|
||||
|
||||
}).call(Marker.prototype);
|
||||
|
||||
exports.Marker = Marker;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,595 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
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 Text = function(parentEl) {
|
||||
this.element = dom.createElement("div");
|
||||
this.element.className = "ace_layer ace_text-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
|
||||
this.$characterSize = this.$measureSizes() || {width: 0, height: 0};
|
||||
this.$pollSizeChanges();
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.EOF_CHAR = "\xB6"; //"¶";
|
||||
this.EOL_CHAR = "\xAC"; //"¬";
|
||||
this.TAB_CHAR = "\u2192"; //"→" "\u21E5";
|
||||
this.SPACE_CHAR = "\xB7"; //"·";
|
||||
this.$padding = 0;
|
||||
|
||||
this.setPadding = function(padding) {
|
||||
this.$padding = padding;
|
||||
this.element.style.padding = "0 " + padding + "px";
|
||||
};
|
||||
|
||||
this.getLineHeight = function() {
|
||||
return this.$characterSize.height || 1;
|
||||
};
|
||||
|
||||
this.getCharacterWidth = function() {
|
||||
return this.$characterSize.width || 1;
|
||||
};
|
||||
|
||||
this.checkForSizeChanges = function() {
|
||||
var size = this.$measureSizes();
|
||||
if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) {
|
||||
this.$characterSize = size;
|
||||
this._emit("changeCharacterSize", {data: size});
|
||||
}
|
||||
};
|
||||
|
||||
this.$pollSizeChanges = function() {
|
||||
var self = this;
|
||||
this.$pollSizeChangesTimer = setInterval(function() {
|
||||
self.checkForSizeChanges();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
this.showInvisibles = false;
|
||||
this.setShowInvisibles = function(showInvisibles) {
|
||||
if (this.showInvisibles == showInvisibles)
|
||||
return false;
|
||||
|
||||
this.showInvisibles = showInvisibles;
|
||||
return true;
|
||||
};
|
||||
|
||||
this.$tabStrings = [];
|
||||
this.$computeTabString = function() {
|
||||
var tabSize = this.session.getTabSize();
|
||||
var tabStr = this.$tabStrings = [0];
|
||||
for (var i = 1; i < tabSize + 1; i++) {
|
||||
if (this.showInvisibles) {
|
||||
tabStr.push("<span class='ace_invisible'>"
|
||||
+ this.TAB_CHAR
|
||||
+ new Array(i).join(" ")
|
||||
+ "</span>");
|
||||
} else {
|
||||
tabStr.push(new Array(i+1).join(" "));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.updateLines = function(config, firstRow, lastRow) {
|
||||
this.$computeTabString();
|
||||
// Due to wrap line changes there can be new lines if e.g.
|
||||
// the line to updated wrapped in the meantime.
|
||||
if (this.config.lastRow != config.lastRow ||
|
||||
this.config.firstRow != config.firstRow) {
|
||||
this.scrollLines(config);
|
||||
}
|
||||
this.config = config;
|
||||
|
||||
var first = Math.max(firstRow, config.firstRow);
|
||||
var last = Math.min(lastRow, config.lastRow);
|
||||
|
||||
var lineElements = this.element.childNodes;
|
||||
var lineElementsIdx = 0;
|
||||
|
||||
for (var row = config.firstRow; row < first; row++) {
|
||||
var foldLine = this.session.getFoldLine(row);
|
||||
if (foldLine) {
|
||||
if (foldLine.containsRow(first)) {
|
||||
first = foldLine.start.row;
|
||||
break;
|
||||
} else {
|
||||
row = foldLine.end.row;
|
||||
}
|
||||
}
|
||||
lineElementsIdx ++;
|
||||
}
|
||||
|
||||
for (var i=first; i<=last; i++) {
|
||||
var lineElement = lineElements[lineElementsIdx++];
|
||||
if (!lineElement)
|
||||
continue;
|
||||
|
||||
var html = [];
|
||||
var tokens = this.session.getTokens(i);
|
||||
this.$renderLine(html, i, tokens, !this.$useLineGroups());
|
||||
lineElement = dom.setInnerHtml(lineElement, html.join(""));
|
||||
|
||||
i = this.session.getRowFoldEnd(i);
|
||||
}
|
||||
};
|
||||
|
||||
this.scrollLines = function(config) {
|
||||
this.$computeTabString();
|
||||
var oldConfig = this.config;
|
||||
this.config = config;
|
||||
|
||||
if (!oldConfig || oldConfig.lastRow < config.firstRow)
|
||||
return this.update(config);
|
||||
|
||||
if (config.lastRow < oldConfig.firstRow)
|
||||
return this.update(config);
|
||||
|
||||
var el = this.element;
|
||||
if (oldConfig.firstRow < config.firstRow)
|
||||
for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--)
|
||||
el.removeChild(el.firstChild);
|
||||
|
||||
if (oldConfig.lastRow > config.lastRow)
|
||||
for (var row=this.session.getFoldedRowCount(config.lastRow + 1, oldConfig.lastRow); row>0; row--)
|
||||
el.removeChild(el.lastChild);
|
||||
|
||||
if (config.firstRow < oldConfig.firstRow) {
|
||||
var fragment = this.$renderLinesFragment(config, config.firstRow, oldConfig.firstRow - 1);
|
||||
if (el.firstChild)
|
||||
el.insertBefore(fragment, el.firstChild);
|
||||
else
|
||||
el.appendChild(fragment);
|
||||
}
|
||||
|
||||
if (config.lastRow > oldConfig.lastRow) {
|
||||
var fragment = this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow);
|
||||
el.appendChild(fragment);
|
||||
}
|
||||
};
|
||||
|
||||
this.$renderLinesFragment = function(config, firstRow, lastRow) {
|
||||
var fragment = this.element.ownerDocument.createDocumentFragment();
|
||||
var row = firstRow;
|
||||
var foldLine = this.session.getNextFoldLine(row);
|
||||
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
||||
|
||||
while (true) {
|
||||
if (row > foldStart) {
|
||||
row = foldLine.end.row+1;
|
||||
foldLine = this.session.getNextFoldLine(row, foldLine);
|
||||
foldStart = foldLine ? foldLine.start.row : Infinity;
|
||||
}
|
||||
if (row > lastRow)
|
||||
break;
|
||||
|
||||
var container = dom.createElement("div");
|
||||
|
||||
var html = [];
|
||||
// Get the tokens per line as there might be some lines in between
|
||||
// beeing folded.
|
||||
var tokens = this.session.getTokens(row);
|
||||
this.$renderLine(html, row, tokens, false);
|
||||
|
||||
// don't use setInnerHtml since we are working with an empty DIV
|
||||
container.innerHTML = html.join("");
|
||||
if (this.$useLineGroups()) {
|
||||
container.className = 'ace_line_group';
|
||||
fragment.appendChild(container);
|
||||
} else {
|
||||
var lines = container.childNodes
|
||||
while(lines.length)
|
||||
fragment.appendChild(lines[0]);
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
return fragment;
|
||||
};
|
||||
|
||||
this.update = function(config) {
|
||||
this.$computeTabString();
|
||||
this.config = config;
|
||||
|
||||
var html = [];
|
||||
var firstRow = config.firstRow, lastRow = config.lastRow;
|
||||
|
||||
var row = firstRow;
|
||||
var foldLine = this.session.getNextFoldLine(row);
|
||||
var foldStart = foldLine ? foldLine.start.row : Infinity;
|
||||
|
||||
while (true) {
|
||||
if (row > foldStart) {
|
||||
row = foldLine.end.row+1;
|
||||
foldLine = this.session.getNextFoldLine(row, foldLine);
|
||||
foldStart = foldLine ? foldLine.start.row :Infinity;
|
||||
}
|
||||
if (row > lastRow)
|
||||
break;
|
||||
|
||||
if (this.$useLineGroups())
|
||||
html.push("<div class='ace_line_group'>")
|
||||
|
||||
// Get the tokens per line as there might be some lines in between
|
||||
// beeing folded.
|
||||
var tokens = this.session.getTokens(row);
|
||||
this.$renderLine(html, row, tokens, false);
|
||||
|
||||
if (this.$useLineGroups())
|
||||
html.push("</div>"); // end the line group
|
||||
|
||||
row++;
|
||||
}
|
||||
this.element = dom.setInnerHtml(this.element, html.join(""));
|
||||
};
|
||||
|
||||
this.$textToken = {
|
||||
"text": true,
|
||||
"rparen": true,
|
||||
"lparen": true
|
||||
};
|
||||
|
||||
this.$renderToken = function(stringBuilder, screenColumn, token, value) {
|
||||
var self = this;
|
||||
var replaceReg = /\t|&|<|( +)|([\u0000-\u0019\u00a0\u1680\u180E\u2000-\u200b\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(" ");
|
||||
} else if (c == "&") {
|
||||
return "&";
|
||||
} else if (c == "<") {
|
||||
return "<";
|
||||
} else if (c == "\t") {
|
||||
var tabSize = self.session.getScreenTabSize(screenColumn + tabIdx);
|
||||
screenColumn += tabSize - 1;
|
||||
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 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>";
|
||||
} else {
|
||||
screenColumn += 1;
|
||||
return "<span class='ace_cjk' style='width:" +
|
||||
(self.config.characterWidth * 2) +
|
||||
"px'>" + c + "</span>";
|
||||
}
|
||||
};
|
||||
|
||||
var output = value.replace(replaceReg, replaceFunc);
|
||||
|
||||
if (!this.$textToken[token.type]) {
|
||||
var classes = "ace_" + token.type.replace(/\./g, " ace_");
|
||||
var style = "";
|
||||
if (token.type == "fold")
|
||||
style = " style='width:" + (token.value.length * this.config.characterWidth) + "px;' ";
|
||||
stringBuilder.push("<span class='", classes, "'", style, ">", output, "</span>");
|
||||
}
|
||||
else {
|
||||
stringBuilder.push(output);
|
||||
}
|
||||
return screenColumn + value.length;
|
||||
};
|
||||
|
||||
this.$renderLineCore = function(stringBuilder, lastRow, tokens, splits, onlyContents) {
|
||||
var chars = 0;
|
||||
var split = 0;
|
||||
var splitChars;
|
||||
var screenColumn = 0;
|
||||
var self = this;
|
||||
|
||||
if (!splits || splits.length == 0)
|
||||
splitChars = Number.MAX_VALUE;
|
||||
else
|
||||
splitChars = splits[0];
|
||||
|
||||
if (!onlyContents) {
|
||||
stringBuilder.push("<div class='ace_line' style='height:",
|
||||
this.config.lineHeight, "px",
|
||||
"'>"
|
||||
);
|
||||
}
|
||||
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i];
|
||||
var value = token.value;
|
||||
|
||||
if (chars + value.length < splitChars) {
|
||||
screenColumn = self.$renderToken(
|
||||
stringBuilder, screenColumn, token, value
|
||||
);
|
||||
chars += value.length;
|
||||
}
|
||||
else {
|
||||
while (chars + value.length >= splitChars) {
|
||||
screenColumn = self.$renderToken(
|
||||
stringBuilder, screenColumn,
|
||||
token, value.substring(0, splitChars - chars)
|
||||
);
|
||||
value = value.substring(splitChars - chars);
|
||||
chars = splitChars;
|
||||
|
||||
if (!onlyContents) {
|
||||
stringBuilder.push("</div>",
|
||||
"<div class='ace_line' style='height:",
|
||||
this.config.lineHeight, "px",
|
||||
"'>"
|
||||
);
|
||||
}
|
||||
|
||||
split ++;
|
||||
screenColumn = 0;
|
||||
splitChars = splits[split] || Number.MAX_VALUE;
|
||||
}
|
||||
if (value.length != 0) {
|
||||
chars += value.length;
|
||||
screenColumn = self.$renderToken(
|
||||
stringBuilder, screenColumn, token, value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.showInvisibles) {
|
||||
if (lastRow !== this.session.getLength() - 1)
|
||||
stringBuilder.push("<span class='ace_invisible'>" + this.EOL_CHAR + "</span>");
|
||||
else
|
||||
stringBuilder.push("<span class='ace_invisible'>" + this.EOF_CHAR + "</span>");
|
||||
}
|
||||
if (!onlyContents)
|
||||
stringBuilder.push("</div>");
|
||||
};
|
||||
|
||||
this.$renderLine = function(stringBuilder, row, tokens, onlyContents) {
|
||||
// Check if the line to render is folded or not. If not, things are
|
||||
// simple, otherwise, we need to fake some things...
|
||||
if (!this.session.isRowFolded(row)) {
|
||||
var splits = this.session.getRowSplitData(row);
|
||||
this.$renderLineCore(stringBuilder, row, tokens, splits, onlyContents);
|
||||
} else {
|
||||
this.$renderFoldLine(stringBuilder, row, tokens, onlyContents);
|
||||
}
|
||||
};
|
||||
|
||||
this.$renderFoldLine = function(stringBuilder, row, tokens, onlyContents) {
|
||||
var session = this.session;
|
||||
var foldLine = session.getFoldLine(row);
|
||||
var renderTokens = [];
|
||||
|
||||
function addTokens(tokens, from, to) {
|
||||
var idx = 0, col = 0;
|
||||
while ((col + tokens[idx].value.length) < from) {
|
||||
col += tokens[idx].value.length;
|
||||
idx++;
|
||||
|
||||
if (idx == tokens.length)
|
||||
return;
|
||||
}
|
||||
if (col != from) {
|
||||
var value = tokens[idx].value.substring(from - col);
|
||||
// Check if the token value is longer then the from...to spacing.
|
||||
if (value.length > (to - from))
|
||||
value = value.substring(0, to - from);
|
||||
|
||||
renderTokens.push({
|
||||
type: tokens[idx].type,
|
||||
value: value
|
||||
});
|
||||
|
||||
col = from + value.length;
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
while (col < to && idx < tokens.length) {
|
||||
var value = tokens[idx].value;
|
||||
if (value.length + col > to) {
|
||||
renderTokens.push({
|
||||
type: tokens[idx].type,
|
||||
value: value.substring(0, to - col)
|
||||
});
|
||||
} else
|
||||
renderTokens.push(tokens[idx]);
|
||||
col += value.length;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) {
|
||||
if (placeholder) {
|
||||
renderTokens.push({
|
||||
type: "fold",
|
||||
value: placeholder
|
||||
});
|
||||
} else {
|
||||
if (isNewRow)
|
||||
tokens = session.getTokens(row);
|
||||
|
||||
if (tokens.length)
|
||||
addTokens(tokens, lastColumn, column);
|
||||
}
|
||||
}, foldLine.end.row, this.session.getLine(foldLine.end.row).length);
|
||||
|
||||
// splits for foldline are stored at its' first row
|
||||
var splits = this.session.$useWrapMode ? this.session.$wrapData[row] : null;
|
||||
this.$renderLineCore(stringBuilder, row, renderTokens, splits, onlyContents);
|
||||
};
|
||||
|
||||
this.$useLineGroups = function() {
|
||||
// For the updateLines function to work correctly, it's important that the
|
||||
// child nodes of this.element correspond on a 1-to-1 basis to rows in the
|
||||
// document (as distinct from lines on the screen). For sessions that are
|
||||
// wrapped, this means we need to add a layer to the node hierarchy (tagged
|
||||
// with the class name ace_line_group).
|
||||
return this.session.getUseWrapMode();
|
||||
};
|
||||
|
||||
this.destroy = function() {
|
||||
clearInterval(this.$pollSizeChangesTimer);
|
||||
if (this.$measureNode)
|
||||
this.$measureNode.parentNode.removeChild(this.$measureNode);
|
||||
delete this.$measureNode;
|
||||
};
|
||||
|
||||
}).call(Text.prototype);
|
||||
|
||||
exports.Text = Text;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("../test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var assert = require("../test/assertions");
|
||||
var EditSession = require("../edit_session").EditSession;
|
||||
var TextLayer = require("./text").Text;
|
||||
var JavaScriptMode = require("../mode/javascript").Mode;
|
||||
|
||||
module.exports = {
|
||||
|
||||
setUp: function(next) {
|
||||
this.session = new EditSession("");
|
||||
this.session.setMode(new JavaScriptMode());
|
||||
this.textLayer = new TextLayer(document.createElement("div"));
|
||||
this.textLayer.setSession(this.session);
|
||||
this.textLayer.config = {
|
||||
characterWidth: 10,
|
||||
lineHeight: 20
|
||||
};
|
||||
next()
|
||||
},
|
||||
|
||||
"test: render line with hard tabs should render the same as lines with soft tabs" : function() {
|
||||
this.session.setValue("a\ta\ta\t\na a a \n");
|
||||
this.textLayer.$computeTabString();
|
||||
|
||||
// row with hard tabs
|
||||
var row = 0;
|
||||
var tokens = this.session.getTokens(row);
|
||||
var stringBuilder = [];
|
||||
this.textLayer.$renderLine(stringBuilder, row, tokens);
|
||||
|
||||
// row with soft tabs
|
||||
row = 1;
|
||||
tokens = this.session.getTokens(row);
|
||||
var stringBuilder2 = [];
|
||||
this.textLayer.$renderLine(stringBuilder2, row, tokens);
|
||||
assert.equal(stringBuilder.join(""), stringBuilder2.join(""));
|
||||
},
|
||||
|
||||
"test rendering width of ideographic space (U+3000)" : function() {
|
||||
this.session.setValue("\u3000");
|
||||
|
||||
var tokens = this.session.getTokens(0);
|
||||
var stringBuilder = [];
|
||||
this.textLayer.$renderLine(stringBuilder, 0, tokens, true);
|
||||
assert.equal(stringBuilder.join(""), "<span class='ace_cjk' style='width:20px'></span>");
|
||||
|
||||
this.textLayer.setShowInvisibles(true);
|
||||
var stringBuilder = [];
|
||||
this.textLayer.$renderLine(stringBuilder, 0, tokens, true);
|
||||
assert.equal(
|
||||
stringBuilder.join(""),
|
||||
"<span class='ace_cjk ace_invisible' style='width:20px'>" + this.textLayer.SPACE_CHAR + "</span>"
|
||||
+ "<span class='ace_invisible'>\xB6</span>"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./oop");
|
||||
var event = require("./event");
|
||||
var EventEmitter = require("./event_emitter").EventEmitter;
|
||||
|
||||
/*
|
||||
* This class keeps track of the focus state of the given window.
|
||||
* Focus changes for example when the user switches a browser tab,
|
||||
* goes to the location bar or switches to another application.
|
||||
*/
|
||||
var BrowserFocus = function(win) {
|
||||
win = win || window;
|
||||
|
||||
this.lastFocus = new Date().getTime();
|
||||
this._isFocused = true;
|
||||
|
||||
var _self = this;
|
||||
|
||||
// IE < 9 supports focusin and focusout events
|
||||
if ("onfocusin" in win.document) {
|
||||
event.addListener(win.document, "focusin", function(e) {
|
||||
_self._setFocused(true);
|
||||
});
|
||||
|
||||
event.addListener(win.document, "focusout", function(e) {
|
||||
_self._setFocused(!!e.toElement);
|
||||
});
|
||||
}
|
||||
else {
|
||||
event.addListener(win, "blur", function(e) {
|
||||
_self._setFocused(false);
|
||||
});
|
||||
|
||||
event.addListener(win, "focus", function(e) {
|
||||
_self._setFocused(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
(function(){
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.isFocused = function() {
|
||||
return this._isFocused;
|
||||
};
|
||||
|
||||
this._setFocused = function(isFocused) {
|
||||
if (this._isFocused == isFocused)
|
||||
return;
|
||||
|
||||
if (isFocused)
|
||||
this.lastFocus = new Date().getTime();
|
||||
|
||||
this._isFocused = isFocused;
|
||||
this._emit("changeFocus");
|
||||
};
|
||||
|
||||
}).call(BrowserFocus.prototype);
|
||||
|
||||
|
||||
exports.BrowserFocus = BrowserFocus;
|
||||
});
|
||||
@@ -0,0 +1,292 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Mihai Sucan <mihai AT sucan AT gmail ODT com>
|
||||
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
exports.createElement = function(tag, ns) {
|
||||
return document.createElementNS ?
|
||||
document.createElementNS(ns || XHTML_NS, tag) :
|
||||
document.createElement(tag);
|
||||
};
|
||||
|
||||
exports.setText = function(elem, text) {
|
||||
if (elem.innerText !== undefined) {
|
||||
elem.innerText = text;
|
||||
}
|
||||
if (elem.textContent !== undefined) {
|
||||
elem.textContent = text;
|
||||
}
|
||||
};
|
||||
|
||||
exports.hasCssClass = function(el, name) {
|
||||
var classes = el.className.split(/\s+/g);
|
||||
return classes.indexOf(name) !== -1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Add a CSS class to the list of classes on the given node
|
||||
*/
|
||||
exports.addCssClass = function(el, name) {
|
||||
if (!exports.hasCssClass(el, name)) {
|
||||
el.className += " " + name;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Remove a CSS class from the list of classes on the given node
|
||||
*/
|
||||
exports.removeCssClass = function(el, name) {
|
||||
var classes = el.className.split(/\s+/g);
|
||||
while (true) {
|
||||
var index = classes.indexOf(name);
|
||||
if (index == -1) {
|
||||
break;
|
||||
}
|
||||
classes.splice(index, 1);
|
||||
}
|
||||
el.className = classes.join(" ");
|
||||
};
|
||||
|
||||
exports.toggleCssClass = function(el, name) {
|
||||
var classes = el.className.split(/\s+/g), add = true;
|
||||
while (true) {
|
||||
var index = classes.indexOf(name);
|
||||
if (index == -1) {
|
||||
break;
|
||||
}
|
||||
add = false;
|
||||
classes.splice(index, 1);
|
||||
}
|
||||
if(add)
|
||||
classes.push(name);
|
||||
|
||||
el.className = classes.join(" ");
|
||||
return add;
|
||||
};
|
||||
|
||||
/*
|
||||
* Add or remove a CSS class from the list of classes on the given node
|
||||
* depending on the value of <tt>include</tt>
|
||||
*/
|
||||
exports.setCssClass = function(node, className, include) {
|
||||
if (include) {
|
||||
exports.addCssClass(node, className);
|
||||
} else {
|
||||
exports.removeCssClass(node, className);
|
||||
}
|
||||
};
|
||||
|
||||
exports.hasCssString = function(id, doc) {
|
||||
var index = 0, sheets;
|
||||
doc = doc || document;
|
||||
|
||||
if (doc.createStyleSheet && (sheets = doc.styleSheets)) {
|
||||
while (index < sheets.length)
|
||||
if (sheets[index++].owningElement.id === id) return true;
|
||||
} else if ((sheets = doc.getElementsByTagName("style"))) {
|
||||
while (index < sheets.length)
|
||||
if (sheets[index++].id === id) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.importCssString = function importCssString(cssText, id, doc) {
|
||||
doc = doc || document;
|
||||
// If style is already imported return immediately.
|
||||
if (id && exports.hasCssString(id, doc))
|
||||
return null;
|
||||
|
||||
var style;
|
||||
|
||||
if (doc.createStyleSheet) {
|
||||
style = doc.createStyleSheet();
|
||||
style.cssText = cssText;
|
||||
if (id)
|
||||
style.owningElement.id = id;
|
||||
} else {
|
||||
style = doc.createElementNS
|
||||
? doc.createElementNS(XHTML_NS, "style")
|
||||
: doc.createElement("style");
|
||||
|
||||
style.appendChild(doc.createTextNode(cssText));
|
||||
if (id)
|
||||
style.id = id;
|
||||
|
||||
var head = doc.getElementsByTagName("head")[0] || doc.documentElement;
|
||||
head.appendChild(style);
|
||||
}
|
||||
};
|
||||
|
||||
exports.importCssStylsheet = function(uri, doc) {
|
||||
if (doc.createStyleSheet) {
|
||||
doc.createStyleSheet(uri);
|
||||
} else {
|
||||
var link = exports.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = uri;
|
||||
|
||||
var head = doc.getElementsByTagName("head")[0] || doc.documentElement;
|
||||
head.appendChild(link);
|
||||
}
|
||||
};
|
||||
|
||||
exports.getInnerWidth = function(element) {
|
||||
return (
|
||||
parseInt(exports.computedStyle(element, "paddingLeft"), 10) +
|
||||
parseInt(exports.computedStyle(element, "paddingRight"), 10) +
|
||||
element.clientWidth
|
||||
);
|
||||
};
|
||||
|
||||
exports.getInnerHeight = function(element) {
|
||||
return (
|
||||
parseInt(exports.computedStyle(element, "paddingTop"), 10) +
|
||||
parseInt(exports.computedStyle(element, "paddingBottom"), 10) +
|
||||
element.clientHeight
|
||||
);
|
||||
};
|
||||
|
||||
if (window.pageYOffset !== undefined) {
|
||||
exports.getPageScrollTop = function() {
|
||||
return window.pageYOffset;
|
||||
};
|
||||
|
||||
exports.getPageScrollLeft = function() {
|
||||
return window.pageXOffset;
|
||||
};
|
||||
}
|
||||
else {
|
||||
exports.getPageScrollTop = function() {
|
||||
return document.body.scrollTop;
|
||||
};
|
||||
|
||||
exports.getPageScrollLeft = function() {
|
||||
return document.body.scrollLeft;
|
||||
};
|
||||
}
|
||||
|
||||
if (window.getComputedStyle)
|
||||
exports.computedStyle = function(element, style) {
|
||||
if (style)
|
||||
return (window.getComputedStyle(element, "") || {})[style] || "";
|
||||
return window.getComputedStyle(element, "") || {};
|
||||
};
|
||||
else
|
||||
exports.computedStyle = function(element, style) {
|
||||
if (style)
|
||||
return element.currentStyle[style];
|
||||
return element.currentStyle;
|
||||
};
|
||||
|
||||
exports.scrollbarWidth = function(document) {
|
||||
|
||||
var inner = exports.createElement("p");
|
||||
inner.style.width = "100%";
|
||||
inner.style.minWidth = "0px";
|
||||
inner.style.height = "200px";
|
||||
|
||||
var outer = exports.createElement("div");
|
||||
var style = outer.style;
|
||||
|
||||
style.position = "absolute";
|
||||
style.left = "-10000px";
|
||||
style.overflow = "hidden";
|
||||
style.width = "200px";
|
||||
style.minWidth = "0px";
|
||||
style.height = "150px";
|
||||
|
||||
outer.appendChild(inner);
|
||||
|
||||
var body = document.body || document.documentElement;
|
||||
body.appendChild(outer);
|
||||
|
||||
var noScrollbar = inner.offsetWidth;
|
||||
|
||||
style.overflow = "scroll";
|
||||
var withScrollbar = inner.offsetWidth;
|
||||
|
||||
if (noScrollbar == withScrollbar) {
|
||||
withScrollbar = outer.clientWidth;
|
||||
}
|
||||
|
||||
body.removeChild(outer);
|
||||
|
||||
return noScrollbar-withScrollbar;
|
||||
};
|
||||
|
||||
/*
|
||||
* Optimized set innerHTML. This is faster than plain innerHTML if the element
|
||||
* already contains a lot of child elements.
|
||||
*
|
||||
* See http://blog.stevenlevithan.com/archives/faster-than-innerhtml for details
|
||||
*/
|
||||
exports.setInnerHtml = function(el, innerHtml) {
|
||||
var element = el.cloneNode(false);//document.createElement("div");
|
||||
element.innerHTML = innerHtml;
|
||||
el.parentNode.replaceChild(element, el);
|
||||
return element;
|
||||
};
|
||||
|
||||
exports.setInnerText = function(el, innerText) {
|
||||
var document = el.ownerDocument;
|
||||
if (document.body && "textContent" in document.body)
|
||||
el.textContent = innerText;
|
||||
else
|
||||
el.innerText = innerText;
|
||||
|
||||
};
|
||||
|
||||
exports.getInnerText = function(el) {
|
||||
var document = el.ownerDocument;
|
||||
if (document.body && "textContent" in document.body)
|
||||
return el.textContent;
|
||||
else
|
||||
return el.innerText || el.textContent || "";
|
||||
};
|
||||
|
||||
exports.getParentWindow = function(document) {
|
||||
return document.defaultView || document.parentWindow;
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,317 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keys = require("./keys");
|
||||
var useragent = require("./useragent");
|
||||
var dom = require("./dom");
|
||||
|
||||
exports.addListener = function(elem, type, callback) {
|
||||
if (elem.addEventListener) {
|
||||
return elem.addEventListener(type, callback, false);
|
||||
}
|
||||
if (elem.attachEvent) {
|
||||
var wrapper = function() {
|
||||
callback(window.event);
|
||||
};
|
||||
callback._wrapper = wrapper;
|
||||
elem.attachEvent("on" + type, wrapper);
|
||||
}
|
||||
};
|
||||
|
||||
exports.removeListener = function(elem, type, callback) {
|
||||
if (elem.removeEventListener) {
|
||||
return elem.removeEventListener(type, callback, false);
|
||||
}
|
||||
if (elem.detachEvent) {
|
||||
elem.detachEvent("on" + type, callback._wrapper || callback);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Prevents propagation and clobbers the default action of the passed event
|
||||
*/
|
||||
exports.stopEvent = function(e) {
|
||||
exports.stopPropagation(e);
|
||||
exports.preventDefault(e);
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.stopPropagation = function(e) {
|
||||
if (e.stopPropagation)
|
||||
e.stopPropagation();
|
||||
else
|
||||
e.cancelBubble = true;
|
||||
};
|
||||
|
||||
exports.preventDefault = function(e) {
|
||||
if (e.preventDefault)
|
||||
e.preventDefault();
|
||||
else
|
||||
e.returnValue = false;
|
||||
};
|
||||
|
||||
/*
|
||||
* @return {Number} 0 for left button, 1 for middle button, 2 for right button
|
||||
*/
|
||||
exports.getButton = function(e) {
|
||||
if (e.type == "dblclick")
|
||||
return 0;
|
||||
if (e.type == "contextmenu" || (e.ctrlKey && useragent.isMac))
|
||||
return 2;
|
||||
|
||||
// DOM Event
|
||||
if (e.preventDefault) {
|
||||
return e.button;
|
||||
}
|
||||
// old IE
|
||||
else {
|
||||
return {1:0, 2:2, 4:1}[e.button];
|
||||
}
|
||||
};
|
||||
|
||||
if (document.documentElement.setCapture) {
|
||||
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
|
||||
function onMouseMove(e) {
|
||||
eventHandler(e);
|
||||
return exports.stopPropagation(e);
|
||||
}
|
||||
|
||||
var called = false;
|
||||
function onReleaseCapture(e) {
|
||||
eventHandler(e);
|
||||
|
||||
if (!called) {
|
||||
called = true;
|
||||
releaseCaptureHandler(e);
|
||||
}
|
||||
|
||||
exports.removeListener(el, "mousemove", eventHandler);
|
||||
exports.removeListener(el, "mouseup", onReleaseCapture);
|
||||
exports.removeListener(el, "losecapture", onReleaseCapture);
|
||||
|
||||
el.releaseCapture();
|
||||
}
|
||||
|
||||
exports.addListener(el, "mousemove", eventHandler);
|
||||
exports.addListener(el, "mouseup", onReleaseCapture);
|
||||
exports.addListener(el, "losecapture", onReleaseCapture);
|
||||
el.setCapture();
|
||||
};
|
||||
}
|
||||
else {
|
||||
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
|
||||
function onMouseMove(e) {
|
||||
eventHandler(e);
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function onMouseUp(e) {
|
||||
eventHandler && eventHandler(e);
|
||||
releaseCaptureHandler && releaseCaptureHandler(e);
|
||||
|
||||
document.removeEventListener("mousemove", onMouseMove, true);
|
||||
document.removeEventListener("mouseup", onMouseUp, true);
|
||||
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove, true);
|
||||
document.addEventListener("mouseup", onMouseUp, true);
|
||||
};
|
||||
}
|
||||
|
||||
exports.addMouseWheelListener = function(el, callback) {
|
||||
var factor = 8;
|
||||
var listener = function(e) {
|
||||
if (e.wheelDelta !== undefined) {
|
||||
if (e.wheelDeltaX !== undefined) {
|
||||
e.wheelX = -e.wheelDeltaX / factor;
|
||||
e.wheelY = -e.wheelDeltaY / factor;
|
||||
} else {
|
||||
e.wheelX = 0;
|
||||
e.wheelY = -e.wheelDelta / factor;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (e.axis && e.axis == e.HORIZONTAL_AXIS) {
|
||||
e.wheelX = (e.detail || 0) * 5;
|
||||
e.wheelY = 0;
|
||||
} else {
|
||||
e.wheelX = 0;
|
||||
e.wheelY = (e.detail || 0) * 5;
|
||||
}
|
||||
}
|
||||
callback(e);
|
||||
};
|
||||
exports.addListener(el, "DOMMouseScroll", listener);
|
||||
exports.addListener(el, "mousewheel", listener);
|
||||
};
|
||||
|
||||
exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbackName) {
|
||||
var clicks = 0;
|
||||
var startX, startY, timer;
|
||||
var eventNames = {
|
||||
2: "dblclick",
|
||||
3: "tripleclick",
|
||||
4: "quadclick"
|
||||
};
|
||||
|
||||
var listener = function(e) {
|
||||
if (exports.getButton(e) != 0) {
|
||||
clicks = 0;
|
||||
} else {
|
||||
var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5;
|
||||
|
||||
if (!timer || isNewClick)
|
||||
clicks = 0;
|
||||
|
||||
clicks += 1;
|
||||
|
||||
if (timer)
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600);
|
||||
}
|
||||
if (clicks == 1) {
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
}
|
||||
|
||||
eventHandler[callbackName]("mousedown", e);
|
||||
|
||||
if (clicks > 4)
|
||||
clicks = 0;
|
||||
else if (clicks > 1)
|
||||
return eventHandler[callbackName](eventNames[clicks], e);
|
||||
};
|
||||
|
||||
exports.addListener(el, "mousedown", listener);
|
||||
useragent.isOldIE && exports.addListener(el, "dblclick", listener);
|
||||
};
|
||||
|
||||
function normalizeCommandKeys(callback, e, keyCode) {
|
||||
var hashId = 0;
|
||||
if ((useragent.isOpera && !("KeyboardEvent" in window)) && useragent.isMac) {
|
||||
hashId = 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0)
|
||||
| (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0);
|
||||
} else {
|
||||
hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0)
|
||||
| (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0);
|
||||
}
|
||||
|
||||
if (keyCode in keys.MODIFIER_KEYS) {
|
||||
switch (keys.MODIFIER_KEYS[keyCode]) {
|
||||
case "Alt":
|
||||
hashId = 2;
|
||||
break;
|
||||
case "Shift":
|
||||
hashId = 4;
|
||||
break;
|
||||
case "Ctrl":
|
||||
hashId = 1;
|
||||
break;
|
||||
default:
|
||||
hashId = 8;
|
||||
break;
|
||||
}
|
||||
keyCode = 0;
|
||||
}
|
||||
|
||||
if (hashId & 8 && (keyCode == 91 || keyCode == 93)) {
|
||||
keyCode = 0;
|
||||
}
|
||||
|
||||
// If there is no hashID and the keyCode is not a function key, then
|
||||
// we don't call the callback as we don't handle a command key here
|
||||
// (it's a normal key/character input).
|
||||
if (!hashId && !(keyCode in keys.FUNCTION_KEYS) && !(keyCode in keys.PRINTABLE_KEYS)) {
|
||||
return false;
|
||||
}
|
||||
return callback(e, hashId, keyCode);
|
||||
}
|
||||
|
||||
exports.addCommandKeyListener = function(el, callback) {
|
||||
var addListener = exports.addListener;
|
||||
if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) {
|
||||
// Old versions of Gecko aka. Firefox < 4.0 didn't repeat the keydown
|
||||
// event if the user pressed the key for a longer time. Instead, the
|
||||
// keydown event was fired once and later on only the keypress event.
|
||||
// To emulate the 'right' keydown behavior, the keyCode of the initial
|
||||
// keyDown event is stored and in the following keypress events the
|
||||
// stores keyCode is used to emulate a keyDown event.
|
||||
var lastKeyDownKeyCode = null;
|
||||
addListener(el, "keydown", function(e) {
|
||||
lastKeyDownKeyCode = e.keyCode;
|
||||
});
|
||||
addListener(el, "keypress", function(e) {
|
||||
return normalizeCommandKeys(callback, e, lastKeyDownKeyCode);
|
||||
});
|
||||
} else {
|
||||
var lastDown = null;
|
||||
|
||||
addListener(el, "keydown", function(e) {
|
||||
lastDown = e.keyIdentifier || e.keyCode;
|
||||
return normalizeCommandKeys(callback, e, e.keyCode);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (window.postMessage) {
|
||||
var postMessageId = 1;
|
||||
exports.nextTick = function(callback, win) {
|
||||
win = win || window;
|
||||
var messageName = "zero-timeout-message-" + postMessageId;
|
||||
exports.addListener(win, "message", function listener(e) {
|
||||
if (e.data == messageName) {
|
||||
exports.stopPropagation(e);
|
||||
exports.removeListener(win, "message", listener);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
win.postMessage(messageName, "*");
|
||||
};
|
||||
}
|
||||
else {
|
||||
exports.nextTick = function(callback, win) {
|
||||
win = win || window;
|
||||
window.setTimeout(callback, 0);
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
|
||||
* Mike de Boer <mike AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EventEmitter = {};
|
||||
|
||||
EventEmitter._emit =
|
||||
EventEmitter._dispatchEvent = function(eventName, e) {
|
||||
this._eventRegistry = this._eventRegistry || {};
|
||||
this._defaultHandlers = this._defaultHandlers || {};
|
||||
|
||||
var listeners = this._eventRegistry[eventName] || [];
|
||||
var defaultHandler = this._defaultHandlers[eventName];
|
||||
if (!listeners.length && !defaultHandler)
|
||||
return;
|
||||
|
||||
e = e || {};
|
||||
e.type = eventName;
|
||||
|
||||
if (!e.stopPropagation) {
|
||||
e.stopPropagation = function() {
|
||||
this.propagationStopped = true;
|
||||
};
|
||||
}
|
||||
|
||||
if (!e.preventDefault) {
|
||||
e.preventDefault = function() {
|
||||
this.defaultPrevented = true;
|
||||
};
|
||||
}
|
||||
|
||||
for (var i=0; i<listeners.length; i++) {
|
||||
listeners[i](e);
|
||||
if (e.propagationStopped)
|
||||
break;
|
||||
}
|
||||
|
||||
if (defaultHandler && !e.defaultPrevented)
|
||||
return defaultHandler(e);
|
||||
};
|
||||
|
||||
EventEmitter.setDefaultHandler = function(eventName, callback) {
|
||||
this._defaultHandlers = this._defaultHandlers || {};
|
||||
|
||||
if (this._defaultHandlers[eventName])
|
||||
throw new Error("The default handler for '" + eventName + "' is already set");
|
||||
|
||||
this._defaultHandlers[eventName] = callback;
|
||||
};
|
||||
|
||||
EventEmitter.on =
|
||||
EventEmitter.addEventListener = function(eventName, callback) {
|
||||
this._eventRegistry = this._eventRegistry || {};
|
||||
|
||||
var listeners = this._eventRegistry[eventName];
|
||||
if (!listeners)
|
||||
var listeners = this._eventRegistry[eventName] = [];
|
||||
|
||||
if (listeners.indexOf(callback) == -1)
|
||||
listeners.push(callback);
|
||||
};
|
||||
|
||||
EventEmitter.removeListener =
|
||||
EventEmitter.removeEventListener = function(eventName, callback) {
|
||||
this._eventRegistry = this._eventRegistry || {};
|
||||
|
||||
var listeners = this._eventRegistry[eventName];
|
||||
if (!listeners)
|
||||
return;
|
||||
|
||||
var index = listeners.indexOf(callback);
|
||||
if (index !== -1)
|
||||
listeners.splice(index, 1);
|
||||
};
|
||||
|
||||
EventEmitter.removeAllListeners = function(eventName) {
|
||||
if (this._eventRegistry) this._eventRegistry[eventName] = [];
|
||||
};
|
||||
|
||||
exports.EventEmitter = EventEmitter;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var EventEmitter = require("./event_emitter").EventEmitter;
|
||||
var assert = require("../test/assertions");
|
||||
|
||||
var Emitter = function() {};
|
||||
|
||||
oop.implement(Emitter.prototype, EventEmitter);
|
||||
|
||||
module.exports = {
|
||||
"test: dispatch event with no data" : function() {
|
||||
var emitter = new Emitter();
|
||||
|
||||
var called = false;
|
||||
emitter.addEventListener("juhu", function(e) {
|
||||
called = true;
|
||||
assert.equal(e.type, "juhu");
|
||||
});
|
||||
|
||||
emitter._emit("juhu");
|
||||
assert.ok(called);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// vim:set ts=4 sts=4 sw=4 st:
|
||||
// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
|
||||
// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project)
|
||||
// -- dantman Daniel Friesen Copyright(C) 2010 XXX No License Specified
|
||||
// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
|
||||
// -- Irakli Gozalishvili Copyright (C) 2010 MIT License
|
||||
|
||||
/*!
|
||||
Copyright (c) 2009, 280 North Inc. http://280north.com/
|
||||
MIT License. http://github.com/280north/narwhal/blob/master/README.md
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
require("./regexp");
|
||||
require("./es5-shim");
|
||||
|
||||
});
|
||||
@@ -0,0 +1,129 @@
|
||||
/*! @license
|
||||
==========================================================================
|
||||
SproutCore -- JavaScript Application Framework
|
||||
copyright 2006-2009, Sprout Systems Inc., Apple Inc. and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
SproutCore and the SproutCore logo are trademarks of Sprout Systems, Inc.
|
||||
|
||||
For more information about SproutCore, visit http://www.sproutcore.com
|
||||
|
||||
|
||||
==========================================================================
|
||||
@license */
|
||||
|
||||
// Most of the following code is taken from SproutCore with a few changes.
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./oop");
|
||||
|
||||
/*
|
||||
* Helper functions and hashes for key handling.
|
||||
*/
|
||||
var Keys = (function() {
|
||||
var ret = {
|
||||
MODIFIER_KEYS: {
|
||||
16: 'Shift', 17: 'Ctrl', 18: 'Alt', 224: 'Meta'
|
||||
},
|
||||
|
||||
KEY_MODS: {
|
||||
"ctrl": 1, "alt": 2, "option" : 2,
|
||||
"shift": 4, "meta": 8, "command": 8
|
||||
},
|
||||
|
||||
FUNCTION_KEYS : {
|
||||
8 : "Backspace",
|
||||
9 : "Tab",
|
||||
13 : "Return",
|
||||
19 : "Pause",
|
||||
27 : "Esc",
|
||||
32 : "Space",
|
||||
33 : "PageUp",
|
||||
34 : "PageDown",
|
||||
35 : "End",
|
||||
36 : "Home",
|
||||
37 : "Left",
|
||||
38 : "Up",
|
||||
39 : "Right",
|
||||
40 : "Down",
|
||||
44 : "Print",
|
||||
45 : "Insert",
|
||||
46 : "Delete",
|
||||
96 : "Numpad0",
|
||||
97 : "Numpad1",
|
||||
98 : "Numpad2",
|
||||
99 : "Numpad3",
|
||||
100: "Numpad4",
|
||||
101: "Numpad5",
|
||||
102: "Numpad6",
|
||||
103: "Numpad7",
|
||||
104: "Numpad8",
|
||||
105: "Numpad9",
|
||||
112: "F1",
|
||||
113: "F2",
|
||||
114: "F3",
|
||||
115: "F4",
|
||||
116: "F5",
|
||||
117: "F6",
|
||||
118: "F7",
|
||||
119: "F8",
|
||||
120: "F9",
|
||||
121: "F10",
|
||||
122: "F11",
|
||||
123: "F12",
|
||||
144: "Numlock",
|
||||
145: "Scrolllock"
|
||||
},
|
||||
|
||||
PRINTABLE_KEYS: {
|
||||
32: ' ', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5',
|
||||
54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a',
|
||||
66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h',
|
||||
73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o',
|
||||
80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
|
||||
87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
|
||||
188: ',', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\',
|
||||
221: ']', 222: '\''
|
||||
}
|
||||
};
|
||||
|
||||
// A reverse map of FUNCTION_KEYS
|
||||
for (var i in ret.FUNCTION_KEYS) {
|
||||
var name = ret.FUNCTION_KEYS[i].toUpperCase();
|
||||
ret[name] = parseInt(i, 10);
|
||||
}
|
||||
|
||||
// Add the MODIFIER_KEYS, FUNCTION_KEYS and PRINTABLE_KEYS to the KEY
|
||||
// variables as well.
|
||||
oop.mixin(ret, ret.MODIFIER_KEYS);
|
||||
oop.mixin(ret, ret.PRINTABLE_KEYS);
|
||||
oop.mixin(ret, ret.FUNCTION_KEYS);
|
||||
|
||||
return ret;
|
||||
})();
|
||||
oop.mixin(exports, Keys);
|
||||
|
||||
exports.keyCodeToString = function(keyCode) {
|
||||
return (Keys[keyCode] || String.fromCharCode(keyCode)).toLowerCase();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,164 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
exports.stringReverse = function(string) {
|
||||
return string.split("").reverse().join("");
|
||||
};
|
||||
|
||||
exports.stringRepeat = function (string, count) {
|
||||
return new Array(count + 1).join(string);
|
||||
};
|
||||
|
||||
var trimBeginRegexp = /^\s\s*/;
|
||||
var trimEndRegexp = /\s\s*$/;
|
||||
|
||||
exports.stringTrimLeft = function (string) {
|
||||
return string.replace(trimBeginRegexp, '');
|
||||
};
|
||||
|
||||
exports.stringTrimRight = function (string) {
|
||||
return string.replace(trimEndRegexp, '');
|
||||
};
|
||||
|
||||
exports.copyObject = function(obj) {
|
||||
var copy = {};
|
||||
for (var key in obj) {
|
||||
copy[key] = obj[key];
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
|
||||
exports.copyArray = function(array){
|
||||
var copy = [];
|
||||
for (var i=0, l=array.length; i<l; i++) {
|
||||
if (array[i] && typeof array[i] == "object")
|
||||
copy[i] = this.copyObject( array[i] );
|
||||
else
|
||||
copy[i] = array[i];
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
|
||||
exports.deepCopy = function (obj) {
|
||||
if (typeof obj != "object") {
|
||||
return obj;
|
||||
}
|
||||
|
||||
var copy = obj.constructor();
|
||||
for (var key in obj) {
|
||||
if (typeof obj[key] == "object") {
|
||||
copy[key] = this.deepCopy(obj[key]);
|
||||
} else {
|
||||
copy[key] = obj[key];
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
|
||||
exports.arrayToMap = function(arr) {
|
||||
var map = {};
|
||||
for (var i=0; i<arr.length; i++) {
|
||||
map[arr[i]] = 1;
|
||||
}
|
||||
return map;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* splice out of 'array' anything that === 'value'
|
||||
*/
|
||||
exports.arrayRemove = function(array, value) {
|
||||
for (var i = 0; i <= array.length; i++) {
|
||||
if (value === array[i]) {
|
||||
array.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.escapeRegExp = function(str) {
|
||||
return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
|
||||
};
|
||||
|
||||
exports.getMatchOffsets = function(string, regExp) {
|
||||
var matches = [];
|
||||
|
||||
string.replace(regExp, function(str) {
|
||||
matches.push({
|
||||
offset: arguments[arguments.length-2],
|
||||
length: str.length
|
||||
});
|
||||
});
|
||||
|
||||
return matches;
|
||||
};
|
||||
|
||||
|
||||
exports.deferredCall = function(fcn) {
|
||||
|
||||
var timer = null;
|
||||
var callback = function() {
|
||||
timer = null;
|
||||
fcn();
|
||||
};
|
||||
|
||||
var deferred = function(timeout) {
|
||||
deferred.cancel();
|
||||
timer = setTimeout(callback, timeout || 0);
|
||||
return deferred;
|
||||
};
|
||||
|
||||
deferred.schedule = deferred;
|
||||
|
||||
deferred.call = function() {
|
||||
this.cancel();
|
||||
fcn();
|
||||
return deferred;
|
||||
};
|
||||
|
||||
deferred.cancel = function() {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
return deferred;
|
||||
};
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
});
|
||||