Compare commits

...

577 Commits

Author SHA1 Message Date
bootstraponline 99e74bf00b Release 2.3.1 2012-10-21 17:16:40 -06:00
bootstraponline f48e923f28 Fix release 2012-10-21 17:15:09 -06:00
bootstraponline 5400b4bfdd Support inline and display math.
$$2^2$$

$2^2$

\\(2^2\\)

[2^2]
2012-10-21 17:15:09 -06:00
bootstraponline f68bebe0f6 Update math note 2012-10-21 16:26:35 -06:00
bootstraponline 4c6019b439 Update math note 2012-10-21 16:23:58 -06:00
bootstraponline 66e08a6b17 Release 2.3.0 2012-10-21 16:19:05 -06:00
bootstraponline 7898db70ed Auto load all MathJax extensions
Fix #549
2012-10-21 16:14:04 -06:00
bootstraponline 7c357116ff Remove TeX
As discussed with @vmg
MathJax is available via a flag for those self hosting gollum
2012-10-18 23:36:05 -06:00
bootstraponline 69ce0eb0d0 Update rake 2012-10-17 21:04:20 -06:00
bootstraponline 4db31a297b Update rake
Jekyll uses rake ~> 0.9
2012-10-17 21:03:29 -06:00
bootstraponline e1fca457e4 Restore gemnasium
Gemnasium fixed the missing pygments.rb issue.

https://github.com/laserlemon/gemnasium-parser/commit/c9b3e43c3021967d5c1bb115e7dd1555e01c6444
2012-10-17 20:54:01 -06:00
bootstraponline 7f8485ce80 Improve system requirements language 2012-10-16 22:31:25 -06:00
bootstraponline 290061fd11 Add system requirements to readme 2012-10-16 22:15:26 -06:00
bootstraponline a507836936 Update dependencies 2012-10-16 21:39:22 -06:00
bootstraponline 6524d20a96 Use pygments.rb 0.3.2 2012-10-16 21:36:37 -06:00
bootstraponline f1c523aa30 Release 2.2.9 2012-10-14 22:26:17 -06:00
bootstraponline 87c08f5613 Escape " in headers 2012-10-14 22:21:00 -06:00
bootstraponline 82913cea20 Improve base path note 2012-10-14 21:42:25 -06:00
bootstraponline 2ad743e4bd Release 2.2.8 2012-10-14 21:28:43 -06:00
bootstraponline fa97b57a96 Define default map as suggested on #460
Base path now sets a default map without having to use an external config.ru.
2012-10-14 20:57:27 -06:00
bootstraponline 1b952b6d56 Release 2.2.7 2012-10-14 17:24:33 -06:00
bootstraponline 90cc512bd1 Fix home loop with page-file-dir #491 2012-10-14 15:45:26 -06:00
bootstraponline b82556c9c0 Fix #460 2012-10-14 15:42:06 -06:00
bootstraponline fbe3b4bb3b Fix #460 2012-10-14 15:23:52 -06:00
bootstraponline 5ffd98ad31 Fix #491 2012-10-14 15:15:55 -06:00
bootstraponline cb9dd4d228 Fix formatting 2012-10-14 14:31:40 -06:00
bootstraponline cd823bf10c Add doc from wiki.rb 2012-10-14 14:31:00 -06:00
bootstraponline 5560ec52c2 Add base_path doc 2012-10-14 14:27:08 -06:00
bootstraponline 065151a77f Add base_path disclaimer 2012-10-14 14:25:27 -06:00
bootstraponline 23454f556c Release 2.2.6 2012-10-14 13:14:08 -06:00
bootstraponline a2b3ddf931 Update tests to XHTML 2012-10-14 13:07:18 -06:00
bootstraponline 44b0d2fcfc Remove old comment 2012-10-14 12:26:23 -06:00
bootstraponline aed4cc590a Fix unicode characters
Fix #547

Update test
2012-10-14 12:21:31 -06:00
bootstraponline 72ee08b5ab Release 2.2.5 2012-10-14 11:21:56 -06:00
bootstraponline 45547624e4 Improve tilde fence support
More than 3 tildes can be used. The code block must end with the same amount of tildes used to open the code block.

Fix #537

http://johnmacfarlane.net/pandoc/README.html#delimited-code-blocks
2012-10-14 11:02:45 -06:00
bootstraponline f928cfa8be Don't ship Lorem ipsum in gem 2012-10-13 20:21:08 -06:00
bootstraponline 988984846a Release 2.2.4 2012-10-13 20:01:57 -06:00
bootstraponline 1149618653 Fix #537 2012-10-13 19:53:41 -06:00
bootstraponline 168a033903 Remove old comment 2012-10-13 14:59:42 -06:00
bootstraponline 6a765c9791 Fix #537 2012-10-13 14:52:28 -06:00
bootstraponline e16ae7b511 Travis is having a bad day
E: There are problems and -y was used without --force-yes
before_install: 'sudo apt-get install -y asciidoc' returned false.
Done. Build script exited with: 1
2012-10-13 14:07:15 -06:00
bootstraponline 174334ea44 Remove comment 2012-10-13 13:58:56 -06:00
bootstraponline dbdf06930d Fix 2012-10-13 13:55:20 -06:00
bootstraponline c93e65ddc3 Merge branch 'master' of github.com:github/gollum 2012-10-13 13:32:19 -06:00
bootstraponline 56101ed264 Fix #535 and add test 2012-10-13 13:32:08 -06:00
bootstraponline 8269c8e574 TOC doesn't require ' 2012-10-13 13:11:31 -06:00
bootstraponline 2246419d1e Fix spacing 2012-10-13 13:09:20 -06:00
bootstraponline 118a0c318b Update comment 2012-10-13 13:06:15 -06:00
bootstraponline 5401cf2910 Fix #542 2012-10-13 13:04:51 -06:00
bootstraponline 432f9b8d2f Add test for #542 2012-10-13 12:57:58 -06:00
bootstraponline 66fc8a2d31 Revert "Fix #542"
This reverts commit 2f3dd3d227.
2012-10-13 12:55:43 -06:00
bootstraponline 2f3dd3d227 Fix #542
Page link may contain duplicate starting forward slashes.
//page points to http://page/ when what we want is
/page pointing to http://localhost:1234/page
2012-10-13 09:53:25 -06:00
bootstraponline c43fd9fa6c Update language comment 2012-10-12 21:19:24 -06:00
bootstraponline 868518e0f5 Bash is Ace mode sh 2012-10-12 20:58:05 -06:00
bootstraponline 039b5cce98 Try to fix Travis
FFI is no longer used in the new pygments.rb.
apt-get update may resolve the asciidoc install failure.
2012-10-12 20:24:31 -06:00
bootstraponline 4a421842d5 https://github.com/travis-ci/travis-ci/issues/725
Modified README to trigger a Travis CI build. It's currently broken.
2012-10-12 20:22:10 -06:00
bootstraponline cfbb124f81 Update README.md 2012-10-12 20:16:43 -06:00
bootstraponline dcb147cde2 Ensure declaredLanguage is lower case 2012-10-10 20:20:33 -06:00
bootstraponline 8d06b5e67e Fix pygments language to Ace mode translation 2012-10-10 20:16:04 -06:00
bootstraponline 4776d0b422 Use rake release in readme 2012-10-10 19:45:42 -06:00
bootstraponline 58bb340c33 Release 2.2.3 2012-10-10 19:43:30 -06:00
bootstraponline ee790a9b7c Add rake bump to readme 2012-10-10 19:38:53 -06:00
bootstraponline ac432aad78 Add bump task to Rakefile 2012-10-10 19:35:04 -06:00
bootstraponline 30207e0a39 Merge pull request #533 from wrs/wrs_syntaxfixes
Two little syntax highlighting fixes
2012-10-10 16:56:37 -07:00
Walter Smith d98547a33c Fix lack of CoffeeScript livepreview
Pygments calls it coffeescript, but Ace calls it coffee.
2012-10-10 14:20:50 -07:00
Walter Smith b7cdeabbf6 Catch all Pygments errors
An unrecognized language was generating a MentosError rather than a
PythonError. Just catch anything that goes wrong in Pygments.
2012-10-10 14:20:50 -07:00
bootstraponline be9907a0cc v2.2.2 2012-10-04 18:17:24 -06:00
bootstraponline 30f42c50a9 Fix #528 2012-10-04 17:18:47 -06:00
bootstraponline 7cba65b138 Gemnasium is not including all deps.
pygments.rb is missing for example. Will restore once Gemnasium has fixed the issue.
2012-10-01 23:50:35 -06:00
bootstraponline f34a78b336 Proc.new instead of lambda. 2012-10-01 23:45:04 -06:00
bootstraponline e1942dda03 Merge pull request #513 from bootstraponline/embed_code
Embed code. #508.
2012-10-01 22:36:25 -07:00
bootstraponline 7142e284fa .call instead of .() for 1.8.7 2012-10-01 23:29:15 -06:00
bootstraponline 3c1c588953 Restore wiki_factory. 2012-10-01 23:23:40 -06:00
bootstraponline 52cc6bae34 Update dependencies. 2012-09-29 13:50:11 -06:00
bootstraponline 955c608115 Update rake. 2012-09-29 13:40:02 -06:00
bootstraponline 2e00cf312c Merge pull request #524 from osener/patch-1
Update org-ruby
2012-09-29 12:17:59 -07:00
Ozan Sener 09bbc144d1 Update org-ruby
Fixes #81
2012-09-29 11:19:09 +03:00
bootstraponline d02b63a434 Fix test. 2012-09-26 00:08:11 -06:00
bootstraponline 9b63c67d8c Try to fix tests. 2012-09-25 23:57:35 -06:00
bootstraponline 05c4bf3374 Add local file support.
Example of absolute path to local file.
```html:/home```

Example of relative path to local file.
```html:home```

1.8.7 string fix. 's'[0..0] instead of 's'[0]

Fix regex.

Add absolute and relative tests.
2012-09-25 23:31:58 -06:00
bootstraponline 424b4d3f4e Remove debug statements. 2012-09-25 23:31:25 -06:00
bootstraponline f9a6187fab Fix undefined method `[]' for nil:NilClass 2012-09-25 23:31:08 -06:00
Henrik d406472882 1.8.7 fixes 2012-09-25 23:29:11 -06:00
Henrik 749b5a5ff8 Adding functionality for fetching code from github
hack for 1.8.7

Don't miss test_markup's relative require

need some food now
2012-09-25 23:29:08 -06:00
bootstraponline 091d5fe750 Update multibyte caracters. 2012-09-25 22:58:07 -06:00
bootstraponline c8894fb465 New pygments.rb works correctly.
The expected output from the tests differs only in newlines.

git diff makes it seem like everything changed. bzr qdiff has a better default diff. git doesn't do per char diffs.

Revert "New pygments has issues."

This reverts commit 2dd41cbfac.
2012-09-25 22:45:57 -06:00
bootstraponline 2dd41cbfac New pygments has issues.
Revert "Update pygments. Solves #225 #490 #517"

This reverts commit c0c77c5ba7.

Revert "Fix pygments.rb tests."

This reverts commit 1f2165e68b.
2012-09-25 21:54:49 -06:00
bootstraponline 1f2165e68b Fix pygments.rb tests. 2012-09-25 21:47:24 -06:00
bootstraponline e9b6bdbdd7 Add dependency status. 2012-09-25 21:38:09 -06:00
bootstraponline c0c77c5ba7 Update pygments. Solves #225 #490 #517 2012-09-25 21:36:37 -06:00
Corey Donohoe 12403172ac Merge pull request #521 from Vanuan/update_nokogiri
Update nokogiri
2012-09-25 12:16:50 -07:00
John Yani 3b41ab8d75 Update nokogiri 2012-09-25 22:04:43 +03:00
bootstraponline 7bcf35f5b1 Fix #517. Thanks @roa 2012-09-23 16:26:48 -06:00
bootstraponline 9a7e1c94c7 Merge pull request #515 from realmacsoftware/master
Populate author details using the session.
2012-09-16 10:32:33 -07:00
Keith Duncan 30c2e675da Test that author details from the session are committed into the repository 2012-09-16 16:49:17 +01:00
Keith Duncan ac405803e8 Add notes on providing author details to the Rack documentation section 2012-09-16 16:25:09 +01:00
Keith Duncan 7dee787a92 Add documentation for where the commit_message parameters are passed and where they're source from 2012-09-16 15:59:49 +01:00
Keith Duncan ae4b1cdeca Add support for author parameters coming in from the session, to be set by rack middleware further up the stack 2012-09-15 21:06:08 +01:00
bootstraponline 572982cbf9 Use a professional right left button. 2012-09-09 21:11:16 -06:00
bootstraponline 74290874f9 Fix #383 test. 2012-09-09 14:05:10 -06:00
bootstraponline 847f08d952 Use block form of gsub to avoid regexp backref interpolation
The content of this commit message is from @kislyuk's comments on the below two issues.

Fix #383
Fix #511

`gsub!(pattern, replacement) interpolates` regexp backreferences
`gsub!(pattern) do block` doesn't

http://stackoverflow.com/questions/2082457/ruby-gsub-problem-when-using-backreference-and-hashes
2012-09-09 12:22:56 -06:00
Neal Pisenti 0bcd616668 fix mathjax option, fixes #509 2012-09-09 11:50:48 -06:00
bootstraponline 9dd701ccc4 Grit is broken. #508 #356 2012-09-04 17:52:56 -06:00
bootstraponline 56a5a7d92b Fix #507 2012-09-04 16:24:16 -06:00
bootstraponline 0cf0fad50e Finish removing MathJax from Live Preview. 2012-09-02 15:27:32 -06:00
bootstraponline 5f9e91656e Fix LaTeX tests. 2012-09-02 15:03:56 -06:00
Vicent Marti a7a2479f85 Release 2.2.1 2012-09-02 22:43:50 +02:00
Vicent Marti a8b230a490 Properly escape TeX data. 2012-09-02 22:27:04 +02:00
bootstraponline 041b01f171 Fix #490 2012-09-01 12:33:08 -06:00
Vicent Marti 1c475f3215 Release 2.2.0 2012-09-01 12:24:17 +02:00
Vicent Marti ab699d94b0 Do not render LaTeX locally
Offload the rendering service to MathTran.org, the free and open-source
LaTeX rendering engine.
2012-09-01 12:23:02 +02:00
bootstraponline 942d32c9b6 Fix uninstall command 2012-08-30 21:36:11 -06:00
bootstraponline 97f15f0b18 Add edit hotkey. #496 2012-08-30 21:07:57 -06:00
bootstraponline ed49358c50 Add h1-3 shortcuts. #496 2012-08-30 20:54:20 -06:00
bootstraponline 85eeecd140 Add save hotkey. 2012-08-30 20:48:44 -06:00
bootstraponline 30fd40fbe5 Fix #498
Ruby 1.8.7 and ri can't deal with <!-- appearing in documentation.
Please upgrade to the latest Ruby if you're able to.
2012-08-30 20:29:53 -06:00
bootstraponline 2ed262cacd v2.1.9 2012-08-30 20:12:28 -06:00
bootstraponline 29a1ef8f8a Skip doc on install 2012-08-30 20:04:20 -06:00
bootstraponline 772d18ee62 Fix uninstall command 2012-08-30 20:00:54 -06:00
bootstraponline dd604d9942 Fix #498 2012-08-30 19:57:20 -06:00
bootstraponline 85abc83427 v2.1.8 2012-08-30 19:41:54 -06:00
bootstraponline 6d8220629c Fix #500 2012-08-30 19:37:57 -06:00
bootstraponline 6ff7ada096 Fix #495 2012-08-30 18:31:35 -03:00
bootstraponline 8575049de5 Update get /data
Remove leading slash from page
Fix edge case with path set to '/'
2012-08-30 11:40:07 -03:00
bootstraponline bb6fb0c253 pathName is undefined when not found instead of 0 2012-08-30 11:18:02 -03:00
bootstraponline eb2ad9f840 Fix path
.key now returns undefined on failure so path can be 0.
If path is undefined then use an empty string.
2012-08-30 11:14:24 -03:00
bootstraponline d0dd23fc11 Fix path 2012-08-30 11:09:44 -03:00
bootstraponline 7ae4acbdb0 Fix #497 #492
Data url now includes path.
2012-08-30 11:03:11 -03:00
bootstraponline 881590ab37 Merge pull request #494 from releu/fix-requiring-uri-encoding-components
Move require "uri_encode_component"
2012-08-28 18:33:18 -07:00
Jan Bernacki 5e479dc5d9 move require 2012-08-28 22:44:09 +04:00
bootstraponline 7db9c2e762 Merge pull request #487 from jm/master
Fix bug with missing variable 'ext'
2012-08-27 11:08:19 -07:00
bootstraponline ce6b0ac095 v2.1.7 2012-08-25 19:21:13 -06:00
bootstraponline 420bb06988 Fix create test. 2012-08-25 18:58:20 -06:00
bootstraponline 20566f8acf Fix #484 2012-08-25 18:54:07 -06:00
bootstraponline 1d5f69704a Clean paths so they start with one slash. 2012-08-25 18:41:13 -06:00
bootstraponline 0da664299e Fix edit. 2012-08-24 13:47:17 -06:00
bootstraponline 6e8fb2b457 Disable exact on edit for now. 2012-08-24 13:38:34 -06:00
bootstraponline d1c72a4ff3 Fix #483 and #481
Exact matching of requested pages

- /page is no longer the same as /a/page
- Deleting /page only deletes /page (before it would delete /a/page instead of /page)
- Edit currently breaks the unit tests if exact matching is enabled
- Fix redirect on create
- Add @giga's checked_dir = '' fix https://github.com/giga/gollum/commit/936958b47324a09c683cb90a2560484b47e09529
- Fix create unit test
2012-08-24 13:35:37 -06:00
bootstraponline 0bf05392e4 Redirect to correct path. #481 2012-08-24 12:26:59 -06:00
bootstraponline 7ecef0c045 Fix #479 2012-08-23 14:11:28 -06:00
bootstraponline 33ca329253 Handle nil slash. 2012-08-23 12:30:08 -06:00
bootstraponline 01fa4770cb Fix page lookup. #473 2012-08-23 12:16:40 -06:00
bootstraponline b76257c49c Restore foward slash. 2012-08-23 11:59:56 -06:00
bootstraponline e2fbf22f38 Fix #473. 2012-08-23 11:51:20 -06:00
bootstraponline 134432d029 v2.1.6 2012-08-23 11:33:00 -06:00
bootstraponline 8d4d6e80b8 Fix #475. 2012-08-23 11:27:40 -06:00
bootstraponline 85e6ef3dca v2.1.5 2012-08-22 19:57:22 -06:00
bootstraponline 60f1467229 Fix encoding for 1.8. 2012-08-22 18:51:41 -06:00
bootstraponline 1757242382 Don't unpack Fixnum. 2012-08-22 17:40:53 -06:00
bootstraponline 55df7bb9c4 Use encodeURIComponent instead of CGI::escape when output is sent to browser. 2012-08-22 17:30:46 -06:00
bootstraponline 686b8acd38 Fix encodeURIComponent on Ruby 1.8.
Replace .ord with .unpack('U')[0]
2012-08-22 17:23:08 -06:00
bootstraponline a5f9df6170 Restore CGI::escape. 2012-08-22 16:57:24 -06:00
bootstraponline 27f61a870a Merge pull request #477 from LuminosoInsight/master
Fix titles created with the "New" button.
2012-08-22 15:54:23 -07:00
bootstraponline a48e8d1c5c New editor style.
Disable MathJax in live preview. Parser isn't MathJax aware.
Performance of MathJax in live preview is not great.
Auto hide editor overflow.
2012-08-22 16:50:57 -06:00
bootstraponline b80f74bccd Remove protocol and host. 2012-08-22 13:32:18 -06:00
bootstraponline 1e768734ef Disable MathJax by default.
GitHub.com doesn't support MathJax. The parser is not MathJax aware which causes problems.

--mathjax enables MathJax.
2012-08-22 13:31:21 -06:00
bootstraponline 11c9cabeb3 Fix edit baseUrl. 2012-08-22 13:21:01 -06:00
bootstraponline 3a14ab92f0 Fix new page when using map '/wiki' in config.ru. 2012-08-22 13:15:18 -06:00
bootstraponline 62d5f52398 Fix anchor for Firefox. 2012-08-22 13:10:11 -06:00
Rob Speer 2b4848566c Fix names created with the 'New' button.
Previously, a page created with the 'New' button would get all of its
spaces turned into the + symbol when submitted, which Gollum would then
convert into "-plus-" in the title. So, for example, a request to create
a page called "Test page" would instead get "test plus page".

This change changes + to - in the parameter received by /create/.
2012-08-22 14:15:20 -04:00
bootstraponline 7c825e877c Remove protocol + host. 2012-08-20 15:51:07 -06:00
bootstraponline 8417c277e6 Fix delete link when using baseUrl. 2012-08-20 15:23:07 -06:00
bootstraponline 9cef423908 Remove default value in new page. 2012-08-19 14:25:02 -06:00
bootstraponline e73c84490e Remove prefix. #470. 2012-08-16 12:01:03 -06:00
bootstraponline 6cfc807db0 Revert still broken in Grit. 2012-08-15 12:22:03 -06:00
bootstraponline be366f8103 v2.1.4 2012-08-15 12:06:12 -06:00
bootstraponline 2d13bd796f Improve #470 fix. 2012-08-15 12:03:48 -06:00
bootstraponline 523f8f80ca Fix #470. 2012-08-15 11:48:17 -06:00
bootstraponline b76fef9143 Update version to 2.1.3 2012-08-13 11:37:56 -06:00
bootstraponline e935af83d5 Update gemspec. 2012-08-13 11:35:15 -06:00
bootstraponline d4e019ef42 Merge pull request #331 from tjh/home-page-link-issue
Redirect from root to /Home, fixes #250
2012-08-09 10:41:31 -07:00
bootstraponline 2e738828c6 Merge pull request #467 from jamesduncombe/pygments_initialize
Added Pygments.start to initialize Pygments on startup, fixes #465
2012-08-09 10:21:59 -07:00
James Duncombe fd7dc93778 Added Pygments.start to initialize Pygments on startup 2012-08-09 09:14:55 +01:00
bootstraponline 3df407d9ee Merge pull request #464 from giga/master
Fix editor when base url is '/'
2012-08-08 10:53:45 -07:00
Jean-Philippe Garcia Ballester 6fbba84725 Revert "Base path is relative."
This reverts commit 69e453ea0b.
2012-08-08 13:49:11 +02:00
Jean-Philippe Garcia Ballester 37d20fa9cc Base url without trailing '/'
This will allow cleaner url in templates and javascripts.
2012-08-08 13:49:09 +02:00
bootstraponline 410cd912ac Fix releasing. 2012-08-06 18:31:36 -06:00
bootstraponline d234bbd861 Test get %r{/(.+?)/([0-9a-f]{40})} do 2012-08-06 18:27:12 -06:00
Corey Donohoe 3f68d96815 setup proper gem version numbers 2012-08-06 16:32:16 -07:00
bootstraponline 015cd895d2 Don't ignore version. 2012-08-06 17:18:30 -06:00
bootstraponline 5fa4b48d85 Fix new page default dir. 2012-08-06 15:57:46 -06:00
bootstraponline 88a3783bbc Remove wpage. 2012-08-06 15:55:05 -06:00
bootstraponline ea2254b9bd Fix #462.
Add test for 462.
2012-08-06 15:52:19 -06:00
bootstraponline 9a0c1f2605 Fix path. 2012-08-06 15:18:15 -06:00
bootstraponline 008f26bb7d Fix app. 2012-08-06 14:49:56 -06:00
bootstraponline 69e453ea0b Base path is relative. 2012-08-06 14:28:24 -06:00
bootstraponline 88b0b608f4 Add null guard. 2012-08-06 13:49:48 -06:00
bootstraponline 19e3987ae3 Fix path escaping. 2012-08-06 13:36:28 -06:00
bootstraponline c72e91ddaf Fix #462. 2012-08-06 13:16:31 -06:00
bootstraponline c789dd5067 Update org-ruby. 2012-08-02 19:45:06 -06:00
bootstraponline 551949de29 Fix #459. 2012-08-02 16:55:24 -06:00
bootstraponline 80730ee87a Merge pull request #419 from trans/metadata
Add support for embedded page metadata.
2012-08-01 16:05:10 -07:00
trans 71028adc9e Add support for embedded page metadata. 2012-08-01 18:35:53 -04:00
bootstraponline a2efebc06c Fix #453. 2012-08-01 13:04:04 -06:00
bootstraponline a4e277a86b Update gemspec. 2012-08-01 10:20:53 -06:00
bootstraponline 494c80d8b1 Add home button. 2012-08-01 01:53:30 -06:00
bootstraponline 02539bfdd3 Move new page dir logic to JS. 2012-08-01 01:49:38 -06:00
bootstraponline a0f05eaf67 More refactoring.
Fix delete.
2012-08-01 01:36:23 -06:00
bootstraponline 72e26fc90b Refactor app.rb to use paged.
Create new pages relative to current directory.
2012-08-01 00:37:34 -06:00
bootstraponline 2261cfabf3 Make wiki.page directory aware.
Remove scoped_page.
2012-07-31 23:24:37 -06:00
bootstraponline c1afa2a0e3 Path is now sent on rename. 2012-07-31 22:13:04 -06:00
bootstraponline d28f454c6e Send path when renaming pages.
Fix nil error on editing a non-existent page.
Use baseURL on delete.
2012-07-31 21:58:35 -06:00
bootstraponline f471c80ac0 Merge pull request #455 from ennova/scoped-page
Add a method that returns a given page name scoped to a directory.
2012-07-31 20:18:38 -07:00
Odin Dutton and Sebastian Korfmann be086d94b5 Add a method that returns a given page name scoped to a directory.
This is to allow access to non unique pages.
2012-08-01 09:15:25 +10:00
bootstraponline ff719510b6 Merge pull request #454 from kislyuk/master
Don't stop highlighting if one code block throws an exception.
2012-07-31 11:13:58 -07:00
Andrey Kislyuk 7b16116b67 Proceed with highlighting if one code block fails 2012-07-31 08:44:38 -07:00
bootstraponline 8422b71204 @arr2036's fix for #453. 2012-07-30 19:04:10 -06:00
bootstraponline c9bc2a89f6 Delete link now works with directories.
Fix #452.
2012-07-27 15:03:26 -06:00
bootstraponline 387a52a7ba Remove extra / in delete href. 2012-07-27 14:54:34 -06:00
bootstraponline 96842d9742 Refactor page url generation.
Avoid appending './' to urls.
2012-07-27 14:45:40 -06:00
bootstraponline 8fcef5401b Fix href in file view. 2012-07-27 12:27:16 -06:00
bootstraponline 804c4c678d Fix #446.
The old regex turns 'a/b/c/' into 'a/' which is not correct.
The new regex is directory aware.
2012-07-27 12:14:06 -06:00
bootstraponline 8558777ece Include full path in file view href. 2012-07-27 11:34:04 -06:00
bootstraponline 77bb608878 Fix #446. 2012-07-27 11:08:11 -06:00
bootstraponline 2f574261a7 Merge pull request #359 from sunny/base-url
Relative urls.
2012-07-25 09:55:26 -07:00
Sunny Ripert 28c4a2c39e Merge pull request #2 from giga/base-url
Fix relative url
2012-07-25 07:59:01 -07:00
Jean-Philippe Garcia Ballester bd36cb59b1 Fix relative url 2012-07-25 12:33:48 +02:00
Jean-Philippe Garcia Ballester 998358ada8 Fix relative url 2012-07-25 12:27:00 +02:00
Sunny Ripert 75a00e8821 baseUrl missing on page rename 2012-07-25 11:20:53 +02:00
Sunny Ripert b5653464d2 Merge branch 'master' into base-url
Conflicts:
	lib/gollum/frontend/public/gollum/css/_styles.css
	lib/gollum/frontend/public/gollum/javascript/gollum.js
	lib/gollum/frontend/public/gollum/livepreview/js/livepreview.js
	lib/gollum/frontend/templates/file_view.mustache
	lib/gollum/frontend/templates/layout.mustache
	lib/gollum/frontend/templates/page.mustache
2012-07-25 10:00:52 +02:00
Sunny Ripert 0269cd0b3b Merge pull request #1 from giga/base-url
Base url
2012-07-25 00:49:18 -07:00
Jean-Philippe Garcia Ballester 88ed662fd4 Fix editor to work with “base_url” 2012-07-24 23:51:49 +02:00
Jean-Philippe Garcia Ballester 7c180c86a4 Set wiki “base_path” option to fix “base_url”
If the “base_path” option of the wiki is not set, set it to the base url.
  It will make links work seamlessly when mounting to a relative url.
2012-07-24 23:46:22 +02:00
bootstraponline f811ac510e Improve names. Fix #447. 2012-07-22 21:04:02 -06:00
bootstraponline 3e5054f357 Call to_url on rename to prevent invalid renames.
Remove to_url on delete so invalid names can be deleted.
Handle nil in to_url.
Update tests.
2012-07-22 13:45:30 -06:00
bootstraponline 3424a424a7 Add /delete test. 2012-07-22 13:25:25 -06:00
bootstraponline 8eb8af8ef8 Use old name default text on rename. 2012-07-21 21:00:14 -06:00
bootstraponline 8eaf7fc497 Remove msg. 2012-07-21 16:57:20 -06:00
bootstraponline 3255709399 Don't mess with the commit message. 2012-07-21 16:52:18 -06:00
bootstraponline 2dbea36b81 Add rename button. Fix #444. 2012-07-21 16:31:38 -06:00
bootstraponline e0b7009bff Add delete this Page based on .com.
Match short sha commit message of .com for edit and delete.
Update tests.
2012-07-21 15:33:43 -06:00
Vicent Marti 77fb5ec3cb Fix parsing extra whitespace in code blocks 2012-07-21 15:34:56 +02:00
bootstraponline 7392bce5dc Restore livepreview.
Improvements include:
- UTF-8 aware
- Undo and redo support
- Code highlighting fixes
- New tests ensure output matches native sundown

Use jquery 1.7.2
2012-07-18 18:11:19 -06:00
bootstraponline 8188bbd35d Add mousetrap. 2012-07-18 18:03:26 -06:00
bootstraponline 80fdea7bfb Fix #437.
Add hotkey support using mousetrap.
2012-07-18 14:17:50 -06:00
bootstraponline dc9f6ac709 Display to_url name on create. 2012-07-18 12:29:03 -06:00
bootstraponline ba796bc23d Comment out test. See #363. 2012-07-18 10:35:53 -06:00
bootstraponline e0ecb4c44f Fix #435. 2012-07-17 15:29:34 -06:00
bootstraponline d4c05304e9 Fix #434. 2012-07-17 15:22:37 -06:00
bootstraponline ccdbd71517 Fix style. 2012-07-17 11:19:54 -06:00
bootstraponline 454fce09c6 Merge pull request #441 from haad/upstream-gollum-path
Add --gollum-path [PATH].
2012-07-17 10:15:32 -07:00
bootstraponline be4b12b4c8 Use .times.
Fix style.
2012-07-17 11:12:59 -06:00
bootstraponline 9fa629de31 Use range instead of upto. 2012-07-17 11:01:52 -06:00
bootstraponline 78dd5774b3 Fix code style. 2012-07-17 10:55:57 -06:00
bootstraponline bb9a9cd0db Merge pull request #440 from haad/upstream
Add support for multi-level directory setups, where files are under mult...
2012-07-17 09:46:34 -07:00
Adam Hamsik ab9d8fb3db Add option to define gollum path from command line. This way we can use different git repo for wiki files and different repo for
gollum.
2012-07-17 15:25:55 +02:00
Adam Hamsik 6ce76af2be Fix tests. 2012-07-17 12:00:42 +02:00
Adam Hamsik 3199a4b2cb Remove debug puts. 2012-07-17 11:10:09 +02:00
Adam Hamsik 6a2d153c3d Add support for multi-level directory setups, where files are under multiple directories.
Generate HTML for them properly.
2012-07-17 11:06:04 +02:00
bootstraponline bfd4ad9255 Async loading of MathJax.
http://calendar.perfplanet.com/2011/the-art-and-craft-of-the-async-snippet/
2012-07-13 14:25:53 -06:00
bootstraponline 30224515fd Update table style to match .com. 2012-07-13 14:11:10 -06:00
bootstraponline d7f3acfd05 Disable live preview until a robust JavaScript based markdown parser is found. 2012-07-13 00:42:26 -06:00
bootstraponline a9e9eeeb54 Another encoding fix from #387. 2012-07-12 12:06:47 -06:00
bootstraponline 76fa52b313 Merge pull request #387 from arr2036/fix_encoding
Work around Grit encoding issues.
2012-07-12 11:03:19 -07:00
bootstraponline 67de8e6a3a Fix to_url so it correctly handles _Header, _Footer, and _Sidebar. 2012-07-11 20:10:59 -06:00
bootstraponline ff78998829 30px height. 2012-07-11 16:12:27 -06:00
bootstraponline 55786e2d29 Uninstall old gollum before installing the new gem. 2012-07-11 10:35:37 -06:00
bootstraponline 20534a71b9 Remove New Page from file view. 2012-07-11 10:23:01 -06:00
bootstraponline 316b6feccb Write_page changes not yet merged. 2012-07-10 11:46:00 -06:00
bootstraponline 6c7417e0a2 Add transliteration test. 2012-07-10 11:40:36 -06:00
bootstraponline af89dc881e Merge pull request #424 from bootstraponline/unicode_to_ascii
Ensure page file names are ASCII.
2012-07-10 09:52:57 -07:00
bootstraponline 5714cef3de Page names are no longer case sensitive. 2012-07-10 10:47:15 -06:00
bootstraponline 3d2c8e7cc5 ASCII only filenames.
Fix test_unicode.
2012-07-10 10:41:55 -06:00
bootstraponline 772ffcc5e8 Ensure ascii only filenames. Fix #423. 2012-07-09 13:22:45 -06:00
bootstraponline 8c30bb3a9f Merge pull request #422 from nature/sidebar_rendering_in_subfolders
Sidebar rendering in subfolders.
2012-07-09 09:19:11 -07:00
bootstraponline 89bc121d3f Merge pull request #421 from nature/create_new_page_in_subdir
Make the 'New Page' button create pages in sub directories.
2012-07-09 09:15:42 -07:00
Darren Oakley 1cc9d7b647 Slight optimisations...
- only create a new GitAccess object if the wiki does not have a @page_file_dir directive
- memoize the new GitAccess object
2012-07-09 13:01:40 +01:00
Darren Oakley 50e494e8e9 Make pages inherit their sidebar/header/footer from parent directories regardless of the current 'page_file_dir' of the wiki. refs #413 (https://github.com/github/gollum/issues/413) 2012-07-09 12:10:41 +01:00
Darren Oakley 19325930a2 Add a new file and sub-directory - 'Rivendell/Elrond.md' so we can test Sidebar/Header/Footer inheritance from parent directory. 2012-07-09 11:50:08 +01:00
Darren Oakley ac97f7e9a2 Make the 'New Page' button create pages in sub directories if the user puts a slash in the path/page name. 2012-07-09 10:41:51 +01:00
bootstraponline 33f133b8b2 Livepreview is 102KB again.
java -jar compiler.jar --compilation_level WHITESPACE_ONLY --js sundown_o2_m0.js --js_output_file sundown_o2_wo.js

MKDEXT_SUPERSCRIPT extension disabled to match .com behavior (also fixes MathJax).
2012-07-06 23:26:12 -06:00
bootstraponline 2e9995e80a Use sundown_o2_m0. Fix #415. 2012-07-06 16:20:53 -06:00
bootstraponline 53f676bf2e Do not load data on github.com. 2012-07-06 12:21:55 -06:00
bootstraponline 874d658d2a Ace is broken on Safari 6. Fix #414. 2012-07-06 12:01:45 -06:00
bootstraponline d27c455ab7 Update sundown. 2012-07-05 12:01:09 -06:00
bootstraponline 9291431c61 Fix #413. 2012-07-04 12:24:35 -06:00
bootstraponline 2e5f51e9ae Update comment. 2012-07-04 11:20:38 -06:00
bootstraponline 2aa7e466ed File view links use '-' instead of %20. 2012-07-04 11:04:51 -06:00
Jeremy McAnally 3767a11d21 Rename variables to be more clear and fix reference to non-existent 'ext' variable 2012-07-04 12:33:09 -04:00
bootstraponline 8c8b72d482 Restore path support to livepreview.js. 2012-07-03 23:55:28 -06:00
bootstraponline bb9effa282 Prevent wrapping on long file names.
Fix formatting.
2012-07-03 20:41:14 -06:00
bootstraponline 52e96bfa0f Detect typed array support based on user agent.
http://caniuse.com/typedarrays
2012-07-03 15:26:40 -06:00
bootstraponline 00ded65b7f Fall back to old edit mode if typed arrays are not supported. 2012-07-03 14:47:27 -06:00
bootstraponline f738aa4234 Disable ie 9 live preview support for now. 2012-07-03 14:19:27 -06:00
bootstraponline 6ff939451c Update livepreview.
Update ace.
Replace pagedown with sundown. Live preview is now able to render markdown identical to regular gollum by leveraging the same library.

Thanks to @kripken for explaining how to best use emscripten for sundown.
2012-07-03 13:55:08 -06:00
bootstraponline 32930cee01 extract_path fails on nil paths. 2012-07-03 10:55:42 -06:00
bootstraponline 3f45c76f48 Extract path on edit. Fix #410. 2012-07-03 10:53:18 -06:00
bootstraponline 1511baf12d Restore Home.md. 2012-07-02 10:37:46 -06:00
bootstraponline 20dd0816a6 Revert "Merge pull request #379 from pipex/latex-dollar-sign"
This reverts commit b53c961db2, reversing
changes made to 9c40cbea76.
2012-07-02 10:27:30 -06:00
bootstraponline 41cd43ebc6 Updated Home (markdown) 2012-07-02 10:18:40 -06:00
Sunny Ripert 4a63899722 Livepreview JavaScript fix for base_url 2012-07-02 15:03:01 +02:00
Sunny Ripert c31ead493a Fixed tests to make up for base url 2012-06-28 17:31:19 +02:00
Sunny Ripert 7485733fba Sinatra base url to allow subdirectories 2012-06-28 17:31:19 +02:00
bootstraponline e930b5d07b Merge pull request #390 from arr2036/app_rest_fix
App rest fix.
2012-06-26 13:27:57 -07:00
Arran Cudbard-Bell 4543781153 Add tests to check page redirects to create 2012-06-24 22:41:27 +01:00
Arran Cudbard-Bell 1d5bfbb162 Add URL for page creation to allow preemption by extensions 2012-06-24 22:41:27 +01:00
bootstraponline 7045f7f92d Fix searching for page titles. 2012-06-22 16:04:57 -06:00
bootstraponline 5e7974f30b Fix file ext removal.
a = '/.md/home.md'

a.chomp(File.extname(a))
=> "/.md/home"

a.gsub(File.extname(a),'')
=> "//home"
2012-06-22 11:45:42 -06:00
bootstraponline 1079a888d3 nil.to_i == 0 2012-06-22 11:28:34 -06:00
bootstraponline b1837abbc2 Fix nil error in search. 2012-06-22 11:24:13 -06:00
bootstraponline 611e1a536c Merge pull request #403 from trans/file
Add Wiki#files for list of non-page files.
2012-06-22 09:59:31 -07:00
bootstraponline c152ae1557 Merge pull request #401 from nature/make_gollum_search_count_additive
Update the Wiki.search function to make the results counts 'additive'.
2012-06-22 09:49:04 -07:00
bootstraponline de3020c1aa Merge pull request #400 from nature/new_page_within_dir
Add a 'New Page' button to the /pages browser.
2012-06-22 09:48:23 -07:00
trans f12c3fe06f Fix docs for File#populate. 2012-06-22 08:45:57 -04:00
trans 754485c306 Add Wiki#files for list of non-page files. 2012-06-22 08:23:46 -04:00
Darren Oakley 088448a8a1 Update the Wiki.search function to make the results counts 'additive'.
i.e. so if we have a file named 'foo' that also contains the word 'foo' is should report 2 matches, not 1.
2012-06-22 12:01:39 +01:00
Darren Oakley 6e35a09abd Add a 'New Page' button to the /pages browser that allows users to create a new page within a subdirectory. 2012-06-22 11:41:42 +01:00
bootstraponline 8fd11e8fdb Fix #396.
Use ls-files to search file names (which define the page title).
2012-06-21 19:18:46 -06:00
bootstraponline 40855103ad Disable failing test. 2012-06-21 17:26:19 -06:00
bootstraponline 02041dbdb7 Work around #363 (grit is broken). 2012-06-21 16:45:38 -06:00
bootstraponline 18ccc01501 Remove #head boarder in /pages because it's now defined by .breadcrumb. 2012-06-21 13:16:34 -06:00
bootstraponline 1ff3f9c0da Merge pull request #393 from nature/dir_support
Add Directory Support.
2012-06-21 09:39:12 -07:00
Darren Oakley 7a251248f1 Re-work the compare URL matchers so that CGI escaping etc shouldn't be so needed. 2012-06-21 15:59:10 +01:00
Darren Oakley 971cbb94f6 Make the Sinatra app directory aware. 2012-06-21 15:59:01 +01:00
bootstraponline b53c961db2 Merge pull request #379 from pipex/latex-dollar-sign
[New] Support `$` and `$$` as formula delimiters.
2012-06-19 13:22:49 -07:00
bootstraponline 9c40cbea76 Merge pull request #377 from pipex/latex-align
[Fix] Inline latex formula alignment
2012-06-19 13:22:26 -07:00
bootstraponline a8ce7e93cd Enable MathJax for live preview. 2012-06-19 11:58:09 -06:00
bootstraponline 4b02b74d6f Fix #389.
Set page name correctly on preview.
2012-06-19 10:59:24 -06:00
Arran Cudbard-Bell 67dd3afd92 Fix for 1.8 versions of ruby 2012-06-19 15:33:47 +02:00
bootstraponline 7aca7fa0ec Update Ace. 2012-06-18 12:32:27 -06:00
bootstraponline c0564a1467 Update readme. 2012-06-18 12:32:14 -06:00
bootstraponline b0a8984d3b Update livepreview for new Ace. 2012-06-18 12:31:30 -06:00
bootstraponline 0f451d6833 Fix #386. File view defines its own layout. 2012-06-18 10:54:14 -06:00
Arran Cudbard-Bell c704d1f3b3 Hacky fix for encoding issues 2012-06-18 09:44:20 +02:00
bootstraponline e6d568fd49 Merge pull request #385 from bootstraponline/sequence_no_conflict
Fix #376.
2012-06-17 15:20:19 -07:00
bootstraponline ee56509302 Fix #376.
New syntax for sequence diagrams is {{{{{{ }}}}}}.
2012-06-17 16:11:59 -06:00
bootstraponline bc5896b51f Update readme. 2012-06-17 16:01:48 -06:00
bootstraponline 3224f5f422 Document building the gem from master.
[ci skip]
2012-06-16 12:17:13 -06:00
Felipe Lalanne f9cd97edaa [Fix] Replaced random escaping of $
The `$` symbol is now escaped by replacing it with a static string.
2012-06-11 20:18:22 +02:00
bootstraponline e1ce3d46de Fix location for live preview. 2012-06-11 10:07:17 -06:00
Felipe Lalanne 294a8e9642 [New] Support $ and $$ as formula delimiters.
Although the standard formula delimiters for latex formulas is currently
`\(` and `\[`, the `$` syntax has an advantage from the point of view of
writing speed, very important if we intend to use *gollum* as a writing
tool.

The code includes support for escaping of the `$` symbol by using the
gollum syntax `'`.
2012-06-11 12:06:54 +02:00
Felipe Lalanne 44fb6d9648 [Removed] Unnecessary require 'time' line. 2012-06-11 11:39:37 +02:00
Felipe Lalanne 74c1ba1653 [Fix] Inline latex formula alignment
Fixed an issue of latex inline formulas not aligning correctly with
the text. The fix is a ruby translation of the Perl code described in
http://tex.stackexchange.com/questions/44486/pixel-perfect-vertical-alignment-of-image-rendered-tex-snippets.
This code calculates the alignment of the generated image depending on
the image size and the size of the white space between the formula and
the margins of the image.

The alignment now is nearly perfect, however the new rendering comes
with a performance impact because of the increased number of operations.
To reduce this impact, the generated images and calculated values for
the alignment are now cached in `~/.cache/gollum`. The caching is done
per formula and not per page, thus avoiding caching the same formula
twice.

The Readme and tests have been modified accordingly with the new tool
requirements and expected markup.
2012-06-11 11:25:25 +02:00
bootstraponline 0cb39f049f Fix IE check. 2012-06-08 16:57:19 -06:00
bootstraponline f7a3a8aa55 Live preview supports IE 9. 2012-06-08 16:54:28 -06:00
bootstraponline cbc37eb006 Fix live_preview option #374. 2012-06-08 16:39:44 -06:00
bootstraponline 097f45eeb3 Use Ace for code highlighting.
Update Ace.
Fix CSS for new Ace.
Prevent flickering of toolpanel.
Add GitHub theme for Ace.
Remove gutter in static highlight ext.
Update languages for Ace.
2012-06-08 15:50:20 -06:00
bootstraponline 4c5b3dd76f Remove highlightjs.
Remove old Ace.
2012-06-08 15:49:05 -06:00
bootstraponline ccf70590a4 Merge pull request #374 from arr2036/optional_livepreview
Optional livepreview
2012-06-07 09:08:58 -07:00
Arran Cudbard-Bell 3c709a27ac Add commandline option for disabling livepreview 2012-06-07 18:05:15 +02:00
Arran Cudbard-Bell 8554654ee9 Add option to disable livepreview from settings 2012-06-07 11:30:30 +02:00
bootstraponline 59ac86cf6e Add header example to readme. 2012-06-05 15:56:02 -06:00
bootstraponline a4ecc9a187 Merge pull request #371 from bootstraponline/searchfix
Search fix (#348 with assert_not_match replacement).
2012-06-03 15:42:21 -07:00
bootstraponline cc67c8b68e Don't use assert_not_match. 2012-06-03 16:37:47 -06:00
bootstraponline b41f660fec Merge pull request #358 from blmarket/koreanfix
Use grit with force_encoding('ascii-8bit')
2012-06-03 15:00:37 -07:00
bootstraponline 00edcbbf64 Move build status to top of readme. 2012-06-03 15:56:29 -06:00
bootstraponline c530c70575 Add tests for file_view. 2012-06-03 15:53:11 -06:00
bootstraponline 21840bb344 Remove debug code. 2012-06-03 14:00:50 -06:00
bootstraponline 57bc23779d Merge pull request #370 from cholick/master
File View doesn't work when there's a single subdirectory
2012-06-03 12:41:23 -07:00
Matt Cholick (phenom2-desktop) 78e649f30a fix for broken file view when only a single directory 2012-06-03 11:56:18 -05:00
blmarket eaa7a61f71 Fixed 1.8.7 compatible issue 2012-05-31 21:27:27 +09:00
Neon 150a019b8d Added test cases to test Unicode handling issue.
these test cases will fail on non-unicode testing environment
2012-05-31 20:14:21 +09:00
Jeong, Heon 5dd1158025 Use grit with force_encoding('ascii-8bit') 2012-05-31 20:14:21 +09:00
bootstraponline c60ca4a8d2 Merge pull request #367 from bootstraponline/browser_fallback
Enable live preview only for supported user agents.
2012-05-29 17:35:01 -07:00
bootstraponline e1b28f0805 Rename is_supported to supported_useragent?. 2012-05-29 18:28:19 -06:00
bootstraponline aeeaeb1eae Fall back to old edit mode for browsers that are not officially supported by Ace. 2012-05-29 16:32:39 -06:00
Corey Donohoe 76f87f9094 stay on 1.8.7 for the foreseeable future
Settles #365 for now
2012-05-28 10:55:59 -07:00
bootstraponline 01e1c92813 Add --base-path option. 2012-05-24 20:45:33 -06:00
bootstraponline 22c0206451 Call page.versions once. 2012-05-24 18:32:45 -06:00
bootstraponline 5173c258b7 Merge pull request #354 from bootstraponline/mathjax
Add MathJax (only for gollum, not github.com).
2012-05-24 16:24:44 -07:00
bootstraponline ff8b892ebe Add mathjax using SSL CDN. 2012-05-24 17:18:55 -06:00
bootstraponline 7b0988cc19 Remove empty line. 2012-05-24 17:10:05 -06:00
bootstraponline a4c79f09f8 Gem uninstall does not require sudo (pointed out by @michaelklishin). 2012-05-24 16:48:54 -06:00
bootstraponline 7ec3d92215 Merge pull request #361 from github/travis-fixes
nuke the ffi gem on travis boxes
2012-05-24 15:43:21 -07:00
Corey Donohoe ac9fef784a nuke the ffi gem on travis boxes
/cc @bootstraponline @akzhan
2012-05-24 15:31:54 -07:00
bootstraponline 4822bad4fb Merge pull request #355 from bootstraponline/author_fix
Fix author info (based on #350).
2012-05-23 11:40:26 -07:00
bootstraponline d7dd90f073 Update README.md 2012-05-23 11:12:29 -06:00
Neon bbc19d1800 Added testcase for 'open existing parent' 2012-05-24 00:04:45 +09:00
Jeong, Heon 9ee9e61312 Fix searching in page_dir if it exists
This bug can cause DuplicateError even there is no such file

in page_dir
2012-05-23 23:58:54 +09:00
bootstraponline f765137f3f Avoid nil. 2012-05-23 00:04:57 -06:00
bootstraponline e160822b0f Only use versions. 2012-05-22 23:48:56 -06:00
bootstraponline c0e35b0126 Avoid nil. 2012-05-22 23:03:23 -06:00
bootstraponline ac41ed629e Merge modified #350. 2012-05-22 22:46:15 -06:00
Kristi 8b5dfff2a1 Merge pull request #343 from kristi/toc
Table of contents feature
2012-05-22 13:14:25 -07:00
kristi e77154bf7a Merge remote-tracking branch 'upstream/master' into toc 2012-05-22 12:14:03 -07:00
kristi 5f5187e05c Only set parentpage if a subpage was found
Fixes error if there's no header or footer
2012-05-22 11:55:02 -07:00
bootstraponline 5db1728a3f Use org-ruby 0.6.3. Fixes #86. 2012-05-22 09:49:11 -06:00
bootstraponline c7984ceed1 Revert "Merge pull request #350 from blmarket/pageauthor"
This reverts commit 5d3571b7a3, reversing
changes made to c1082b4474.
2012-05-21 17:09:15 -06:00
bootstraponline 5d3571b7a3 Merge pull request #350 from blmarket/pageauthor
Proper last edit info (with test case)
2012-05-21 16:00:15 -07:00
bootstraponline c1082b4474 Fix click. 2012-05-21 10:39:11 -06:00
bootstraponline 14f16349c0 Remove unload on save. 2012-05-21 10:35:29 -06:00
bootstraponline aa7e01a085 Add unload confirmation on live preview, edit, and create. 2012-05-21 10:27:16 -06:00
bootstraponline 484629734e Update README.md 2012-05-21 10:17:05 -06:00
bootstraponline 444fca2250 Revert changes to Home. 2012-05-21 10:02:55 -06:00
bootstraponline 7f17102c86 Remove home.md. 2012-05-21 10:00:06 -06:00
bootstraponline e480998a4c Merge pull request #345 from bootstraponline/file_view
Add file view.
2012-05-21 08:58:14 -07:00
bootstraponline 5c642997fe Origin is undefined in Firefox. 2012-05-21 09:50:23 -06:00
bootstraponline 5be5cd5ba5 Updated Home (markdown) 2012-05-21 09:49:22 -06:00
bootstraponline 1d55ed0599 Updated Home (markdown) 2012-05-21 09:49:12 -06:00
bootstraponline 4380aa9803 Updated Home (markdown) 2012-05-21 09:45:39 -06:00
bootstraponline 66e7f240da Updated Home (markdown) 2012-05-21 09:45:14 -06:00
bootstraponline f3e5816547 Updated Home (markdown) 2012-05-21 09:45:08 -06:00
bootstraponline 3d5931c259 Updated Home (markdown) 2012-05-21 09:44:52 -06:00
bootstraponline d510c74456 Updated Home (markdown) 2012-05-21 09:44:27 -06:00
bootstraponline 7154220d0b Updated Home (markdown) 2012-05-21 09:44:19 -06:00
bootstraponline d5155273df Move script tags to bottom. Refactor livepreview logic into livepreview.js. 2012-05-20 12:34:32 -06:00
Jeong, Heon 60dbe9d0a7 Proper last edit info
but it can be slow if page modified so many times
2012-05-20 12:37:10 +09:00
bootstraponline f7d3f6b3f0 Don't wait for onload. 2012-05-18 15:57:41 -06:00
bootstraponline 40fdd2aa74 Adjust save text. 2012-05-18 15:49:57 -06:00
bootstraponline f39ed93ca0 Use default commit message in comment window. 2012-05-18 15:32:14 -06:00
bootstraponline 541b2fabb4 Add new page button to file view action panel. 2012-05-18 15:00:23 -06:00
bootstraponline 067ad72f34 Update icon license. 2012-05-18 13:12:14 -06:00
bootstraponline 6c137e39c9 Add file view button. 2012-05-18 13:05:08 -06:00
bootstraponline f8c6cdb207 Add license for css tree menu. 2012-05-18 12:11:55 -06:00
bootstraponline f5de6a809d Remove name2 now that name is fixed. 2012-05-18 12:09:42 -06:00
bootstraponline e36b96fca6 Remove comments. 2012-05-18 12:01:43 -06:00
bootstraponline cd1738bdf6 Fix file names. 2012-05-18 12:00:43 -06:00
bootstraponline ebcd30fadc Add file view. 2012-05-18 11:50:38 -06:00
bootstraponline 3c10a6bf94 Set focus when toggling comment window. 2012-05-18 11:08:27 -06:00
bootstraponline dc80fd9b15 Remove old comments. 2012-05-18 10:39:52 -06:00
bootstraponline 5d21df9ac7 Fix css href. 2012-05-18 10:38:27 -06:00
bootstraponline 019e912d7f Fix comment button. 2012-05-18 10:35:42 -06:00
bootstraponline 3479dca0d0 Add comment window using Ace that allows user entered commit messages.
Use darkness div to dim the background when the comment window is active.
Set CSS in batch to avoid unnecessary reflows.
Use debouncing to efficiently resize the window.
Eliminate previewSetter in favor of redefining the previewSet function.
2012-05-18 10:28:59 -06:00
bootstraponline 32e5cc4a5a Add debounce. 2012-05-18 10:27:01 -06:00
bootstraponline 268a9f18fa Update readme. 2012-05-18 10:24:14 -06:00
bootstraponline 16a6186570 Add icon for save with comment in live preview. 2012-05-17 16:00:09 -06:00
bootstraponline 4b2fb6dd11 Add default commit messages when using gollum editor. 2012-05-17 15:17:24 -06:00
bootstraponline 67d21bcd64 Fix location. 2012-05-17 12:44:28 -06:00
bootstraponline 9b87126f0f Generate commit messages when using live preview. 2012-05-17 12:40:27 -06:00
Corey Donohoe 1043b4de70 Revert "Merge pull request #338 from jroes/resize-sha1s"
This reverts commit 4bc5e7b8ff, reversing
changes made to 423b5205bf.
2012-05-16 12:48:16 -07:00
Corey Donohoe 4bc5e7b8ff Merge pull request #338 from jroes/resize-sha1s
Fit generated SHA1 placeholders to original length.
2012-05-16 12:15:40 -07:00
bootstraponline 423b5205bf Fix language detection. 2012-05-15 11:49:55 -06:00
bootstraponline fde288d9e8 Guess highlight rules for code blocks to match gollum behavior. 2012-05-15 11:48:48 -06:00
bootstraponline f2a2d85008 Preserve whitespace in gollum code blocks. 2012-05-15 11:20:01 -06:00
bootstraponline 3a91b076e1 Fix gollum code blocks. 2012-05-15 11:06:36 -06:00
bootstraponline 27bd608b53 Update live preview title. 2012-05-15 10:37:38 -06:00
bootstraponline 966ba29084 Fix gollum style code blocks. 2012-05-15 10:12:32 -06:00
bootstraponline 3ea5b0193c Fix sanitizer to whitelist h1-6. 2012-05-15 09:59:15 -06:00
kristi 97dd1b3b00 Fix toc test 2012-05-14 17:01:39 -07:00
kristi fe0088d1ae Add TOC to readme file 2012-05-14 16:12:20 -07:00
kristi 342e1e22f8 Change link icon 2012-05-14 15:54:46 -07:00
kristi c9203047fc Make universal toc pretty too 2012-05-14 13:07:57 -07:00
kristi a3a946ccd6 Remove toc.rb; markup.rb handles toc processing 2012-05-14 13:06:46 -07:00
kristi 22564f34a9 Merge remote-tracking branch 'upstream/master' into toc 2012-05-14 10:44:50 -07:00
kristi f939c24aa4 Clear floats for footer 2012-05-14 10:25:31 -07:00
kristi be93fa747b Make TOC pretty. Also put in "[[_TOC_]]" stub for viewing sub-page directly 2012-05-14 10:23:12 -07:00
kristi d7f4eeea2c Merge remote-tracking branch 'upstream/master' into toc
Conflicts:
	lib/gollum/frontend/app.rb
	lib/gollum/markup.rb
	test/test_markup.rb
2012-05-14 09:12:44 -07:00
kristi 6191f60025 Fix tests for added example repo pages 2012-05-14 02:01:33 -07:00
kristi 82ccb0cedb add documentation comment 2012-05-14 02:01:06 -07:00
kristi eb92e4413a Add header files and TOC test files 2012-05-14 01:28:03 -07:00
kristi b0ba205532 Remove :header_hashtags option and adjust tests 2012-05-14 00:38:27 -07:00
kristi 4fa2cdf8d9 Allow sub pages to use the [[_TOC_]] tag 2012-05-13 22:19:55 -07:00
kristi ae30b23d34 insert a comment if no TOC headers found 2012-05-13 18:48:02 -07:00
kristi 1d3905bb71 Use special tag [[_TOC_]] to insert a table of contents 2012-05-13 12:44:20 -07:00
kristi aa1e845f9a create process_headers function to add anchors and create toc 2012-05-13 10:21:50 -07:00
Jonathan Roes fbcc69ec67 Tell Travis that the tests now depend on docutils. 2012-05-12 21:47:31 -04:00
Jonathan Roes 68b2de6dd7 Fit generated SHA1 placeholders to original length. 2012-05-12 21:05:42 -04:00
bootstraponline 20389babbc Merge pull request #336 from jroes/remove-links-in-code
Remove links in code, fixes #128.
2012-05-12 14:48:41 -07:00
Jonathan Roes f9899033aa Before replacing tags, ensure the SHA1 is not within preformatted content. 2012-05-12 17:29:23 -04:00
Jonathan Roes eb37b17486 Remove links in code, fixes #128. 2012-05-11 22:49:26 -04:00
bootstraponline c428cad286 Remove marker on no highlight pre tags. 2012-05-11 15:05:05 -06:00
kristi 26486da27b Use correct wiki option 2012-05-11 13:41:03 -07:00
kristi cabd0ed85e Add tests for new universal_toc and header_hashtags wiki options 2012-05-11 13:27:43 -07:00
kristi f53e1a60d5 Fix tests by adding a default_options hash to the wiki 2012-05-11 12:51:04 -07:00
kristi ec694e4a99 Fix option setting 2012-05-11 12:50:34 -07:00
Corey Donohoe 81e076c924 gemspec upgrade 2012-05-10 14:12:45 -07:00
Corey Donohoe 04070ffc23 bump gollum version 2012-05-10 14:12:36 -07:00
bootstraponline 6941d6b863 Restore title now that #308 is merged using github.com css. 2012-05-10 13:35:33 -06:00
bootstraponline 3c88f68f16 Fix relative links in live preview. 2012-05-10 12:25:26 -06:00
bootstraponline 82461da704 Merge pull request #334 from Skookum/selected-links
Grab selected text and use it as the default text when creating links.
2012-05-10 10:23:52 -07:00
Mark Rickert 8e5d17c907 Grab selected text and use it as the default text when creating links. 2012-05-10 13:16:52 -04:00
Tim Harvey 43d2143506 Redirect from root to /Home, fixes #250 2012-05-10 08:55:56 -04:00
kristi 28b729acda Add in some minimal documentation for wiki options 2012-05-10 00:38:35 -07:00
kristi 584641236b fixup toc/anchor code in markup.rb 2012-05-10 00:34:35 -07:00
kristi ca74897569 Add header_hashtag feature option: headers display a link icon when moused over so you can jump to sections
Move anchor processing into markup.rb
Use dashes for spaces in the anchor hashtag
2012-05-10 00:26:22 -07:00
kristi 61987c85d2 Add universal_toc wiki option 2012-05-09 16:13:53 -07:00
bootstraponline cfb75abeed Remove test file. 2012-05-09 16:27:59 -06:00
bootstraponline fd32706f0b Use pre tag for code in live preview. 2012-05-09 16:15:48 -06:00
bootstraponline d1f90b7d44 Merge branch 'master' of github.com:github/gollum 2012-05-09 16:09:30 -06:00
kristi f09bc4a81a Fix editor bug - displaying wrong version of header/footer/sidebar
Use most recent version; not the version matching the page
2012-05-09 15:04:29 -07:00
bootstraponline 31b3aea282 Merge branch 'master' of github.com:github/gollum 2012-05-09 14:36:37 -06:00
bootstraponline 2e1d236e8e Enable previewframe scrolling. 2012-05-09 14:36:20 -06:00
kristi 065d06a98f Move toc calling code out of app; put in Page.toc_data
Page stores the formatted document parsed by Nokogiri
2012-05-09 13:33:54 -07:00
kristi 63107566ec add Toc to Gollum 2012-05-09 13:33:08 -07:00
bootstraponline 4f1dcea806 2012-05-09 14:28:32 -06:00
bootstraponline 5da1a2c611 2012-05-09 14:28:20 -06:00
bootstraponline 180a214e1f Merge pull request #311 from bootstraponline/livepreview
Live Preview.
2012-05-09 13:24:12 -07:00
kristi bb417c6975 Rename class to Toc 2012-05-09 12:18:24 -07:00
kristi 75c02475be Remove extensions namespace 2012-05-09 12:14:45 -07:00
bootstraponline 2fd07211d9 Update README.md 2012-05-09 12:06:05 -06:00
bootstraponline 128f3be596 Use template.css 2012-05-09 10:56:52 -06:00
bootstraponline 810333dbb7 Update link CSS to match github.com. 2012-05-09 10:24:12 -06:00
bootstraponline e465358ec0 Add Ubuntu asciidoc install commmand. 2012-05-09 10:03:38 -06:00
bootstraponline 2954ed84a0 Merge pull request #327 from arr2036/master
Pass :is_bare to Grit where appropriate.
2012-05-09 08:57:18 -07:00
Arran Cudbard-Bell b36cd8a68e Pass through :is_bare option from wiki_options, allows Gollum to work with gitolite 2012-05-09 16:12:00 +02:00
Arran Cudbard-Bell 8435daa598 Stop anchor highlighting 2012-05-09 15:37:42 +02:00
Arran Cudbard-Bell 38c943d564 Add supporting modifications to frontend and css 2012-05-09 15:07:01 +02:00
Arran Cudbard-Bell 8e89ec504f Initial commit of Nokogiri based TOC generator 2012-05-09 14:06:17 +02:00
Kristi a692ec1124 Merge pull request #326 from kristi/frontend-tweak
Frontend tweak: Add header to editor, small fixup for asciidoc css, add spacing to headers
2012-05-08 17:25:26 -07:00
kristi 4e5f2c9587 Add header to editor 2012-05-08 17:29:28 -07:00
kristi 1cc263acfb Make footer editor font normal sized 2012-05-08 17:22:39 -07:00
kristi 49c6534da6 Put asciidoc fix into template with the rest of the markup css
Also remove padding from the asciidoc code block so first line doesn't get indented
2012-05-08 17:11:02 -07:00
bootstraponline 02d3a3d7ec Clarify gemspec task desc. 2012-05-08 16:36:44 -06:00
kristi 1dbe49243c Give headers more headroom 2012-05-08 15:03:15 -07:00
kristi 2c12fb7ae8 Add missing semicolons 2012-05-08 15:02:52 -07:00
kristi 829c6debbd Merge remote-tracking branch 'upstream/master' into frontend-tweak 2012-05-08 14:58:32 -07:00
bootstraponline f2d3ed322e Merge pull request #325 from bootstraponline/ascii_css
Fix AsciiDoc CSS.
2012-05-08 12:40:57 -07:00
bootstraponline d90e7db497 Fix #278. 2012-05-08 13:39:21 -06:00
Corey Donohoe 26f372a36a this works on 1.9.3 now too 2012-05-08 12:25:03 -07:00
bootstraponline b037777f83 Fix spacing. 2012-05-08 13:18:46 -06:00
bootstraponline 35ce35b1e0 Default to empty edit window. 2012-05-08 13:15:09 -06:00
bootstraponline e1517c2907 Merge with upstream. 2012-05-08 13:13:36 -06:00
bootstraponline ed5f88daa0 Remove unused local var. 2012-05-08 13:05:49 -06:00
bootstraponline 4afda646f0 Merge pull request #324 from bootstraponline/windowsNote
Add windows filename invalid characters notice to readme.
2012-05-08 11:36:41 -07:00
bootstraponline e782538777 Add windows filename invalid notice to readme. 2012-05-08 12:17:36 -06:00
Corey Donohoe 4e86be86d9 Merge pull request #323 from kristi/frontend-tweak
Fix HR background
2012-05-07 21:22:29 -07:00
kristi 6c8cfcd7c2 Make code border darker 2012-05-07 20:47:04 -07:00
kristi 9fc7929665 uniform spacing for css 2012-05-07 20:47:04 -07:00
kristi d590bf7d64 Add images from github 2012-05-07 20:47:04 -07:00
kristi c0f653340e Fix urls 2012-05-07 20:47:04 -07:00
Corey Donohoe ac2bef083b Merge pull request #322 from kristi/header-feature
Header feature
2012-05-07 20:42:14 -07:00
kristi 42c7d0ca44 Fix crazy spacing (sorry, git blame, I couldn't stand it any longer) 2012-05-07 20:35:28 -07:00
kristi 8a8afcfb24 Put gray background on header, fix footer font size 2012-05-07 20:28:07 -07:00
kristi 5d259bb5aa Use markdown css formatting for header and footer 2012-05-07 20:09:59 -07:00
Corey Donohoe d2a24ed4bc Merge pull request #321 from bootstraponline/cleanUp
Remove unused local var.
2012-05-07 15:04:04 -07:00
bootstraponline efd2f49484 Remove unused local var. 2012-05-07 15:37:24 -06:00
Corey Donohoe 9d4d6ccca5 Merge remote-tracking branch 'bootstraponline/gollum2'
/cc @kristi is the css behaving on this? we had minor markup conflicts

Conflicts:
	lib/gollum/frontend/templates/page.mustache
2012-05-07 14:10:38 -07:00
Aman Gupta 218c894b5a Merge pull request #319 from bootstraponline/looseObject
Fix LooseObjectError by upgrading to grit 2.5.
2012-05-07 13:29:21 -07:00
bootstraponline 0dec522542 Fix LooseObjectError by upgrading to grit 2.5. See https://github.com/mojombo/grit/issues/65 2012-05-07 14:26:48 -06:00
bootstraponline 7fa6708483 Add _Header.md to revert.git. 2012-05-07 14:17:15 -06:00
kristi 33af47c282 Make code border darker 2012-05-07 00:22:24 -07:00
kristi 6b971e9e1b uniform spacing for css 2012-05-07 00:22:24 -07:00
kristi 50107504a6 Add images from github 2012-05-07 00:22:23 -07:00
kristi 2cb0c9fea6 Fix urls 2012-05-07 00:22:23 -07:00
Corey Donohoe dd7c2cc7f6 Merge pull request #317 from kristi/frontend-tweak
Frontend tweak
2012-05-06 17:00:16 -07:00
kristi 857ca14499 add bottom margin to wiki-page css 2012-05-06 16:37:29 -07:00
kristi f022b3fcde Use github markup for page and sidebar content 2012-05-06 16:37:29 -07:00
kristi 9470ff2dcc fix the sidebar editor 2012-05-06 16:37:28 -07:00
Corey Donohoe d817a4fdb6 fixup page versioning, fixes #174
Thanks @nealpoole and @arr2036
2012-05-06 13:30:23 -07:00
Corey Donohoe 19635b06cf gemspec updates 2012-05-06 12:08:25 -07:00
Corey Donohoe 872776660b next version will be 2.0 2012-05-06 12:08:12 -07:00
Corey Donohoe 9644d4b00e dupe sanitization attrs initialized by constants, fixes #200 2012-05-06 12:07:41 -07:00
bootstraponline 04579d7ae6 Update test. 2012-05-05 13:51:46 -06:00
bootstraponline e9a9eb1779 Add header. 2012-05-05 13:49:01 -06:00
Corey Donohoe 9a1dddaccf whitelist apt uri schemes, fixes #233 2012-05-05 11:56:01 -07:00
Corey Donohoe 4110ab5a82 Merge pull request #308 from bootstraponline/title
Title defined by filename only.
2012-05-04 15:35:32 -07:00
Corey Donohoe 5d1844e491 Merge pull request #313 from kristi/frontend-tweak
Fix searchbar scaling issue
2012-05-04 09:44:23 -07:00
kristi 6a126d46ee Fix searchbar scaling issue 2012-05-04 09:35:27 -07:00
kristi f834a0c84f searchbar fix for ie9 2012-05-04 09:24:20 -07:00
Corey Donohoe 9dfeb237e7 Merge pull request #312 from kristi/frontend-tweak
searchbar fix for ie9
2012-05-04 09:21:45 -07:00
Corey Donohoe b769ba2974 Merge pull request #310 from kristi/frontend-tweak
Frontend tweaks
2012-05-04 08:32:17 -07:00
Corey Donohoe fc1feb280f let's use 0.8.0 if at all 2012-05-04 08:25:01 -07:00
Corey Donohoe bface83af7 Merge pull request #309 from nricciar/master
Gollum using very old version of wikicloth
2012-05-04 08:24:14 -07:00
bootstraponline 9a89a16388 Update live preview and gemspec. 2012-05-03 17:22:34 -06:00
bootstraponline 7649abf86a Add encodeURIComponent. 2012-05-03 11:51:59 -06:00
bootstraponline b6ad97745d Use encodeURIComponent. 2012-05-03 11:49:41 -06:00
bootstraponline 92028e191d Remove console.log. 2012-05-03 11:13:27 -06:00
bootstraponline 7d4427a5d3 Add save and load. 2012-05-03 11:10:50 -06:00
Vicent Martí 2bea800a37 Proper ordering for markup processing, fixes #135
Code blocks get extracted first.
2012-05-02 18:53:41 -07:00
kristi 4c1ff7deb7 fixup the compare revisions page 2012-05-02 16:55:16 -07:00
bootstraponline 347260f17b Add livepreview (7f3ed651e4e4388977f9b3ce29ed1a995ff6d7a9). 2012-05-02 16:59:50 -06:00
bootstraponline 1086fba7da Only use live preview for editing markdown pages. 2012-05-02 16:58:49 -06:00
kristi 5a7cb129bb Fixup css styling for pages, editor, history 2012-05-02 15:52:15 -07:00
kristi b29d22e99b Make navbar flow nicely for narrow windows 2012-05-02 13:51:26 -07:00
David 12cf102543 removing hardcoded reference to old version of wikicloth 2012-05-02 20:45:46 +00:00
kristi 3d95730880 Fix navbar and searchbar css 2012-05-02 13:00:46 -07:00
bootstraponline c5d807dd58 Fix tests. 2012-05-02 12:13:18 -06:00
bootstraponline d40df79dce Title defined by filename only. 2012-05-02 12:05:57 -06:00
Corey Donohoe 3cfa297b49 hide the page title as before 2012-05-02 19:29:17 +02:00
Corey Donohoe e435769345 remove executable bit 2012-05-02 19:20:57 +02:00
bootstraponline 9a73877b3e Fix search bar and restore title. 2012-05-02 11:03:37 -06:00
Corey Donohoe e2cd8d93f4 Merge pull request #306 from pdeschen/master
README Installation requirements sub section for mathematical equations support
2012-05-01 16:33:51 -07:00
Corey Donohoe afc6ec468f bit of testing info 2012-05-02 01:33:15 +02:00
Corey Donohoe 391838cfc3 no more rbx 2012-05-02 01:25:52 +02:00
Corey Donohoe 36a11ded4f Merge pull request #304 from rwfowler/asciidocLinksWithTravis
Disable internal link processing for asciidoc
2012-05-01 16:10:51 -07:00
Corey Donohoe f540ef2e06 Merge pull request #305 from rwfowler/goForGreen
Fix the test_normalizes_commit_hash on Travis-CI
2012-05-01 16:04:39 -07:00
Corey Donohoe b061e0f859 2.0 is unnecessary 2012-05-02 00:49:44 +02:00
Corey Donohoe 4972fbbc7b this doesn't build on 1.9.x /cc @brianmario 2012-05-02 00:44:17 +02:00
Pascal Deschenes 1f318de812 add missing note about dvips in installation requirements sub section + associated section text 2012-05-01 18:15:01 -04:00
Pascal Deschenes 0ceeadd75b add installation requirements regarding mathematical equations support 2012-05-01 18:10:21 -04:00
Ryan Fowler b9dad32707 Fix the test_normalizes_commit_hash on Travis-CI 2012-05-01 17:02:50 -05:00
Ryan Fowler d1cf698b45 Disable internal link processing for asciidoc
asciidoc's representation of section identifiers interferes with
Gollum's page linking. This disables Gollum's page link tag
extraction for asciidoc files.

Adds "apt-get install -y asciidoc" to .travis.yml so tests pass
on @travis-ci.
2012-05-01 14:23:26 -05:00
Corey Donohoe 9dba3f9c58 Revert "Merge pull request #303 from rwfowler/asciidocLinks"
This reverts commit 8fbbe40300, reversing
changes made to b7fb4c5950.
2012-05-01 19:51:05 +02:00
Corey Donohoe 8fbbe40300 Merge pull request #303 from rwfowler/asciidocLinks
Fix for #52 - Disable internal link processing for asciidoc
2012-05-01 10:42:31 -07:00
Ryan Fowler f73c925ad9 Disable internal link processing for asciidoc
asciidoc's representation of section identifiers interferes with
Gollum's page linking. This disables Gollum's page link tag
extraction for asciidoc files.
2012-05-01 11:43:27 -05:00
Corey Donohoe b7fb4c5950 Merge pull request #302 from kristi/master
fix Rack config.ru documentation
2012-05-01 02:32:07 -07:00
kristi fed49bb98b Fix gollum_path in rack setup documentation 2012-05-01 01:37:17 -07:00
462 changed files with 151131 additions and 8522 deletions
+1
View File
@@ -4,3 +4,4 @@ pkg
.bundle
Gemfile.lock
*.gem
*.swp
+4 -2
View File
@@ -1,6 +1,8 @@
rvm:
- 1.8.7
- 1.9.2
- rbx-2.0
- 1.9.3
notifications:
disabled: true
before_install:
- sudo apt-get update
- sudo apt-get install -y --force-yes asciidoc
+2 -2
View File
@@ -1,4 +1,4 @@
source "http://rubygems.org"
source 'http://rubygems.org'
gemspec
gem "rake", "~> 0.9.2"
gem 'rake', '~> 0.9'
+95 -15
View File
@@ -1,6 +1,9 @@
gollum -- A wiki built on top of Git
====================================
[![Build Status](https://secure.travis-ci.org/github/gollum.png?branch=master)](http://travis-ci.org/github/gollum)
[![Dependency Status](https://gemnasium.com/github/gollum.png)](https://gemnasium.com/github/gollum)
## DESCRIPTION
Gollum is a simple wiki system built on top of Git that powers GitHub Wikis.
@@ -16,6 +19,11 @@ number of ways depending on your needs. You can edit your wiki locally:
Gollum follows the rules of [Semantic Versioning](http://semver.org/) and uses
[TomDoc](http://tomdoc.org/) for inline documentation.
## SYSTEM REQUIREMENTS
- Python 2.5+ (2.7.3 recommended)
- Ruby 1.8.7+ (1.9.3 recommended)
- Unix like operating system (OS X, Ubuntu, Debian, and more)
- Will not work on Windows (because of [grit](https://github.com/github/grit))
## INSTALLATION
@@ -32,7 +40,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 +67,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 +115,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 +129,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 +297,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
@@ -309,19 +340,30 @@ then that whitespace will be ignored (this makes the blocks easier to read in pl
The block must end with three backticks indented at the same level than the opening
backticks.
### GITHUB SYNTAX HIGHLIGHTING
As an extra feature, you can syntax highlight a file from your repository, allowing
you keep some of your sample code in the main repository. The code-snippet is
updated when the wiki is rebuilt. You include github code like this:
```html:github/gollum/master/test/file_view/1_file.txt```
This will make the builder look at the **github user**, in the **gollum project**,
in the **master branch**, at path **test/file_view/1_file.txt**. It will be
rewritten to:
```html
<ol class="tree">
<li class="file"><a href="0">0</a></li>
</ol>
```
Which will be parsed as HTML code during the Pygments run, and thereby coloured
appropriately.
## 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:
\[ P(E) = {n \choose k} p^k (1-p)^{ n-k} \]
Inline equations are delimited by `\(` and `\)`. These equations will appear
inline with regular text. For example:
The Pythagorean theorem is \( a^2 + b^2 = c^2 \).
Start gollum with the `--mathjax` flag. Read more about [MathJax](http://docs.mathjax.org/en/latest/index.html) on the web. Gollum uses the `TeX-AMS-MML_HTMLorMML` config with the autoload-all extension.
## SEQUENCE DIAGRAMS
@@ -359,6 +401,17 @@ By default, internal wiki links are all absolute from the root. To specify a dif
wiki = Gollum::Wiki.new("my-gollum-repo.git", :base_path => "/wiki")
Note that base_path just modifies the links. To map gollum to a non-root location:
- Use the gollum binary: `gollum path/to/wiki --base-path mywiki`
- Define config.ru with `map`. See [#532](https://github.com/github/gollum/issues/532) for an example.
> :base_path - String base path for all Wiki links.
>
> The String base path to prefix to internal links. For example, when set
> to "/wiki", the page "Hobbit" will be linked as "/wiki/Hobbit". Defaults
> to "/".
Get the latest version of the given human or canonical page name:
page = wiki.page('page-name')
@@ -383,6 +436,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 +512,20 @@ 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
Your Rack middleware can pass author details to Gollum in a Hash in the session under the 'gollum.author' key.
## 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.
## LIB.SO ERROR
`Could not open library 'lib.so'` may be solved by installing `python-devel` on Fedora or `python-dev` on Ubuntu. Gentoo requires a rubypython [patch](https://gist.github.com/2802480) to use python2.7.
## CONTRIBUTE
If you'd like to hack on Gollum, start by forking my repo on GitHub:
@@ -477,7 +546,18 @@ your changes merged back into core is as follows:
1. Send a pull request to the github/gollum project.
## RELEASING
For z releases:
$ rake bump
$ rake release
For x.y releases:
Update VERSION in lib/gollum.rb
$ rake gemspec
$ gem build gollum.gemspec
$ gem push gollum-X.Y.Z.gem
$ rake release
## 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 --no-ri --no-rdoc pkg/gollum*.gem
+33 -4
View File
@@ -17,6 +17,27 @@ def version
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
end
# assumes x.y.z all digit version
def next_version
# x.y.z
v = version.split '.'
# bump z
v[-1] = v[-1].to_i + 1
v.join '.'
end
def bump_version
old_file = File.read("lib/#{name}.rb")
old_version_line = old_file[/^\s*VERSION\s*=\s*.*/]
new_version = next_version
# replace first match of old vesion with new version
old_file.sub!(old_version_line, " VERSION = '#{new_version}'")
File.write("lib/#{name}.rb", old_file)
new_version
end
def date
Date.today.to_s
end
@@ -71,7 +92,14 @@ end
#
#############################################################################
desc "Update version number and gemspec"
task :bump do
puts "Updated version to #{bump_version}"
# Execute does not invoke dependencies.
# Manually invoke gemspec then validate.
Rake::Task[:gemspec].execute
Rake::Task[:validate].execute
end
#############################################################################
#
@@ -85,6 +113,7 @@ task :release => :build do
puts "You must be on the master branch to release!"
exit!
end
sh "git pull"
sh "git commit --allow-empty -a -m 'Release #{version}'"
sh "git tag v#{version}"
sh "git push origin master"
@@ -99,7 +128,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)
@@ -117,7 +146,7 @@ task :gemspec => :validate do
split("\n").
sort.
reject { |file| file =~ /^\./ }.
reject { |file| file =~ /^(rdoc|pkg)/ }.
reject { |file| file =~ /^(rdoc|pkg|test|Home\.md)/ }.
map { |file| " #{file}" }.
join("\n")
@@ -139,4 +168,4 @@ task :validate do
puts "A `VERSION` file at root level violates Gem best practices."
exit!
end
end
end
+47 -2
View 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
wiki_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'
@@ -122,5 +141,31 @@ else
require cfg
end
Precious::App.run!(options)
base_path = wiki_options[:base_path]
if wiki_options[:base_path].nil?
Precious::App.run!(options)
else
require 'rack'
class MapGollum
def initialize base_path
@mg = Rack::Builder.new do
map '/' do
run Proc.new { [ 302, {'Location'=> "/#{base_path}" }, [] ] }
end
map "/#{base_path}" do
run Precious::App
end
end
end
def call(env)
@mg.call(env)
end
end
# Rack::Handler does not work with Ctrl + C. Use Rack::Server instead.
Rack::Server.new(:app => MapGollum.new(base_path), :Port => options['port']).start
end
end
+380 -133
View File
@@ -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.3.1'
s.date = '2012-10-21'
s.rubyforge_project = 'gollum'
s.summary = "A simple, Git-powered wiki."
@@ -22,29 +23,29 @@ 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('github-markup', [">= 0.7.0", "< 1.0.0"])
s.add_dependency('github-markdown')
s.add_dependency('pygments.rb', "~> 0.2.0")
s.add_dependency('posix-spawn', "~> 0.3.0")
s.add_dependency('sinatra', "~> 1.0")
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('grit', '~> 2.5.0')
s.add_dependency('github-markup', ['>= 0.7.4', '< 1.0.0'])
s.add_dependency('github-markdown', '~> 0.5.1')
s.add_dependency('pygments.rb', '~> 0.3.2')
s.add_dependency('sinatra', '~> 1.3.3')
s.add_dependency('mustache', ['>= 0.99.4', '< 1.0.0'])
s.add_dependency('sanitize', '~> 2.0.3')
s.add_dependency('nokogiri', '~> 1.5.5')
s.add_dependency('useragent', '~> 0.4.12')
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('shoulda')
s.add_development_dependency('rack-test')
s.add_development_dependency('wikicloth', '~> 0.6.3')
s.add_development_dependency('rake', '~> 0.9.2')
s.add_development_dependency('RedCloth', '~> 4.2.9')
s.add_development_dependency('mocha', '~> 0.12.7')
s.add_development_dependency('org-ruby', '~> 0.7.2')
s.add_development_dependency('shoulda', '~> 3.3.1')
s.add_development_dependency('rack-test', '~> 0.6.2')
s.add_development_dependency('wikicloth', '~> 0.8.0')
s.add_development_dependency('rake', '~> 0.9')
# = MANIFEST =
s.files = %w[
Gemfile
HISTORY.md
Home.md
LICENSE
README.md
Rakefile
@@ -55,13 +56,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,150 +87,383 @@ 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/licenses/templarian_windowsicons/license.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
lib/gollum/frontend/views/pages.rb
lib/gollum/frontend/views/search.rb
lib/gollum/git_access.rb
lib/gollum/gitcode.rb
lib/gollum/markup.rb
lib/gollum/page.rb
lib/gollum/pagination.rb
lib/gollum/sanitization.rb
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
test/examples/empty.git/description
test/examples/empty.git/hooks/applypatch-msg.sample
test/examples/empty.git/hooks/commit-msg.sample
test/examples/empty.git/hooks/post-commit.sample
test/examples/empty.git/hooks/post-receive.sample
test/examples/empty.git/hooks/post-update.sample
test/examples/empty.git/hooks/pre-applypatch.sample
test/examples/empty.git/hooks/pre-commit.sample
test/examples/empty.git/hooks/pre-rebase.sample
test/examples/empty.git/hooks/prepare-commit-msg.sample
test/examples/empty.git/hooks/update.sample
test/examples/empty.git/info/exclude
test/examples/empty.git/objects/info/.gitkeep
test/examples/empty.git/objects/pack/.gitkeep
test/examples/empty.git/refs/heads/.gitkeep
test/examples/lotr.git/COMMIT_EDITMSG
test/examples/lotr.git/HEAD
test/examples/lotr.git/ORIG_HEAD
test/examples/lotr.git/config
test/examples/lotr.git/description
test/examples/lotr.git/index
test/examples/lotr.git/info/exclude
test/examples/lotr.git/logs/HEAD
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/0e/d8cbe0a25235bd867e65193c7d837c66b328ef
test/examples/lotr.git/objects/12/629d666c5e3178f82f533f543d61b53dc78c0b
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/2c/b9156ad383914561a8502fc70f5a1d887e48ad
test/examples/lotr.git/objects/5d/cac289a8603188d2c5caf481dcba2985126aaa
test/examples/lotr.git/objects/60/f12f4254f58801b9ee7db7bca5fa8aeefaa56b
test/examples/lotr.git/objects/71/4323c104239440a5c66ab12a67ed07a83c404f
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/96/97dc65e095658bbd1b8e8678e08881e86d32f1
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/bc/4b5fc0ce2c2ba3acef6647e4f67256ee45ab60
test/examples/lotr.git/objects/c3/b43e9f08966b088e7a0192e436b7a884542e05
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/info/packs
test/examples/lotr.git/objects/pack/pack-dcbeaf3f6ff6c5eb08ea2b0a2d83626e8763546b.idx
test/examples/lotr.git/objects/pack/pack-dcbeaf3f6ff6c5eb08ea2b0a2d83626e8763546b.pack
test/examples/lotr.git/packed-refs
test/examples/lotr.git/refs/heads/master
test/examples/lotr.git/refs/remotes/origin/HEAD
test/examples/page_file_dir.git/COMMIT_EDITMSG
test/examples/page_file_dir.git/HEAD
test/examples/page_file_dir.git/config
test/examples/page_file_dir.git/description
test/examples/page_file_dir.git/index
test/examples/page_file_dir.git/info/exclude
test/examples/page_file_dir.git/logs/HEAD
test/examples/page_file_dir.git/logs/refs/heads/master
test/examples/page_file_dir.git/objects/0c/7d27db1f575263efdcab3dc650f4502a2dbcbf
test/examples/page_file_dir.git/objects/22/b404803c966dd92865614d86ff22ca12e50c1e
test/examples/page_file_dir.git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99
test/examples/page_file_dir.git/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6
test/examples/page_file_dir.git/objects/5b/43e14e0a15fb6f08feab1773d1c0991e9f71e2
test/examples/page_file_dir.git/refs/heads/master
test/examples/revert.git/COMMIT_EDITMSG
test/examples/revert.git/HEAD
test/examples/revert.git/config
test/examples/revert.git/description
test/examples/revert.git/index
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/20/2ced67cea93c7b6bd2928aa1daef8d1d55a20d
test/examples/revert.git/objects/41/76394bfa11222363c66ce7e84b5f154095b6d9
test/examples/revert.git/objects/6a/69f92020f5df77af6e8813ff1232493383b708
test/examples/revert.git/objects/b4/785957bc986dc39c629de9fac9df46972c00fc
test/examples/revert.git/objects/f4/03b791119f8232b7cb0ba455c624ac6435f433
test/examples/revert.git/objects/info/packs
test/examples/revert.git/objects/pack/pack-a561f8437234f74d0bacb9e0eebe52d207f5770d.idx
test/examples/revert.git/objects/pack/pack-a561f8437234f74d0bacb9e0eebe52d207f5770d.pack
test/examples/revert.git/packed-refs
test/examples/revert.git/refs/heads/master
test/examples/revert.git/refs/remotes/origin/HEAD
test/examples/yubiwa.git/HEAD
test/examples/yubiwa.git/config
test/examples/yubiwa.git/description
test/examples/yubiwa.git/info/exclude
test/examples/yubiwa.git/objects/10/fa2ddc4e3b4009d8a453aace10bd6148c1ad00
test/examples/yubiwa.git/objects/52/4b82874327ea7cbf730389964ba7cb3de966de
test/examples/yubiwa.git/objects/58/3fc201cb457fb3f1480f3e1e5999b119633835
test/examples/yubiwa.git/objects/87/bc1dd46ab3d3874d4e898d45dd512cc20a7cc8
test/examples/yubiwa.git/objects/89/64ed1b4e21aa90e831763bbce9034bfda81b70
test/examples/yubiwa.git/objects/9f/f6dd0660da5fba2d3374adb2b84fa653bb538b
test/examples/yubiwa.git/objects/ac/e97abf2b177815a1972d7db22f229f58c83309
test/examples/yubiwa.git/objects/b1/f443863a4816628807fbf86141ebef055dda34
test/examples/yubiwa.git/refs/heads/master
test/helper.rb
test/test_app.rb
test/test_committer.rb
test/test_file.rb
test/test_git_access.rb
test/test_markup.rb
test/test_page.rb
test/test_page_revert.rb
test/test_wiki.rb
templates/helper_wiki.rb
]
# = MANIFEST =
+3 -2
View File
@@ -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__)
require File.expand_path('../gollum/frontend/uri_encode_component', __FILE__)
module Gollum
VERSION = '1.4.3'
VERSION = '2.3.1'
def self.assets_path
::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__))
+13 -1
View 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
+17 -4
View File
@@ -91,19 +91,29 @@ 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|
next if page_path_scheduled_for_deletion?(index.tree, fullpath)
file = blob.name.downcase.sub(/\.\w+$/, '')
file_ext = ::File.extname(blob.name).sub(/^\./, '')
if downpath == file && !(allow_same_ext && file_ext == ext)
existing_file = blob.name.downcase.sub(/\.\w+$/, '')
existing_file_ext = ::File.extname(blob.name).sub(/^\./, '')
new_file_ext = ::File.extname(path).sub(/^\./, '')
if downpath == existing_file && !(allow_same_ext && new_file_ext == existing_file_ext)
raise DuplicatePageError.new(dir, blob.name, path)
end
end
end
fullpath = fullpath.force_encoding('ascii-8bit') if fullpath.respond_to?(:force_encoding)
index.add(fullpath, @wiki.normalize(data))
end
@@ -129,6 +139,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 +224,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
+15 -2
View File
@@ -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
+145
View File
@@ -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
+251 -83
View File
@@ -2,16 +2,58 @@ 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 '../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 +80,131 @@ 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[:page_file_dir].to_s,settings.wiki_options[:base_path].to_s, 'Home')
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)
return if page.nil?
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
page_dir = File.join(settings.wiki_options[:page_file_dir].to_s,
settings.wiki_options[:base_path].to_s)
# Home is a special case.
path = '' if name.downcase == 'home'
page_dir = File.join(page_dir, path)
# write_page is not directory aware so use wiki_options to emulate dir support.
wiki_options = settings.wiki_options.merge({ :page_file_dir => page_dir })
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(page_dir,name)))}")
rescue Gollum::DuplicatePageError => e
@message = "Duplicate page: #{e.message}"
mustache :error
@@ -86,79 +212,89 @@ 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
get '/_tex.png' do
content_type 'image/png'
formula = Base64.decode64(params[:data])
Gollum::Tex.render_formula(formula)
end
get %r{^/(javascript|css|images)} do
halt 404
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,51 +307,83 @@ 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
private
# Options parameter to Gollum::Committer#initialize
# :message - The String commit message.
# :name - The String author full name.
# :email - The String email address.
# message is sourced from the incoming request parameters
# author details are sourced from the session, to be populated by rack middleware ahead of us
def commit_message
{ :message => params[:message] }
commit_message = { :message => params[:message] }
author_parameters = session['gollum.author']
commit_message.merge! author_parameters unless author_parameters.nil?
commit_message
end
end
end
+34
View File
@@ -0,0 +1,34 @@
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
# Remove all slashes from the start of string.
def clean_url url
return url if url.nil?
url.gsub('%2F','/').gsub(/^\/+/,'')
end
def trim_leading_slash url
return url if url.nil?
url.gsub!('%2F','/')
return '/' + url.gsub(/^\/+/,'') if url[0,1] == '/'
url
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;
+409 -353
View File
@@ -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;
}
+544 -292
View File
@@ -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;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

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,29 @@
if(LanguageDefinition.getHookFunctionFor("activate")) {
LanguageDefinition.getHookFunctionFor("activate")();
}
function hotkey( e, cmd ) {
e.preventDefault();
var def = LanguageDefinition.getDefinitionFor( cmd );
if ( typeof def == 'object' ) {
FunctionBar.executeAction( def );
}
// Prevent bubbling of hotkey.
return false;
}
Mousetrap.bind(['command+1', 'ctrl+1'], function( e ){ hotkey( e, 'function-h1' ); });
Mousetrap.bind(['command+2', 'ctrl+2'], function( e ){ hotkey( e, 'function-h2' ); });
Mousetrap.bind(['command+3', 'ctrl+3'], function( e ){ hotkey( e, 'function-h3' ); });
Mousetrap.bind(['command+b', 'ctrl+b'], function( e ){ hotkey( e, 'function-bold' ); });
Mousetrap.bind(['command+i', 'ctrl+i'], function( e ){ hotkey( e, 'function-italic' ); });
Mousetrap.bind(['command+s', 'ctrl+s'], function( e ){
e.preventDefault();
$("#gollum-editor-submit").trigger("click");
return false;
});
} );
} else {
LanguageDefinition._ACTIVE_LANG = name;
@@ -262,7 +288,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 +773,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('&quot;') + '"';
}
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);
}
});
});
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -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 -- */
Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

@@ -0,0 +1,43 @@
<!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 id='editor_bg' 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>
</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(); });
}
});
Binary file not shown.

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;
}
Binary file not shown.

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()
}
File diff suppressed because it is too large Load Diff
@@ -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()
}
File diff suppressed because it is too large Load Diff
@@ -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, "&quot;").replace(/'/g, "&#8217;").replace(/</, "&lt;");
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"; //"&para;";
this.EOL_CHAR = "\xAC"; //"&not;";
this.TAB_CHAR = "\u2192"; //"&rarr;" "\u21E5";
this.SPACE_CHAR = "\xB7"; //"&middot;";
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("&#160;")
+ "</span>");
} else {
tabStr.push(new Array(i+1).join("&#160;"));
}
}
};
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("&#160;");
} else if (c == "&") {
return "&#38;";
} else if (c == "<") {
return "&#60;";
} 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;
};
});
File diff suppressed because it is too large Load Diff
@@ -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");
});

Some files were not shown because too many files have changed in this diff Show More