Compare commits
860 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 851f53194e | |||
| d3a709c4d3 | |||
| 0b75a47750 | |||
| 4fcc72078b | |||
| 9b4755e822 | |||
| 9c574fd760 | |||
| 46c22a8b87 | |||
| 7e379cfab1 | |||
| 93d3d10453 | |||
| 98a0006c86 | |||
| d97721f38b | |||
| 8d3ec8605e | |||
| 7517389072 | |||
| b7011139cf | |||
| 6e8a68dd0d | |||
| 4e8309d3e4 | |||
| 371ab21d16 | |||
| cbcbc4bc3f | |||
| dc9b2e1766 | |||
| 334df62651 | |||
| 046353cf7e | |||
| 51f2f032d7 | |||
| 70360edb96 | |||
| 2b12ab9206 | |||
| 87a01e04ce | |||
| 5f04200bd0 | |||
| aa823b5a2d | |||
| 9012dee888 | |||
| 81d5f1a8bb | |||
| d2b0a22a8f | |||
| 355e6b1f18 | |||
| 7a2c9107c3 | |||
| 127473fff8 | |||
| 9a79b0a800 | |||
| ca13298d00 | |||
| eaf82e6367 | |||
| cae290ded7 | |||
| a22208a0be | |||
| bc877dc9dc | |||
| 40b1775d42 | |||
| c2dc605adb | |||
| a1e1af07a4 | |||
| 76948130f6 | |||
| f71ba31bfe | |||
| b7caa228e6 | |||
| 0101dd2f65 | |||
| c8baa61fe3 | |||
| 104335706a | |||
| 7c60841bad | |||
| f6a7c57175 | |||
| 730acee609 | |||
| b7295df662 | |||
| aba3ec37d9 | |||
| 020c98bfad | |||
| d33d11e086 | |||
| 2e41751cf6 | |||
| f493150825 | |||
| 68d0dd0cd5 | |||
| 38fc7e69c1 | |||
| 5b7b9f40ae | |||
| 17162aa091 | |||
| 0c89aa2b3e | |||
| 1980e39876 | |||
| 2b949014b8 | |||
| b399496ec2 | |||
| 8433327926 | |||
| bb207f43d0 | |||
| 333af9b76c | |||
| 18a16665cc | |||
| 6c0796733d | |||
| 97ed5a7c57 | |||
| c87c8c446e | |||
| bfbfb21c17 | |||
| 137728cdab | |||
| 3f7fd21d4a | |||
| 2204cef0ef | |||
| 29ad7127d1 | |||
| 123518b940 | |||
| dbe849707a | |||
| 986a76cf8e | |||
| 42439033c8 | |||
| 421ff18788 | |||
| 519a275ff0 | |||
| 5a95f79b32 | |||
| 627ee5bbbe | |||
| a9d300341c | |||
| 6b7e912010 | |||
| 4feae80814 | |||
| 5f5730fe2e | |||
| 5f784f5e10 | |||
| 35a44efafd | |||
| b32dcfa8dd | |||
| 38fc32bbdd | |||
| 6c7b12ae5e | |||
| 649e19bdb1 | |||
| a4266170ea | |||
| 6e6d9d8c1f | |||
| e49758334f | |||
| 580068212d | |||
| 504278d9ba | |||
| 214056a88a | |||
| e310f76030 | |||
| 83abe62125 | |||
| 8e7a714991 | |||
| 4f67710ed2 | |||
| 8ec8be5db3 | |||
| 92da563211 | |||
| 2eb5a7e4b8 | |||
| 23110d5f05 | |||
| 18de3272e3 | |||
| 1e81c42818 | |||
| ef6e0e8a07 | |||
| ba575b886d | |||
| c8f856109d | |||
| 4035c579c7 | |||
| 8bab3de510 | |||
| 9ab4bbb17c | |||
| ae024eb3b3 | |||
| db84653bf2 | |||
| d8ebba114f | |||
| b9d7375dba | |||
| 676811206d | |||
| ff1baf0036 | |||
| 3d12aeb8b2 | |||
| 5a8750a975 | |||
| 0cb303f09f | |||
| edc7d0b50b | |||
| 2c268a9f8c | |||
| d61a09d421 | |||
| 0eee014a8b | |||
| 76f6b6e81c | |||
| 40215c3da2 | |||
| 1056d5cf16 | |||
| f74c6c1706 | |||
| 821614e45a | |||
| 32e8618ed4 | |||
| e123611fed | |||
| 5c3394c227 | |||
| da6708e61d | |||
| c99da8ff34 | |||
| 9ab308412c | |||
| 4efcba6ceb | |||
| ca7c708bf9 | |||
| 1f70dca752 | |||
| d32c5a88f7 | |||
| b209127000 | |||
| 6e37601b25 | |||
| 23b97daa84 | |||
| 7329b7595d | |||
| f0bb300e03 | |||
| 6a1ea82ff1 | |||
| 6011deb930 | |||
| 28bfe02411 | |||
| 862c6d5d2e | |||
| 4c491a01db | |||
| 16676e0788 | |||
| ebf46629b1 | |||
| 36811490d0 | |||
| f0122cebb5 | |||
| e2804d6313 | |||
| ae7ed4eafa | |||
| aae320ddff | |||
| a71cb40bdf | |||
| 2ba5d389a8 | |||
| f1e8d30a43 | |||
| e6ee27a083 | |||
| 4008bf12e7 | |||
| 0b1d7ab01c | |||
| a45101cfe9 | |||
| d5970d6274 | |||
| 83f4ccfa70 | |||
| 707648bde8 | |||
| 0707205374 | |||
| f6f81b39f8 | |||
| f8829c68d6 | |||
| 54bbd1d789 | |||
| ee267f72a2 | |||
| f516b1cb79 | |||
| 0e4c8342ab | |||
| 6f61ddae77 | |||
| e312641cbd | |||
| 07de956b1d | |||
| 4d549b1660 | |||
| e1a13aef1f | |||
| cc3eb233c7 | |||
| f0b04f1334 | |||
| 9b89e31679 | |||
| 2b380ee6bc | |||
| caf4da73e2 | |||
| 56e36df6bd | |||
| c8fed4d50d | |||
| c619920452 | |||
| 70ede99545 | |||
| 9862c51e3f | |||
| f0dbc2801b | |||
| 7c65d65cb1 | |||
| 5dd6c40933 | |||
| 5487563a71 | |||
| 7458e396ee | |||
| 8f104ec09c | |||
| 8fe4c614db | |||
| c137c2af4b | |||
| 2402c9ef3b | |||
| bbe609974a | |||
| 88c624877e | |||
| 41d7cf75c5 | |||
| 9da11dba10 | |||
| d1857e5824 | |||
| fc64d88ce9 | |||
| 3713890b5e | |||
| efaa6a0ba2 | |||
| d55a3432a2 | |||
| 0fda253457 | |||
| 2216d67d5a | |||
| a04af6c638 | |||
| 91c04cd44c | |||
| 1c98a787ab | |||
| 87902f258a | |||
| 3740a7f6ff | |||
| b6b176fdc1 | |||
| 77aaeef5ff | |||
| d1b1375629 | |||
| 569eac3a06 | |||
| a5ecb772ae | |||
| 736897a168 | |||
| c1f6f0b429 | |||
| 9fd9acb573 | |||
| beff52a68e | |||
| cc33d81473 | |||
| 1a27f04577 | |||
| 2f2487150a | |||
| 6d44bd7bc8 | |||
| e2d9d1f4d5 | |||
| 958410146b | |||
| 0a9b9ff709 | |||
| bce9800142 | |||
| 7f07f652d4 | |||
| 1b5f0b910b | |||
| e1aa4c02a0 | |||
| 976f55e1b2 | |||
| 29a8b893f1 | |||
| c991149422 | |||
| 175c0ceab5 | |||
| 9d48ea0079 | |||
| 042ad2d8c4 | |||
| 19868a10ef | |||
| 92b17f9053 | |||
| 2dc527b60f | |||
| fa08ce35cc | |||
| 8413e5b5ee | |||
| aa16f6ba2a | |||
| 22e0fdc822 | |||
| 0de56202e9 | |||
| bcec052e35 | |||
| e28a41bb8f | |||
| 17c574467f | |||
| 8f350976a1 | |||
| dfb4281a14 | |||
| 7881237de2 | |||
| 05daab661e | |||
| c0e6de899b | |||
| c103f3ebdc | |||
| 7cabd684a9 | |||
| af344c1d25 | |||
| b40a344c49 | |||
| e0a2b183ad | |||
| 97857d0e3f | |||
| 6fcfe7895e | |||
| f5f655e3a1 | |||
| 94fe2f59d3 | |||
| 66fd8eef1f | |||
| fb5c65827d | |||
| bb79cf5ce6 | |||
| f72e8610da | |||
| b76a250596 | |||
| 2aea55a92c | |||
| 073137af7d | |||
| e966de6922 | |||
| 616c004058 | |||
| 59bb48340e | |||
| 7ec80bf2f1 | |||
| 006dd36078 | |||
| 58225c7c20 | |||
| 04501c205a | |||
| 253ba89f90 | |||
| 7f598cb49e | |||
| d3402dded2 | |||
| f222efd281 | |||
| 8f6c19b3fd | |||
| f44367c31b | |||
| c31c68200b | |||
| ddfaf8c091 | |||
| ca9702088f | |||
| 413e962871 | |||
| 848cef26ee | |||
| b40b3aa9fc | |||
| ae853e074a | |||
| f4838d12c6 | |||
| 4eb7fd211c | |||
| efd1d3992d | |||
| d4a9da0db5 | |||
| bde72cb52e | |||
| f251e0f556 | |||
| 5de2442540 | |||
| b5c4fdcc83 | |||
| b50872497e | |||
| 6d0b42b18f | |||
| 70bf766cd0 | |||
| 104c959bf7 | |||
| 3c4c2a072c | |||
| 769f8ec8d6 | |||
| 64c4ee9c05 | |||
| 6857995442 | |||
| eade94dcfd | |||
| daef5fe9d2 | |||
| b8629729b9 | |||
| 4e2b1442bd | |||
| 83fbb16c3b | |||
| d2ea03fbb9 | |||
| b1ac06cd5f | |||
| 19751ec37f | |||
| 814caff755 | |||
| 8d611ea25a | |||
| 1a8b6d6823 | |||
| 78289a53bb | |||
| 303796c773 | |||
| 825f43c429 | |||
| 454b5e94dc | |||
| 7ddbab76c1 | |||
| 6475394133 | |||
| 874c20e69f | |||
| b93083667d | |||
| 8f7108c56f | |||
| a6167d88cd | |||
| 197a2bd57b | |||
| fd73eb6d05 | |||
| 963eb24fce | |||
| 5c5bfc71bd | |||
| 3b9af34e0d | |||
| daaa82fab5 | |||
| ff52933320 | |||
| 84c01bb69b | |||
| eb9b71e94a | |||
| 1080e776a3 | |||
| f8673f565a | |||
| 6d4f97fdc4 | |||
| c85e14336e | |||
| b1cdf91789 | |||
| fd9156821c | |||
| feb098bf45 | |||
| b0ad3265e7 | |||
| 02fd12339f | |||
| 9048d6a03d | |||
| b5eed33932 | |||
| c660222300 | |||
| 93f6b0373a | |||
| 43d3271b4e | |||
| 66d09b76c7 | |||
| 90043a66cb | |||
| 317ccef7c8 | |||
| ef6bd9b538 | |||
| 012f1fcd47 | |||
| e46861f827 | |||
| 4549fdb9c5 | |||
| f5ad5e397e | |||
| f64ecd340b | |||
| 3060a3576f | |||
| 771ca331e9 | |||
| 92e42236f5 | |||
| 7ada448bce | |||
| c2258c449e | |||
| 051b88fe70 | |||
| 25578961c0 | |||
| b47db5611b | |||
| efe1df769b | |||
| 812cd311c3 | |||
| 676fb474b9 | |||
| 612267d322 | |||
| 167b5c4b1f | |||
| d87a481ffb | |||
| 6f54af5556 | |||
| ddea445a28 | |||
| e82bf4ce46 | |||
| f75037db42 | |||
| 01c7b5f380 | |||
| 0b906dd952 | |||
| dac91e9998 | |||
| 6de0914788 | |||
| e4f702d1e2 | |||
| a75b003c78 | |||
| 08d822a3ff | |||
| 2f864c5e15 | |||
| c9e3e9aa84 | |||
| 7139590798 | |||
| 37c1183515 | |||
| 935a080152 | |||
| 6f11ce71c4 | |||
| f41a85ced9 | |||
| 97fab1df14 | |||
| f6273ded80 | |||
| 9b7028a74e | |||
| 16894330a9 | |||
| 35f6952519 | |||
| ca50e87538 | |||
| 0870655455 | |||
| ba24a7bb8c | |||
| 56ad3251fd | |||
| f32d7465a2 | |||
| 750e2ee677 | |||
| cc273f30e9 | |||
| 64fd56e8ef | |||
| 0fa47047f3 | |||
| 6e2559f77a | |||
| cabe9f353b | |||
| 5aa5bccda3 | |||
| 16ea6245e3 | |||
| df9382bbc3 | |||
| 39aa290ea6 | |||
| f9b8b4e8d3 | |||
| 8aa10fe400 | |||
| e202698bf1 | |||
| c1f94d2deb | |||
| 11c2bf7dae | |||
| 159a2e13ad | |||
| 1e53d7ba53 | |||
| 53cf0e1148 | |||
| 2d1e49e3f2 | |||
| 199161f611 | |||
| ece5c775f1 | |||
| 895d2eb97e | |||
| 3121c43b71 | |||
| c5f3270ff6 | |||
| 318a4717d1 | |||
| 37a11546fa | |||
| 643a42aea6 | |||
| 2b8497531d | |||
| fdbde7840d | |||
| d702026134 | |||
| e2d55b45ba | |||
| 72c8e1aff3 | |||
| 51e8caf369 | |||
| e7e7937678 | |||
| a0f5a60ea0 | |||
| af29c6e441 | |||
| 00dfecb1c7 | |||
| cc249bef15 | |||
| 9a2231804d | |||
| 1edcf15bcd | |||
| 0190e08763 | |||
| 6b20c5df71 | |||
| 8da809f22c | |||
| 54ece4e432 | |||
| a50fcd31e2 | |||
| d3cc5a69c4 | |||
| 07ca53a778 | |||
| abb516e1b1 | |||
| 6910b6d024 | |||
| 435a3e62ba | |||
| f02c934ad7 | |||
| 236680aab9 | |||
| 6316f97c06 | |||
| 14830af306 | |||
| b620decde7 | |||
| b08ca620a0 | |||
| 66a2bb0393 | |||
| 0675844d97 | |||
| 148eda2990 | |||
| 330f7b4002 | |||
| def0fc8866 | |||
| fa1bcf9608 | |||
| 5a5e56a47b | |||
| e64f40eaa3 | |||
| 3f3d86ad4c | |||
| 91833dd72e | |||
| c049f7c11f | |||
| 6bd2f3bff5 | |||
| 8c3c519679 | |||
| 4e5002a31e | |||
| 5a53c58b04 | |||
| a61d1e3d10 | |||
| 1a50f99189 | |||
| 6caacbf388 | |||
| f876aa7d0f | |||
| 31e1281600 | |||
| 90072a9332 | |||
| bacd2893b9 | |||
| 7362fd859b | |||
| 3811fb46b3 | |||
| ab42c0c0df | |||
| de5aed2f6a | |||
| ce68a88293 | |||
| 288f75929d | |||
| 8528dd0c7f | |||
| e0f35eceab | |||
| 7e36517a79 | |||
| 69327766bb | |||
| 9ecf8a61ba | |||
| 2323506c82 | |||
| caa1a55e7a | |||
| 2ce44c157a | |||
| e17778190d | |||
| d1d81a0043 | |||
| ddb5ced3d5 | |||
| 9cebe655fd | |||
| 51b5a11a54 | |||
| f3405851a7 | |||
| 5b6870d610 | |||
| c3dceaff5c | |||
| 0a9b35c039 | |||
| dc32997f45 | |||
| 67c64c17d5 | |||
| 9cc02982be | |||
| b4c70a62a9 | |||
| c9d5921f4e | |||
| 0f47a4de5d | |||
| 0ba5e4d3c7 | |||
| 73e61dbcff | |||
| ba142e3b19 | |||
| f651a401e8 | |||
| 3301252fb2 | |||
| fe77e2b0d3 | |||
| d586567c3b | |||
| 211178d39e | |||
| d8354faa49 | |||
| f9e5c05046 | |||
| 596afe9451 | |||
| f7b5de986a | |||
| ee9262472b | |||
| 8a6a8db730 | |||
| 3642370f11 | |||
| 2db2cfb81c | |||
| 279b028c5e | |||
| f268827a2e | |||
| d8bc065057 | |||
| 6301bbbb66 | |||
| 3ad65eaef8 | |||
| 3d1bc7949d | |||
| 26e092fd20 | |||
| be7ddec1b0 | |||
| 5781ac6bbd | |||
| a51bc4427a | |||
| 80854584bb | |||
| 93af289d3b | |||
| a27b882493 | |||
| ba6f957692 | |||
| ec0e1bf26f | |||
| e4df298bb4 | |||
| 804d21e31d | |||
| 6d33687866 | |||
| 21bb1efb46 | |||
| 9d0986f1ca | |||
| fd483f397f | |||
| 09364850ee | |||
| 4d3a8bad4c | |||
| cc39b0aa41 | |||
| 1cceb7d4b4 | |||
| 6fc3b4be75 | |||
| af6d690fc8 | |||
| eea5152444 | |||
| 1ca38b625b | |||
| f964407c47 | |||
| 3be2e76ec0 | |||
| f9a9b90ed7 | |||
| 1f2917ac22 | |||
| fe1a8569f6 | |||
| 33e8d4f328 | |||
| e183260d0a | |||
| b4023942b4 | |||
| c10c24d90d | |||
| 915f63cac4 | |||
| 5c30ff4d3e | |||
| 3269f02ba7 | |||
| e5c2e3b3eb | |||
| 77f4aee0af | |||
| 868cbdfc7b | |||
| a650c0eab8 | |||
| a7dc8d8c6f | |||
| 355db16d2c | |||
| c54ce41eb7 | |||
| afb7d4c9d1 | |||
| b55cdde9da | |||
| 93cbc6c770 | |||
| 3b1b4a0a96 | |||
| 10b45cb54d | |||
| 9d289e571b | |||
| cce871c30e | |||
| c2b605a90f | |||
| 09149592b5 | |||
| e7410e551b | |||
| 9d77bc4192 | |||
| 537fa0c423 | |||
| c78dbc8bc1 | |||
| 249eed5c2c | |||
| 55eb3b24f7 | |||
| 508c255d0f | |||
| 9f8a90c0ac | |||
| 861dc935cb | |||
| 96ef8cacea | |||
| 5f3ecc8713 | |||
| 8b8ef0eb46 | |||
| 2dbea54c84 | |||
| a776d9fb6f | |||
| 57b7bbff5a | |||
| a832b0ed54 | |||
| 3ec75b84ae | |||
| b932763080 | |||
| 374f8f2f69 | |||
| 226c253d5a | |||
| c78a9f7950 | |||
| 7264510ab2 | |||
| 3458ec6511 | |||
| 2c80db6678 | |||
| 439aa6e4f5 | |||
| adf544dca9 | |||
| 0965269ee9 | |||
| 19d370c4e9 | |||
| cee0f8b652 | |||
| 37664d3487 | |||
| 5a78015d81 | |||
| 7250962ba3 | |||
| 442120bfdb | |||
| de624d1e54 | |||
| 523029cc45 | |||
| 934affe419 | |||
| 55b9af1589 | |||
| 16dd7e46ef | |||
| 851c77d8f2 | |||
| ee55b74898 | |||
| 13fc1e5c66 | |||
| 87112c2942 | |||
| 2664fdca30 | |||
| e05f523145 | |||
| 1148d29439 | |||
| 7ba52978d1 | |||
| 138a9fee43 | |||
| 1d522eaf0d | |||
| b5c5da64c9 | |||
| 8466425836 | |||
| b774ee5cd0 | |||
| 7e2e0e926b | |||
| 30f673c63c | |||
| bb5be728e3 | |||
| 0be5d1c657 | |||
| d143e6be06 | |||
| e65a78a5f5 | |||
| 4f443a3c62 | |||
| ff82ddea97 | |||
| 2e2d3f5e87 | |||
| 491b1041f8 | |||
| ce192d33f7 | |||
| ca1cb64026 | |||
| 71b5f5e469 | |||
| 946567f903 | |||
| 036e739511 | |||
| 87a95b85c5 | |||
| 4f49859bf7 | |||
| 2c53e55533 | |||
| 2ae75978dd | |||
| 452d825e66 | |||
| a7a1c4f81e | |||
| 00740eb9e8 | |||
| d76264c255 | |||
| 2297ce418d | |||
| fec85e6c59 | |||
| 54efa35fb3 | |||
| 988aebf630 | |||
| d2f7766aea | |||
| 25d30aee64 | |||
| 8af92da23c | |||
| 08dd36e1b0 | |||
| 324ff0a17c | |||
| cfb372e5e2 | |||
| 6513c732ba | |||
| c4ea869223 | |||
| 5387267675 | |||
| 8e4c3cc562 | |||
| 8b6b0699e5 | |||
| 229bff1658 | |||
| 7a59d37350 | |||
| d06b1e7883 | |||
| c8a284db9d | |||
| c7d6aceff4 | |||
| 7ea45d5e89 | |||
| 48c4aafb15 | |||
| ff302ed842 | |||
| 20a2424b83 | |||
| de0f34a27a | |||
| d0992cce3f | |||
| 15feeb3614 | |||
| fc0a879e52 | |||
| 9b675146a2 | |||
| 4d0bdcc8c0 | |||
| 0abdb67687 | |||
| d1fb98cf1b | |||
| 5eac24eacb | |||
| 3fd16daeca | |||
| d9b38c3b73 | |||
| 0a5176c1ee | |||
| b836b0e273 | |||
| 9a41e2a65d | |||
| cb1b74ed7b | |||
| e25e5d9768 | |||
| 9f3766952f | |||
| cb4471b07f | |||
| 9fa7eac41f | |||
| 94fa985550 | |||
| 1c498ead35 | |||
| 5abc983172 | |||
| 7a0d4919b0 | |||
| d5e9183877 | |||
| 9b39a51e9f | |||
| bec7eabd1c | |||
| cd3791087f | |||
| 714985e377 | |||
| 76c37dce96 | |||
| 5a9af40058 | |||
| e871ff35b7 | |||
| ecc6c32933 | |||
| 831cf61a08 | |||
| cc1231dece | |||
| bb3d1a165b | |||
| 3da0426c54 | |||
| e01aa25be3 | |||
| ee2f9d8dcb | |||
| 4d8677965c | |||
| 72729d5510 | |||
| 0b57e70c87 | |||
| 033d6489f8 | |||
| 8608007337 | |||
| 665e493570 | |||
| eb1e2f60f3 | |||
| dc637f0a9b | |||
| f81634728d | |||
| 440cd5ebc0 | |||
| 1cd7d0f205 | |||
| a69d62911c | |||
| 395e9bd006 | |||
| 90e20810d5 | |||
| 9c714e7687 | |||
| 6c3523d61c | |||
| 183840b793 | |||
| 4e2856aa64 | |||
| 4627a39165 | |||
| c87cbe83d2 | |||
| f05282badf | |||
| 957879346e | |||
| 87e64f67f3 | |||
| 43840d246d | |||
| 4aeb9af8a7 | |||
| b37acb8bc6 | |||
| 433865e927 | |||
| 5428161e0f | |||
| db0b536b5b | |||
| a4e50908fb | |||
| 96b89fe83d | |||
| adb131f131 | |||
| 757ab87e8a | |||
| f1d1db1159 | |||
| 3942bf60a6 | |||
| e2c0dcc0da | |||
| f63180d8d8 | |||
| 999bbf3d50 | |||
| eab612bdd0 | |||
| 1147186b4c | |||
| a88314e061 | |||
| 9221f5528d | |||
| 520f60cd65 | |||
| 84c85774e8 | |||
| 1f118deed9 | |||
| 55ce07ae73 | |||
| 85677d5e91 | |||
| 04f9be15b8 | |||
| 09cd72a829 | |||
| f5f5ad70e3 | |||
| a0774b320a | |||
| 4feea6051a | |||
| f548ea757b | |||
| abc8ea5280 | |||
| bacd2313fb | |||
| 63295d3f9b | |||
| 9c25eb20cf | |||
| 7f533f33ae | |||
| 352b4e1ed8 | |||
| 9a4252b579 | |||
| ed7011c229 | |||
| 4ddd6a5207 | |||
| 0a74c7cfd2 | |||
| d84fdc7599 | |||
| dac1268266 | |||
| b42db1c7c1 | |||
| 7a7a27c5c7 | |||
| af83186b10 | |||
| a8646f8fe7 | |||
| 01c1e30284 | |||
| b3980f9e39 | |||
| c9fd50d23e | |||
| ea3544f46d | |||
| 4e04f5f540 | |||
| b1021cf233 | |||
| 8fa3529123 | |||
| 3b494c235a | |||
| 1641c3e3e8 | |||
| ccd5d850ac | |||
| b989f160cf | |||
| 54e144564c | |||
| ab8599da6d | |||
| 0885702873 | |||
| 0083bc9302 | |||
| cbc0821928 | |||
| 7a70169d06 | |||
| bf2377ac11 | |||
| 1f79126b27 | |||
| 624e324383 | |||
| 846ebb285e | |||
| e567759935 | |||
| fe706c184e | |||
| 90bbb8e348 | |||
| e21ec540c2 | |||
| 2a4517ced4 | |||
| 8c8d151b3e | |||
| 44a3cf1934 | |||
| 5dcd3c8c8f | |||
| 251bd7cd3d | |||
| 02dfb0a8c1 | |||
| 544d499ab1 | |||
| 8ebc2f7079 | |||
| a31ba16070 | |||
| 60e3baad8a | |||
| f720a84831 | |||
| b74b2c4399 | |||
| 252aa10d75 | |||
| 6f3d362920 | |||
| 9b54e4c79f | |||
| f908d0d170 | |||
| 852ecdd1a9 | |||
| 78f5df5e56 | |||
| 580a61a515 | |||
| 4faf5a0150 | |||
| 1201d2434a | |||
| e1ca392da6 | |||
| 3ee6d22727 | |||
| 28a0329f65 | |||
| 2dc696c940 | |||
| e3acef0e91 | |||
| 62601f1adc | |||
| 982915a22f | |||
| 9f1bbd097f | |||
| 694bd6e74a | |||
| 394cf0bc8e | |||
| 09257deaae | |||
| 21c4b0dd95 | |||
| 3b4662b583 | |||
| 2e2e6457c7 | |||
| 631a7cccd6 | |||
| 2a3d51c7dc | |||
| e7e8a17b61 | |||
| 8fd8a56893 | |||
| 443c453507 | |||
| 0495c89ba1 | |||
| 78e4dfbece |
@@ -30,3 +30,11 @@ gollum text
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
|
||||
# Make github-linguist ignore files that aren't our own
|
||||
|
||||
lib/gollum/public/gollum/* linguist-vendored
|
||||
lib/gollum/public/gollum/javascript/gollum* linguist-vendored=false
|
||||
lib/gollum/public/gollum/javascript/*/gollum* linguist-vendored=false
|
||||
lib/gollum/public/gollum/css linguist-vendored=false
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Please read the [CONTRIBUTION GUIDELINES](https://github.com/gollum/gollum/blob/master/CONTRIBUTING.md) before submitting!**
|
||||
|
||||
If your have problems using or installing the software which stem from bugs in the software or a lack of documentation, we are always happy to help out! However, **for ordinary usage questions, please consider asking elsewhere**, for instance on [StackOverflow](http://stackoverflow.com/questions/tagged/gollum-wiki).
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment Info**
|
||||
|
||||
Always include the output of the `gollum --versions` command (NB: `versions` in plural).
|
||||
@@ -0,0 +1,39 @@
|
||||
name: Deploy docker
|
||||
on: [push]
|
||||
env:
|
||||
DEPLOY_NAME: gollumwiki/gollum:latest
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
steps:
|
||||
- name: Check Out Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Login
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Cache docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
push: true
|
||||
tags: ${{ env.DEPLOY_NAME }}
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||
- name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
@@ -0,0 +1,38 @@
|
||||
name: Build and Test Docker
|
||||
on: [push, pull_request]
|
||||
env:
|
||||
CI_IMAGE: gollum-ci-img
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check Out Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Cache docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
- name: Build
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
push: false
|
||||
tags: ${{ env.CI_IMAGE }}
|
||||
outputs: type=docker
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||
- name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
- name: docker state
|
||||
run: docker image ls
|
||||
- name: Run gollum as test
|
||||
run: docker run -e CI=true ${{ env.CI_IMAGE }} --irb
|
||||
@@ -0,0 +1,25 @@
|
||||
on:
|
||||
push:
|
||||
# Sequence of patterns matched against refs/tags
|
||||
tags:
|
||||
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
|
||||
|
||||
name: Create Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Ruby Build
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
jruby_build:
|
||||
name: JRuby (${{ matrix.ruby }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: [jruby-9.2.18]
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
- name: List files in the repository
|
||||
run: |
|
||||
ls ${{ github.workspace }}
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
- name: Run tests
|
||||
run: bundle exec rake
|
||||
mri_build:
|
||||
name: Ruby (${{ matrix.ruby }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: [2.6, 2.7, 3.0]
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
- name: List files in the repository
|
||||
run: |
|
||||
ls ${{ github.workspace }}
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
- name: Run tests
|
||||
run: bundle exec rake
|
||||
@@ -5,3 +5,7 @@ pkg
|
||||
Gemfile.lock
|
||||
*.gem
|
||||
*.swp
|
||||
.*
|
||||
!.sprockets*
|
||||
!lib/gollum/public/gollum/stylesheets/_styles.css
|
||||
!.github*
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- 1.9.3
|
||||
notifications:
|
||||
disabled: true
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
@@ -0,0 +1,111 @@
|
||||
# Contributing to Gollum
|
||||
|
||||
Thanks for your interest in the gollum project!
|
||||
|
||||
## Submitting an Issue
|
||||
|
||||
Please note that the issue tracker is meant for:
|
||||
|
||||
1. Bug reports.
|
||||
2. Feature requests.
|
||||
|
||||
If your have problems using or installing the software which stem from bugs in the software or a lack of documentation, we are always happy to help out! However, **for ordinary usage questions, please consider asking elsewhere**, for instance on [StackOverflow](http://stackoverflow.com/questions/tagged/gollum-wiki).
|
||||
|
||||
Gollum supports [custom macros](https://github.com/gollum/gollum/wiki#macros) for the creation of additional wiki markup tags. Please **do not** use this tracker to request macros specific to your situation. However, if you have or are working on a macro that you think may be useful to more users, you can share it as a GitHub [gist](https://gist.github.com) and link to it in the [wiki](https://github.com/gollum/gollum/wiki/Custom-macros).
|
||||
|
||||
Before submitting an issue, **please carefully look through the following places** to make sure your problem is not already addressed:
|
||||
|
||||
1. The issue tracker.
|
||||
1. The [README](https://github.com/gollum/gollum/blob/master/README.md).
|
||||
1. The project's [wiki](https://github.com/gollum/gollum/wiki).
|
||||
|
||||
Security vulnerabilities can be reported directly to the maintainers using these GPG keys:
|
||||
|
||||
* [@dometto](https://keys.openpgp.org/vks/v1/by-fingerprint/02354CC9F820B52CC2791979BB8CCC95FD83B795)
|
||||
|
||||
Lastly, please **consider helping out** by opening a Pull Request!
|
||||
|
||||
## Triaging Issues [](https://www.codetriage.com/gollum/gollum)
|
||||
|
||||
You can triage issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to gollum on CodeTriage](https://www.codetriage.com/gollum/gollum).
|
||||
|
||||
|
||||
## Opening a Pull Request
|
||||
|
||||
Pull Requests fixing bugs, implementing new features, or updating documentation and dependencies are all very welcome! If you would like to help out with the project, you can pick an open issue from the issue tracker. We're more than happy to help you get started! Here's how you can proceed:
|
||||
|
||||
1. Fork and clone Gollum.
|
||||
2. Create a thoughtfully named topic branch to contain your changes.
|
||||
3. If you haven't installed dependencies yet, navigate to your clone and execute:
|
||||
```
|
||||
[sudo] bundle install
|
||||
```
|
||||
4. Hack away.
|
||||
5. Add your own tests and make sure they're all still passing.
|
||||
6. If some of your changes deserve a mention on Gollum's home page, edit the README accordingly.
|
||||
7. If necessary, rebase your commits into logical chunks, without errors.
|
||||
8. Push the branch to your fork on GitHub.
|
||||
9. Create a pull request for Gollum.
|
||||
|
||||
**Notes:**
|
||||
* Do not change Gollum's version numbers, we will do that on our own.
|
||||
|
||||
### Running tests
|
||||
|
||||
1. Install [Bundler](http://bundler.io/).
|
||||
2. Navigate to the cloned source of Gollum.
|
||||
3. Install dependencies:
|
||||
```
|
||||
[sudo] bundle install
|
||||
```
|
||||
4. Run the tests:
|
||||
```
|
||||
bundle exec rake test
|
||||
```
|
||||
|
||||
To profile slow tests, you can use `bundle exec rake test TESTOPTS="--verbose"`.
|
||||
|
||||
### Working with test repositories
|
||||
|
||||
An example of how to add a test file to the bare repository lotr.git.
|
||||
|
||||
```
|
||||
mkdir tmp
|
||||
cd tmp
|
||||
git clone ../test/examples/lotr.git/
|
||||
git log
|
||||
echo "test" > test.md
|
||||
git add .
|
||||
git commit -am "Add test"
|
||||
git push ../lotr.git/ master
|
||||
```
|
||||
|
||||
## Updating static assets
|
||||
|
||||
This is necessary whenever changes have been made to the assets in `lib/gollum/public/gollum/javascript` (mostly SASS, CSS, and JS files), to ensure the changes are also present in the [released](#releasing-the-gem) version of the gem. Steps:
|
||||
|
||||
1. `git rm -r lib/gollum/public/assets`
|
||||
1. `bundle exec rake precompile`
|
||||
1. `git add lib/gollum/public/assets`
|
||||
1. `git commit`
|
||||
|
||||
## Releasing the gem
|
||||
|
||||
Gollum uses [Semantic Versioning](http://semver.org/).
|
||||
|
||||
x.y.z
|
||||
|
||||
For z releases:
|
||||
|
||||
```
|
||||
rake bump
|
||||
rake release
|
||||
```
|
||||
|
||||
For x.y releases:
|
||||
|
||||
```
|
||||
# First update VERSION in lib/gollum.rb and then:
|
||||
rake gemspec
|
||||
rake release
|
||||
```
|
||||
@@ -0,0 +1,40 @@
|
||||
FROM ruby:2.7-alpine AS builder
|
||||
|
||||
RUN apk add \
|
||||
build-base \
|
||||
cmake \
|
||||
git \
|
||||
icu-dev \
|
||||
openssl-dev
|
||||
|
||||
COPY Gemfile* /tmp/
|
||||
COPY gollum.gemspec* /tmp/
|
||||
WORKDIR /tmp
|
||||
RUN bundle install
|
||||
|
||||
RUN gem install \
|
||||
asciidoctor \
|
||||
creole \
|
||||
wikicloth \
|
||||
org-ruby \
|
||||
RedCloth \
|
||||
bibtex-ruby \
|
||||
&& echo "gem-extra complete"
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
RUN bundle exec rake install
|
||||
|
||||
|
||||
FROM ruby:2.7-alpine
|
||||
|
||||
COPY --from=builder /usr/local/bundle/ /usr/local/bundle/
|
||||
|
||||
RUN apk add \
|
||||
bash \
|
||||
git
|
||||
|
||||
VOLUME /wiki
|
||||
WORKDIR /wiki
|
||||
COPY docker-run.sh /docker-run.sh
|
||||
ENTRYPOINT ["/docker-run.sh"]
|
||||
@@ -1,4 +1,26 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'warbler', platforms: :jruby
|
||||
|
||||
# FIXME:
|
||||
#
|
||||
# There's an issue in 1.12.5 that causes XHTML elements to be generated badly,
|
||||
# causing Gollum's test suite to fail.[1] The issue has been fixed upstream,
|
||||
# but we're still waiting for a new Nokogiri point release.
|
||||
#
|
||||
# However, 1.12.5 is a security patch, so we don't want end users to use an
|
||||
# older version of Nokogiri. But this is safe to do in our CI environment.
|
||||
#
|
||||
# Once there's a new Nokogiri release, we can remove this dependency and JRuby
|
||||
# CI should pass normally again.
|
||||
#
|
||||
# Note that Nokogiri 1.11+ does not support Ruby v2.4.x anymore. So to make our
|
||||
# current CI workflows pass, we should only try to install this version of
|
||||
# Nokogiri for newer Ruby versions.
|
||||
#
|
||||
# [1]: https://github.com/gollum/gollum/issues/1779
|
||||
gem 'nokogiri', '1.12.4' unless RUBY_VERSION.include? '2.4'
|
||||
|
||||
gemspec
|
||||
gem 'rake', '~> 10.0.2'
|
||||
|
||||
gem 'rake', '~> 13.0'
|
||||
|
||||
@@ -1,3 +1,82 @@
|
||||
# 5.2.3 2021-04-18
|
||||
|
||||
* Fix bug preventing page titles from being displayed
|
||||
|
||||
# 5.2.1 2021-02-25
|
||||
|
||||
* Fix include call to a missing asset (@benjaminwil). This caused slow first page loads on JRuby.
|
||||
|
||||
# 5.2 2021-02-24
|
||||
|
||||
* Improved styling and Primer upgrade (@benjaminwil)
|
||||
* Add redirect to rename commit (@ViChyavIn)
|
||||
* Updated dependencies
|
||||
* Bugfixes
|
||||
|
||||
# 5.1.2
|
||||
|
||||
* Guard against malicious filenames in breadcrumbs
|
||||
|
||||
# 5.1
|
||||
|
||||
* Bugfixes
|
||||
* Add autosave feature (#1576)
|
||||
* Add Add quick access to diff of each commit in the history
|
||||
|
||||
# 5.0 / 2020-03-17
|
||||
|
||||
This is a major new release that introduces many new features, bugfixes, and removes major limitations. See [here](https://github.com/gollum/gollum/wiki/5.0-release-notes) for a list of changes.
|
||||
|
||||
**Note**: due to changes to the way in which Gollum handles filenames, you may have to change some links in your wiki when migrating from gollum 4.x. See the [release notes](https://github.com/gollum/gollum/wiki/5.0-release-notes#migrating-your-wiki) for more details. You may be find the `bin/gollum-migrate-tags` script helpful to accomplish this. Also see the `--lenient-tag-lookup` option for making tag lookup backwards compatible with 4.x, though note that this will decrease performance on large wikis with many tags.
|
||||
|
||||
Many thanks to all the users who have provided feedback, and everyone who has chipped in in the development process!
|
||||
|
||||
Many of these changes have been made possible by removing the default grit adapter in favour of the new [rugged adapter](https://github.com/gollum/rugged_adapter).
|
||||
|
||||
# 4.1.4 /2018-01-10
|
||||
|
||||
* Depend on new version of gollum-lib that relies on a patched version of sanitize, which solves a vulnerability (CVE-2018-3740). See https://github.com/gollum/gollum-lib/pull/296.
|
||||
|
||||
# 4.1.3 /2018-17-09
|
||||
|
||||
* Solves a vulnerability in the File view and All Pages view that would allow XSS.
|
||||
|
||||
# 4.1.2 /2017-08-07
|
||||
|
||||
* Lock to a newer version of gollum-lib to avoid installing an outdated and vulnerable dependency (nokogiri) on ruby 2.0. See https://github.com/gollum/gollum-lib/pull/279. Note: this breaks semantic versioning so those using outdated rubies will discover the problem on update.
|
||||
|
||||
# 4.1.0 /2017-03-09
|
||||
|
||||
* Added file deletion functionality to file view
|
||||
* Various performance improvements
|
||||
* Emoji support
|
||||
|
||||
# 4.0.0 /2015-04-11
|
||||
|
||||
* Now compatible with JRuby (via the [rjgit](https://github.com/repotag/rjgit) [adapter](https://github.com/repotag/gollum-lib_rjgit_adapter))
|
||||
|
||||
# 3.1.1 /2014-12-04
|
||||
|
||||
* Security fix for [remote code execution issue](https://github.com/gollum/gollum/issues/913). Please update!
|
||||
|
||||
# 3.1 / 2014-11-28
|
||||
|
||||
* New features
|
||||
* Drag-and-drop uploading in the editor [@lucas-clemente](https://github.com/lucas-clemente)
|
||||
* Latest changes view [@etienneCharignon](https://github.com/etienneCharignon) (#707)
|
||||
* Option `--no-edit` to disable editing from the web interface [@bambycha](https://github.com/bambycha) (#879)
|
||||
* Option `--mathjax-config` to specify custom mathjax configuration [@hardywu](https://github.com/hardywu) (#842)
|
||||
* Major enhancements
|
||||
* Made the Gollum theme responsive [@rtrvrtg](https://github.com/rtrvrtg) (#831)
|
||||
* Depends on new [gollum-lib](https://github.com/gollum/gollum-lib) `4.0.0`
|
||||
* Allows specifiying [git adapter](https://github.com/gollum/gollum/wiki/Git-adapters) with `--adapter` [@bartkamphorst](https://github.com/bartkamphorst), [@dometto](https://github.com/dometto)
|
||||
* Numerous bugfixes
|
||||
* **NB**: please pass `--h1-title` if you do not want page titles to default to the page's filepath. See [here](https://github.com/gollum/gollum/wiki/Page-titles).
|
||||
|
||||
# 2.4.11 / 2013-01-08
|
||||
|
||||
* Numerous security issues have been fixed. Please update to `2.4.11`
|
||||
|
||||
# 1.4.0 / 2012-04-10
|
||||
|
||||
* Minor
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vulputate tincidunt sollicitudin. Quisque sit amet leo sed nunc eleifend rhoncus in consectetur leo. Vivamus posuere semper convallis. Duis malesuada lacus sed erat lobortis tincidunt mattis ligula consectetur. Sed aliquam vulputate eros at euismod. Aenean egestas lorem ligula, quis faucibus turpis. Curabitur a eros in ipsum gravida ornare. Sed elementum enim vel mi scelerisque dapibus. Nulla id libero ligula, quis tempus sem. Morbi nec felis tortor, ac cursus risus. Mauris elementum tortor id lacus eleifend non lobortis tellus pharetra. Etiam posuere cursus vestibulum. $x \lt y$
|
||||
|
||||
Morbi tincidunt dolor vel massa dictum volutpat. Vestibulum quis nibh metus, id tincidunt nisl. Vivamus eget sem ac risus eleifend rhoncus at eu nisl. Nunc elit massa, vulputate ac gravida eget, condimentum quis justo. Integer scelerisque, libero vel consequat ultricies, eros libero sagittis libero, pellentesque bibendum quam massa ut orci. Maecenas sit amet urna eget quam aliquam posuere. Nulla facilisi. Duis imperdiet augue sit amet metus ornare et hendrerit dui feugiat. Aenean a lacus neque. Sed eu enim tincidunt dolor pharetra porttitor. Vestibulum ut felis dui, rutrum iaculis orci. Duis eu bibendum tortor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse mollis sagittis purus sit amet sollicitudin. Phasellus vel interdum erat.
|
||||
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) Tom Preston-Werner, Rick Olson
|
||||
Copyright (c) Tom Preston-Werner, Rick Olson, Dawa Ometto, Bart Kamphorst
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the 'Software'), to deal
|
||||
|
||||
@@ -1,589 +1,156 @@
|
||||
gollum -- A wiki built on top of Git
|
||||
gollum -- A git-based Wiki
|
||||
====================================
|
||||
|
||||
[](http://travis-ci.org/github/gollum)
|
||||
[](https://gemnasium.com/github/gollum)
|
||||
[](http://badge.fury.io/rb/gollum)
|
||||

|
||||
[](https://www.codetriage.com/gollum/gollum)
|
||||
[](https://dometto-cuttingedge.herokuapp.com/github/gollum/gollum/info)
|
||||
|
||||
|
||||
**Gollum version 5.0 is out!** See [here](https://github.com/gollum/gollum/wiki/5.0-release-notes) for a list of changes and new features compared to Gollum version 4.x, and see some [Screenshots](https://github.com/gollum/gollum/wiki/Screenshots) of Gollum's features.
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Gollum is a simple wiki system built on top of Git that powers GitHub Wikis.
|
||||
Gollum is a simple wiki system built on top of Git. A Gollum Wiki is simply a git repository of a specific nature:
|
||||
* A Gollum repository's contents are human-editable text or markup files.
|
||||
* Pages may be organized into directories any way you choose.
|
||||
* Other content can also be included, for example images, PDFs and headers/footers for your pages.
|
||||
* Gollum pages:
|
||||
* May be written in a variety of [markups](#markups).
|
||||
* Can be edited with your favourite system editor or IDE (changes will be visible after committing) or with the built-in web interface.
|
||||
* Can be displayed in all versions, reverted, etc.
|
||||
* Gollum strives to be compatible with GitHub wikis (see `--lenient-tag-lookup`)
|
||||
* Gollum supports advanced functionality like:
|
||||
* [UML diagrams](https://github.com/gollum/gollum/wiki#plantuml-diagrams)
|
||||
* [BibTeX and Citation support](https://github.com/gollum/gollum/wiki/BibTeX-and-Citations)
|
||||
* Annotations using [CriticMarkup](https://github.com/gollum/gollum/wiki#criticmarkup-annotations)
|
||||
* Mathematics via [MathJax](https://github.com/gollum/gollum/wiki#mathematics)
|
||||
* [Macros](https://github.com/gollum/gollum/wiki/Standard-Macros)
|
||||
* [Redirects](https://github.com/gollum/gollum/wiki#redirects)
|
||||
* [RSS Feed](https://github.com/gollum/gollum/wiki/5.0-release-notes#rss-feed) of latest changes
|
||||
* ...and [more](https://github.com/gollum/gollum/wiki)
|
||||
|
||||
Gollum wikis are simply Git repositories that adhere to a specific format.
|
||||
Gollum pages may be written in a variety of formats and can be edited in a
|
||||
number of ways depending on your needs. You can edit your wiki locally:
|
||||
### SYSTEM REQUIREMENTS
|
||||
|
||||
* With your favorite text editor or IDE (changes will be visible after committing).
|
||||
* With the built-in web interface.
|
||||
* With the Gollum Ruby API.
|
||||
|
||||
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))
|
||||
Gollum runs on Unix-like systems using its [adapter](https://github.com/gollum/rugged_adapter) for [rugged](https://github.com/libgit2/rugged) by default. You can also run Gollum on [JRuby](https://github.com/jruby/jruby) via its [adapter](https://github.com/repotag/gollum-lib_rjgit_adapter) for [RJGit](https://github.com/repotag/rjgit/). On Windows, Gollum runs only on JRuby.
|
||||
|
||||
## INSTALLATION
|
||||
|
||||
The best way to install Gollum is with RubyGems:
|
||||
1. Ruby is best installed either via [RVM](https://rvm.io/) or a package manager of choice.
|
||||
2. Gollum is best installed via RubyGems:
|
||||
```
|
||||
[sudo] gem install gollum
|
||||
```
|
||||
|
||||
$ [sudo] gem install gollum
|
||||
Installation examples for individual systems can be seen [here](https://github.com/gollum/gollum/wiki/Installation).
|
||||
|
||||
If you're installing from source, you can use [Bundler][bundler] to pick up all the
|
||||
gems:
|
||||
To run, simply:
|
||||
|
||||
$ bundle install
|
||||
1. Run: `gollum /path/to/wiki` where `/path/to/wiki` is an initialized Git repository.
|
||||
2. Open `http://localhost:4567` in your browser.
|
||||
|
||||
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.
|
||||
See [below](#running-from-source) for information on running Gollum from source, as a Rack app, and more.
|
||||
|
||||
* [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`
|
||||
* [Org](http://orgmode.org/) -- `gem install org-ruby`
|
||||
* [Pod](http://search.cpan.org/dist/perl/pod/perlpod.pod) -- `Pod::Simple::HTML` comes with Perl >= 5.10. Lower versions should install Pod::Simple from CPAN.
|
||||
### Markups
|
||||
|
||||
Gollum allows using different markup languages on different wiki pages. It presently ships with support for the following markups:
|
||||
* [Markdown](http://daringfireball.net/projects/markdown/syntax) (see [below](#Markdown-flavors) for more information on Markdown flavors)
|
||||
* [RDoc](http://rdoc.sourceforge.net/)
|
||||
* [ReStructuredText](http://docutils.sourceforge.net/rst.html) -- `easy_install docutils`
|
||||
* [Textile](http://www.textism.com/tools/textile/) -- `gem install RedCloth`
|
||||
* [MediaWiki](http://www.mediawiki.org/wiki/Help:Formatting) -- `gem install wikicloth`
|
||||
|
||||
[bundler]: http://gembundler.com/
|
||||
You can easily activate support for other markups by installing additional renderers (any that are supported by [github-markup](https://github.com/github/markup)):
|
||||
* [AsciiDoc](http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/) -- `[sudo] gem install asciidoctor`
|
||||
* [Creole](http://www.wikicreole.org/wiki/CheatSheet) -- `[sudo] gem install creole`
|
||||
* [MediaWiki](http://www.mediawiki.org/wiki/Help:Formatting) -- `[sudo] gem install wikicloth`
|
||||
* [Org](http://orgmode.org/worg/dev/org-syntax.html) -- `[sudo] gem install org-ruby`
|
||||
* [Pod](http://perldoc.perl.org/perlpod.html) -- requires Perl >= 5.10 (the `perl` command must be available on your command line)
|
||||
* Lower versions should install `Pod::Simple` from CPAN.
|
||||
* [ReStructuredText](http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html) -- requires python >= 2 (the `python2` command must be available on your command line)
|
||||
* Note that Gollum will also need you to install `docutils` for your Python 2.
|
||||
* [Textile](http://redcloth.org/hobix.com/textile/quick.html) -- `[sudo] gem install RedCloth`
|
||||
|
||||
## RUNNING
|
||||
### Markdown flavors
|
||||
|
||||
To view and edit your Gollum repository locally via the built in web
|
||||
interface, simply install the Gollum gem, navigate to your repository via the
|
||||
command line, and run the executable:
|
||||
By default, Gollum ships with the `kramdown` gem to render Markdown. However, you can use any [Markdown renderer supported by github-markup](https://github.com/github/markup/blob/master/lib/github/markup/markdown.rb). This includes [CommonMark](https://commonmark.org/) support via the `commonmarker` gem. The first installed renderer from the list will be used (e.g., `redcarpet` will NOT be used if `github/markdown` is installed). Just `gem install` the renderer of your choice.
|
||||
|
||||
$ gollum
|
||||
See [here](https://github.com/gollum/gollum/wiki/Custom-rendering-gems) for instructions on how to use custom rendering gems and set custom options.
|
||||
|
||||
This will start up a web server running the Gollum frontend and you can view
|
||||
and edit your wiki at http://localhost:4567. To get help on the command line
|
||||
utility, you can run it like so:
|
||||
## RUNNING FROM SOURCE
|
||||
|
||||
$ gollum --help
|
||||
1. `git clone https://github.com/gollum/gollum`
|
||||
2. `cd gollum`
|
||||
3. `[sudo] bundle install`
|
||||
4. `bundle exec bin/gollum`
|
||||
5. Open `http://localhost:4567` in your browser.
|
||||
|
||||
Note that the gollum server will not run on Windows because of [an issue](https://github.com/rtomayko/posix-spawn/issues/9) with posix-spawn (which is used by Grit).
|
||||
### Rack
|
||||
|
||||
## REPO STRUCTURE
|
||||
Gollum can also be run with any [rack-compatible web server](https://github.com/rack/rack#supported-web-servers). More on that [over here](https://github.com/gollum/gollum/wiki/Gollum-via-Rack).
|
||||
|
||||
A Gollum repository's contents are designed to be human editable. Page content
|
||||
is written in `page files` and may be organized into directories any way you
|
||||
choose. Special footers can be created in `footer files`. Other content
|
||||
(images, PDFs, etc) may also be present and organized in the same way.
|
||||
### Rack, with an authentication server
|
||||
|
||||
Gollum can also be run alongside a CAS (Central Authentication Service) SSO (single sign-on) server. With a bit of tweaking, this adds basic user-support to Gollum. To see an example and an explanation, navigate [over here](https://github.com/gollum/gollum/wiki/Gollum-via-Rack-and-CAS-SSO).
|
||||
|
||||
## PAGE FILES
|
||||
### Docker
|
||||
|
||||
Page files may be written in any format supported by
|
||||
[GitHub-Markup](http://github.com/github/markup) (except roff). The
|
||||
current list of formats and allowed extensions is:
|
||||
Gollum can also be run via [Docker](https://www.docker.com/). More on that [over here](https://github.com/gollum/gollum/wiki/Gollum-via-Docker).
|
||||
|
||||
* ASCIIDoc: .asciidoc
|
||||
* Creole: .creole
|
||||
* Markdown: .markdown, .mdown, .mkdn, .mkd, .md
|
||||
* Org Mode: .org
|
||||
* Pod: .pod
|
||||
* RDoc: .rdoc
|
||||
* ReStructuredText: .rest.txt, .rst.txt, .rest, .rst
|
||||
* Textile: .textile
|
||||
* MediaWiki: .mediawiki, .wiki
|
||||
### Service
|
||||
|
||||
Gollum detects the page file format via the extension, so files must have one
|
||||
of the supported extensions in order to be converted.
|
||||
Gollum can also be run as a service. More on that [over here](https://github.com/gollum/gollum/wiki/Gollum-as-a-service).
|
||||
|
||||
Page file names may contain any printable UTF-8 character except space
|
||||
(U+0020) and forward slash (U+002F). If you commit a page file with any of
|
||||
these characters in the name it will not be accessible via the web interface.
|
||||
## CONFIGURATION
|
||||
|
||||
Even though page files may be placed in any directory, there is still only a
|
||||
single namespace for page names, so all page files should have globally unique
|
||||
names regardless of where they are located in the repository.
|
||||
Gollum comes with the following command line options:
|
||||
|
||||
The special page file `Home.ext` (where the extension is one of the supported
|
||||
formats) will be used as the entrance page to your wiki. If it is missing, an
|
||||
automatically generated table of contents will be shown instead.
|
||||
| Option | Arguments | Description |
|
||||
| ----------------- | --------- | ----------- |
|
||||
| --host | [HOST] | Specify the hostname or IP address to listen on. Default: '0.0.0.0'.<sup>1</sup> |
|
||||
| --port | [PORT] | Specify the port to bind Gollum with. Default: `4567`. |
|
||||
| --config | [FILE] | Specify path to Gollum's configuration file. |
|
||||
| --ref | [REF] | Specify the git branch to serve. Default: `master`. |
|
||||
| --bare | none | Tell Gollum that the git repository should be treated as bare. |
|
||||
| --adapter | [ADAPTER] | Launch Gollum using a specific git adapter. Default: `rugged`.<sup>2</sup> |
|
||||
| --base-path | [PATH] | Specify the leading portion of all Gollum URLs (path info). Setting this to `/wiki` will make the wiki accessible under `http://localhost:4567/wiki/`. Default: `/`. |
|
||||
| --page-file-dir | [PATH] | Specify the subdirectory for all pages. If set, Gollum will only serve pages from this directory and its subdirectories. Default: repository root. |
|
||||
| --static, --no-static | none | Use static assets. Defaults to false in development/test, true in production/staging. |
|
||||
| --assets | [PATH] | Set the path to look for static assets. |
|
||||
| --css | none | Tell Gollum to inject custom CSS into each page. Uses `custom.css` from wiki root.<sup>3</sup> |
|
||||
| --js | none | Tell Gollum to inject custom JS into each page. Uses `custom.js` from wiki root.<sup>3</sup> |
|
||||
| --no-edit | none | Disable the feature of editing pages. |
|
||||
| --follow-renames, --no-follow-renames | none | Follow pages across renames in the History view. Default: true.
|
||||
| --allow-uploads | [MODE] | Enable file uploads. If set to `dir`, Gollum will store all uploads in the `/uploads/` directory in repository root. If set to `page`, Gollum will store each upload at the currently edited page.<sup>4</sup> |
|
||||
| --mathjax | none | Enables MathJax (renders mathematical equations). By default, uses the `TeX-AMS-MML_HTMLorMML` config with the `autoload-all` extension.<sup>5</sup> |
|
||||
| --critic-markup | none | Enable support for annotations using [CriticMarkup](http://criticmarkup.com/). |
|
||||
| --irb | none | Launch Gollum in "console mode", with a [predefined API](https://github.com/gollum/gollum-lib/). |
|
||||
| --h1-title | none | Tell Gollum to use the first `<h1>` as page title. |
|
||||
| --no-display-metadata | none | Do not render metadata tables in pages. |
|
||||
| --user-icons | [MODE] | Tell Gollum to use specific user icons for history view. Can be set to `gravatar`, `identicon` or `none`. Default: `none`. |
|
||||
| --mathjax-config | [FILE] | Specify path to a custom MathJax configuration. If not specified, uses the `mathjax.config.js` file from repository root. |
|
||||
| --template-dir | [PATH] | Specify custom mustache template directory. Only overrides templates that exist in this directory. |
|
||||
| --template-page | none | Use _Template in root as a template for new pages. Must be committed. |
|
||||
| --emoji | none | Parse and interpret emoji tags (e.g. `:heart:`) except when the leading colon is backslashed (e.g. `\:heart:`). |
|
||||
| --lenient-tag-lookup | none | Internal links resolve case-insensitively, will treat spaces as hyphens, and will match the first page found with a certain filename, anywhere in the repository. Provides compatibility with Gollum 4.x. |
|
||||
| --help | none | Display the list of options on the command line. |
|
||||
| --version | none | Display the current version of Gollum. |
|
||||
| --versions | none | Display the current version of Gollum and auxiliary gems. |
|
||||
|
||||
## SIDEBAR FILES
|
||||
**Notes:**
|
||||
|
||||
Sidebar files allow you to add a simple sidebar to your wiki. Sidebar files
|
||||
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.
|
||||
1. The `0.0.0.0` IP address allows remote access. Should you wish for Gollum to turn into a personal Wiki, use `127.0.0.1`.
|
||||
2. Before using `--adapter`, you should probably read [this](https://github.com/gollum/gollum/wiki/Git-adapters) first.
|
||||
3. When `--css` or `--js` is used, respective files must be committed to your git repository or you will get a 302 redirect to the create a page.
|
||||
4. Files can be uploaded simply by dragging and dropping them onto the editor's text area when `--allow-uploads` is used.
|
||||
|
||||
## HEADER FILES
|
||||
### Config file
|
||||
|
||||
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.
|
||||
When `--config` option is used, certain inner parts of Gollum can be customized. This is used throughout our wiki for certain user-level alterations, among which [customizing supported markups](https://github.com/gollum/gollum/wiki/Formats-and-extensions) will probably stand out.
|
||||
|
||||
## FOOTER FILES
|
||||
**All of the mentioned alterations work both for Gollum's config file (`config.rb`) and Rack's config file (`config.ru`).**
|
||||
|
||||
Footer files allow you to add a simple footer to your wiki. Footer files must
|
||||
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.
|
||||
## CONTRIBUTING
|
||||
|
||||
## HTML SANITIZATION
|
||||
Please consider helping out! See [CONTRIBUTING](CONTRIBUTING.md) for information on how to submit issues, and how to start hacking on gollum.
|
||||
|
||||
For security and compatibility reasons Gollum wikis may not contain custom CSS
|
||||
or JavaScript. These tags will be stripped from the converted HTML. See
|
||||
`docs/sanitization.md` for more details on what tags and attributes are
|
||||
allowed.
|
||||
## THANKS TO
|
||||
|
||||
## TITLES
|
||||
|
||||
The first defined `h1` will override the default header on a page. There are two ways to set a page title. The metadata syntax:
|
||||
|
||||
`<!-- --- title: New Title -->`
|
||||
|
||||
The first `h1` tag can be set to always override the page title, without needing to use the metadata syntax. Start gollum with the `--h1-title` flag.
|
||||
## BRACKET TAGS
|
||||
|
||||
A variety of Gollum tags use a double bracket syntax. For example:
|
||||
|
||||
[[Link]]
|
||||
|
||||
Some tags will accept attributes which are separated by pipe symbols. For
|
||||
example:
|
||||
|
||||
[[Link|Page Title]]
|
||||
|
||||
In all cases, the first thing in the link is what is displayed on the page.
|
||||
So, if the tag is an internal wiki link, the first thing in the tag will be
|
||||
the link text displayed on the page. If the tag is an embedded image, the
|
||||
first thing in the tag will be a path to an image file. Use this trick to
|
||||
easily remember which order things should appear in tags.
|
||||
|
||||
Some formats, such as MediaWiki, support the opposite syntax:
|
||||
|
||||
[[Page Title|Link]]
|
||||
|
||||
## PAGE LINKS
|
||||
|
||||
To link to another Gollum wiki page, use the Gollum Page Link Tag.
|
||||
|
||||
[[Frodo Baggins]]
|
||||
|
||||
The above tag will create a link to the corresponding page file named
|
||||
`Frodo-Baggins.ext` where `ext` may be any of the allowed extension types. The
|
||||
conversion is as follows:
|
||||
|
||||
1. Replace any spaces (U+0020) with dashes (U+002D)
|
||||
2. Replace any slashes (U+002F) with dashes (U+002D)
|
||||
|
||||
If you'd like the link text to be something that doesn't map directly to the
|
||||
page name, you can specify the actual page name after a pipe:
|
||||
|
||||
[[Frodo|Frodo Baggins]]
|
||||
|
||||
The above tag will link to `Frodo-Baggins.ext` using "Frodo" as the link text.
|
||||
|
||||
The page file may exist anywhere in the directory structure of the repository.
|
||||
Gollum does a breadth first search and uses the first match that it finds.
|
||||
|
||||
Here are a few more examples:
|
||||
|
||||
[[J. R. R. Tolkien]] -> J.-R.-R.-Tolkien.ext
|
||||
[[Movies / The Hobbit]] -> Movies---The-Hobbit.ext
|
||||
[[モルドール]] -> モルドール.ext
|
||||
|
||||
|
||||
## EXTERNAL LINKS
|
||||
|
||||
As a convenience, simple external links can be placed within brackets and they
|
||||
will be linked to the given URL with the URL as the link text. For example:
|
||||
|
||||
[[http://example.com]]
|
||||
|
||||
External links must begin with either "http://" or "https://". If you need
|
||||
something more flexible, you can resort to the link syntax in the page's
|
||||
underlying markup format.
|
||||
|
||||
|
||||
## ABSOLUTE VS. RELATIVE VS. EXTERNAL PATH
|
||||
|
||||
For Gollum tags that operate on static files (images, PDFs, etc), the paths
|
||||
may be referenced as either relative, absolute, or external. Relative paths
|
||||
point to a static file relative to the page file within the directory
|
||||
structure of the Gollum repo (even though after conversion, all page files
|
||||
appear to be top level). These paths are NOT prefixed with a slash. For
|
||||
example:
|
||||
|
||||
gollum.pdf
|
||||
docs/diagram.png
|
||||
|
||||
Absolute paths point to a static file relative to the Gollum repo's
|
||||
root, regardless of where the page file is stored within the directory
|
||||
structure. These paths ARE prefixed with a slash. For example:
|
||||
|
||||
/pdfs/gollum.pdf
|
||||
/docs/diagram.png
|
||||
|
||||
External paths are full URLs. An external path must begin with either
|
||||
"http://" or "https://". For example:
|
||||
|
||||
http://example.com/pdfs/gollum.pdf
|
||||
http://example.com/images/diagram.png
|
||||
|
||||
All of the examples in this README use relative paths, but you may use
|
||||
whatever works best in your situation.
|
||||
|
||||
|
||||
## FILE LINKS
|
||||
|
||||
To link to static files that are contained in the Gollum repository you should
|
||||
use the Gollum File Link Tag.
|
||||
|
||||
[[Gollum|gollum.pdf]]
|
||||
|
||||
The first part of the tag is the link text. The path to the file appears after
|
||||
the pipe.
|
||||
|
||||
|
||||
## IMAGES
|
||||
|
||||
To display images that are contained in the Gollum repository you should use
|
||||
the Gollum Image Tag. This will display the actual image on the page.
|
||||
|
||||
[[gollum.png]]
|
||||
|
||||
In addition to the simple format, there are a variety of options that you
|
||||
can specify between pipe delimiters.
|
||||
|
||||
To specify alt text, use the `alt=` option. Default is no alt text.
|
||||
|
||||
[[gollum.png|alt=Gollum and his precious wiki]]
|
||||
|
||||
To place the image in a frame, use the `frame` option. When combined with the
|
||||
`alt=` option, the alt text will be used as a caption as well. Default is no
|
||||
frame.
|
||||
|
||||
[[gollum.png|frame|alt=Gollum and his precious wiki]]
|
||||
|
||||
To specify the alignment of the image on the page, use the `align=` option.
|
||||
Possible values are `left`, `center`, and `right`. Default is `left`.
|
||||
|
||||
[[gollum.png|align=center]]
|
||||
|
||||
To float an image so that text flows around it, use the `float` option. When
|
||||
`float` is specified, only `left` and `right` are valid `align` options.
|
||||
Default is not floating. When floating is activated but no alignment is
|
||||
specified, default alignment is `left`.
|
||||
|
||||
[[gollum.png|float]]
|
||||
|
||||
To specify a max-width, use the `width=` option. Units must be specified in
|
||||
either `px` or `em`.
|
||||
|
||||
[[gollum.png|width=400px]]
|
||||
|
||||
To specify a max-height, use the `height=` option. Units must be specified in
|
||||
either `px` or `em`.
|
||||
|
||||
[[gollum.png|height=300px]]
|
||||
|
||||
Any of these options may be composed together by simply separating them with
|
||||
pipes.
|
||||
|
||||
|
||||
## ESCAPING GOLLUM TAGS
|
||||
|
||||
If you need the literal text of a wiki or static link to show up in your final
|
||||
wiki page, simply preface the link with a single quote (like in LISP):
|
||||
|
||||
'[[Page Link]]
|
||||
'[[File Link|file.pdf]]
|
||||
'[[image.jpg]]
|
||||
|
||||
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
|
||||
|
||||
In page files you can get automatic syntax highlighting for a wide range of
|
||||
languages (courtesy of [Pygments](http://pygments.org/) - must install
|
||||
separately) by using the following syntax:
|
||||
|
||||
```ruby
|
||||
def foo
|
||||
puts 'bar'
|
||||
end
|
||||
```
|
||||
|
||||
The block must start with three backticks, at the beginning of a line or
|
||||
indented with any number of spaces or tabs.
|
||||
After that comes the name of the language that is contained by the
|
||||
block. The language must be one of the `short name` lexer strings supported by
|
||||
Pygments. See the [list of lexers](http://pygments.org/docs/lexers/) for valid
|
||||
options.
|
||||
|
||||
The block contents should be indented at the same level than the opening backticks.
|
||||
If the block contents are indented with an additional two spaces or one tab,
|
||||
then that whitespace will be ignored (this makes the blocks easier to read in plaintext).
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
Inline math:
|
||||
|
||||
- $2^2$
|
||||
- `\\(2^2\\)`
|
||||
|
||||
Display math:
|
||||
|
||||
- $$2^2$$
|
||||
- [2^2]
|
||||
|
||||
## SEQUENCE DIAGRAMS
|
||||
|
||||
You may imbed sequence diagrams into your wiki page (rendered by
|
||||
[WebSequenceDiagrams](http://www.websequencediagrams.com) by using the
|
||||
following syntax:
|
||||
|
||||
{{{{{{ blue-modern
|
||||
alice->bob: Test
|
||||
bob->alice: Test response
|
||||
}}}}}}
|
||||
|
||||
You can replace the string "blue-modern" with any supported style.
|
||||
|
||||
## API DOCUMENTATION
|
||||
|
||||
The Gollum API allows you to retrieve raw or formatted wiki content from a Git
|
||||
repository, write new content to the repository, and collect various meta data
|
||||
about the wiki as a whole.
|
||||
|
||||
Initialize the Gollum::Repo object:
|
||||
|
||||
# Require rubygems if necessary
|
||||
require 'rubygems'
|
||||
|
||||
# Require the Gollum library
|
||||
require 'gollum'
|
||||
|
||||
# Create a new Gollum::Wiki object by initializing it with the path to the
|
||||
# Git repository.
|
||||
wiki = Gollum::Wiki.new("my-gollum-repo.git")
|
||||
# => <Gollum::Wiki>
|
||||
|
||||
By default, internal wiki links are all absolute from the root. To specify a different base path, you can specify the `:base_path` option:
|
||||
|
||||
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')
|
||||
# => <Gollum::Page>
|
||||
|
||||
page.raw_data
|
||||
# => "# My wiki page"
|
||||
|
||||
page.formatted_data
|
||||
# => "<h1>My wiki page</h1>"
|
||||
|
||||
page.format
|
||||
# => :markdown
|
||||
|
||||
vsn = page.version
|
||||
# => <Grit::Commit>
|
||||
|
||||
vsn.id
|
||||
# => '3ca43e12377ea1e32ea5c9ce5992ec8bf266e3e5'
|
||||
|
||||
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:
|
||||
|
||||
vsns = wiki.page('page-name').versions
|
||||
# => [<Grit::Commit, <Grit::Commit, <Grit::Commit>]
|
||||
|
||||
vsns.first.id
|
||||
# => '3ca43e12377ea1e32ea5c9ce5992ec8bf266e3e5'
|
||||
|
||||
vsns.first.authored_date
|
||||
# => Sun Mar 28 19:11:21 -0700 2010
|
||||
|
||||
Get a specific version of a given canonical page file:
|
||||
|
||||
wiki.page('page-name', '5ec521178e0eec4dc39741a8978a2ba6616d0f0a')
|
||||
|
||||
Get the latest version of a given static file:
|
||||
|
||||
file = wiki.file('asset.js')
|
||||
# => <Gollum::File>
|
||||
|
||||
file.raw_data
|
||||
# => "alert('hello');"
|
||||
|
||||
file.version
|
||||
# => <Grit::Commit>
|
||||
|
||||
Get a specific version of a given static file:
|
||||
|
||||
wiki.file('asset.js', '5ec521178e0eec4dc39741a8978a2ba6616d0f0a')
|
||||
|
||||
Get an in-memory Page preview (useful for generating previews for web
|
||||
interfaces):
|
||||
|
||||
preview = wiki.preview_page("My Page", "# Contents", :markdown)
|
||||
preview.formatted_data
|
||||
# => "<h1>Contents</h1>"
|
||||
|
||||
Methods that write to the repository require a Hash of commit data that takes
|
||||
the following form:
|
||||
|
||||
commit = { :message => 'commit message',
|
||||
:name => 'Tom Preston-Werner',
|
||||
:email => 'tom@github.com' }
|
||||
|
||||
Write a new version of a page (the file will be created if it does not already
|
||||
exist) and commit the change. The file will be written at the repo root.
|
||||
|
||||
wiki.write_page('Page Name', :markdown, 'Page contents', commit)
|
||||
|
||||
Update an existing page. If the format is different than the page's current
|
||||
format, the file name will be changed to reflect the new format.
|
||||
|
||||
page = wiki.page('Page Name')
|
||||
wiki.update_page(page, page.name, page.format, 'Page contents', commit)
|
||||
|
||||
To delete a page and commit the change:
|
||||
|
||||
wiki.delete_page(page, commit)
|
||||
|
||||
### RACK
|
||||
|
||||
You can also run gollum with any rack-compatible server by placing this config.ru
|
||||
file inside your wiki repository. This allows you to utilize any Rack middleware
|
||||
like Rack::Auth, OmniAuth, etc.
|
||||
|
||||
#!/usr/bin/env ruby
|
||||
require 'rubygems'
|
||||
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.
|
||||
|
||||
## CONFIG FILE
|
||||
|
||||
Gollum optionally takes a `--config file`. See [config.rb](https://github.com/github/gollum/blob/master/config.rb) for an example.
|
||||
|
||||
## CUSTOM CSS
|
||||
|
||||
The `--css` flag will inject `custom.css` from the root of your git repository into each page. `custom.css` must be commited to git or you will get a 302 redirect to the create page. Here's an example of floating the sidebar to the left.
|
||||
|
||||
```css
|
||||
#wiki-rightbar { float: left !important; }
|
||||
```
|
||||
|
||||
## CONTRIBUTE
|
||||
|
||||
If you'd like to hack on Gollum, start by forking my repo on GitHub:
|
||||
|
||||
http://github.com/github/gollum
|
||||
|
||||
To get all of the dependencies, install the gem first. The best way to get
|
||||
your changes merged back into core is as follows:
|
||||
|
||||
1. Clone down your fork
|
||||
1. Create a thoughtfully named topic branch to contain your change
|
||||
1. Hack away
|
||||
1. Add tests and make sure everything still passes by running `rake`
|
||||
1. If you are adding new functionality, document it in the README
|
||||
1. Do not change the version number, I will do that on my end
|
||||
1. If necessary, rebase your commits into logical chunks, without errors
|
||||
1. Push the branch up to GitHub
|
||||
1. Send a pull request to the github/gollum project.
|
||||
|
||||
## RELEASING
|
||||
x.y.z
|
||||
|
||||
For z releases:
|
||||
$ rake bump
|
||||
$ rake release
|
||||
|
||||
For x.y releases:
|
||||
Update VERSION in lib/gollum.rb
|
||||
$ rake gemspec
|
||||
$ 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
|
||||
[](https://saucelabs.com)
|
||||
|
||||
@@ -71,6 +71,7 @@ Rake::TestTask.new(:test) do |test|
|
||||
test.libs << 'lib' << 'test' << '.'
|
||||
test.pattern = 'test/**/test_*.rb'
|
||||
test.verbose = true
|
||||
test.warning = false
|
||||
end
|
||||
|
||||
desc "Generate RCov test coverage and open in your browser"
|
||||
@@ -107,20 +108,23 @@ end
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
desc 'Create a release build'
|
||||
desc 'Create a release build and push to rubygems'
|
||||
task :release => :build do
|
||||
unless `git branch` =~ /^\* master$/
|
||||
puts "You must be on the master branch to release!"
|
||||
exit!
|
||||
end
|
||||
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
||||
sh "git pull"
|
||||
sh "git pull --rebase origin master"
|
||||
sh "git tag v#{version}"
|
||||
sh "git push origin master"
|
||||
sh "git push origin v#{version}"
|
||||
sh "gem push pkg/#{name}-#{version}.gem"
|
||||
end
|
||||
|
||||
desc 'Publish to rubygems. Same as release'
|
||||
task :publish => :release
|
||||
|
||||
desc 'Build gem'
|
||||
task :build => :gemspec do
|
||||
sh "mkdir -p pkg"
|
||||
@@ -128,6 +132,11 @@ task :build => :gemspec do
|
||||
sh "mv #{gem_file} pkg"
|
||||
end
|
||||
|
||||
desc "Build and install"
|
||||
task :install => :build do
|
||||
sh "gem install --local --no-document pkg/#{name}-#{version}.gem"
|
||||
end
|
||||
|
||||
desc 'Update gemspec'
|
||||
task :gemspec => :validate do
|
||||
# read spec file and split out manifest section
|
||||
@@ -169,3 +178,21 @@ task :validate do
|
||||
exit!
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Precompile assets'
|
||||
task :precompile do
|
||||
require './lib/gollum/app.rb'
|
||||
Precious::App.set(:environment, :production)
|
||||
env = Precious::Assets.sprockets
|
||||
path = ENV.fetch('GOLLUM_ASSETS_PATH', ::File.join(File.dirname(__FILE__), 'lib/gollum/public/assets'))
|
||||
manifest = Sprockets::Manifest.new(env, path)
|
||||
Sprockets::Helpers.configure do |config|
|
||||
config.environment = env
|
||||
config.prefix = Precious::Assets::ASSET_URL
|
||||
config.digest = true
|
||||
config.public_path = path
|
||||
config.manifest = manifest
|
||||
end
|
||||
puts "Precompiling assets to #{path}..."
|
||||
manifest.compile(Precious::Assets::MANIFEST)
|
||||
end
|
||||
|
||||
@@ -2,108 +2,217 @@
|
||||
|
||||
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
||||
|
||||
help = <<HELP
|
||||
Gollum is a multi-format Wiki Engine/API/Frontend.
|
||||
|
||||
Basic Command Line Usage:
|
||||
gollum [OPTIONS] [PATH]
|
||||
|
||||
PATH The path to the Gollum repository (default .).
|
||||
|
||||
Options:
|
||||
HELP
|
||||
|
||||
require 'optparse'
|
||||
require 'rubygems'
|
||||
require 'gollum'
|
||||
require 'erb'
|
||||
require 'sprockets'
|
||||
|
||||
exec = {}
|
||||
options = { 'port' => 4567, 'bind' => '0.0.0.0' }
|
||||
wiki_options = {}
|
||||
exec = {}
|
||||
options = {
|
||||
:port => 4567,
|
||||
:bind => '0.0.0.0',
|
||||
}
|
||||
wiki_options = {
|
||||
:allow_uploads => false,
|
||||
:allow_editing => true,
|
||||
}
|
||||
|
||||
opts = OptionParser.new do |opts|
|
||||
opts.banner = help
|
||||
# define program name (although this defaults to the name of the file, just in case...)
|
||||
opts.program_name = 'gollum'
|
||||
|
||||
opts.on("--port [PORT]", "Bind port (default 4567).") do |port|
|
||||
options['port'] = port.to_i
|
||||
# set basic info for the '--help' command (options will be appended automatically from the below definitions)
|
||||
opts.banner = '
|
||||
Gollum is a multi-format Wiki Engine/API/Frontend.
|
||||
|
||||
Usage:
|
||||
gollum [options] [git-repo]
|
||||
|
||||
Arguments:
|
||||
[git-repo] Path to the git repository being served. If not specified, current working directory is used.
|
||||
|
||||
Notes:
|
||||
Paths for all options are relative to <git-repo> unless absolute.
|
||||
This message is only a basic description. For more information, please visit:
|
||||
https://github.com/gollum/gollum
|
||||
|
||||
OPTIONS'
|
||||
|
||||
# define gollum options
|
||||
opts.separator ''
|
||||
opts.separator ' Major:'
|
||||
|
||||
opts.on('-h', '--host [HOST]', 'Specify the hostname or IP address to listen on. Default: \'0.0.0.0\'.') do |host|
|
||||
options[:bind] = host
|
||||
end
|
||||
opts.on('-p', '--port [PORT]', 'Specify the port to bind Gollum with. Default: \'4567\'.') do |port|
|
||||
begin
|
||||
# don't use 'port.to_i' here... it doesn't raise errors which might result in a nice confusion later on
|
||||
options[:port] = Integer(port)
|
||||
rescue ArgumentError
|
||||
puts "Error: '#{port}' is not a valid port number."
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
opts.on('-c', '--config [FILE]', 'Specify path to the Gollum\'s configuration file.') do |file|
|
||||
options[:config] = file
|
||||
end
|
||||
opts.on('-r', '--ref [REF]', 'Specify the branch to serve. Default: \'master\'.') do |ref|
|
||||
wiki_options[:ref] = ref
|
||||
end
|
||||
opts.on("--bare", "Declare '<git-repo>' to be bare.") do
|
||||
wiki_options[:repo_is_bare] = true
|
||||
end
|
||||
opts.on('-a', '--adapter [ADAPTER]', 'Launch Gollum using a specific git adapter. Default: \'rugged\'.') do |adapter|
|
||||
Gollum::GIT_ADAPTER = adapter
|
||||
end
|
||||
opts.on('-b', '--base-path [PATH]', 'Specify the leading portion of all Gollum URLs (path info). Default: \'/\'.',
|
||||
'Example: setting this to \'/wiki\' will make the wiki accessible under \'http://localhost:4567/wiki/\'.') do |base_path|
|
||||
|
||||
# first trim a leading slash, if any
|
||||
base_path.sub!(/^\/+/, '')
|
||||
|
||||
# make a backup of the option and sanitize it
|
||||
base_path_original = base_path.dup
|
||||
base_path = ERB::Util.url_encode(base_path)
|
||||
base_path.gsub!('%2F', '/')
|
||||
|
||||
# then let the user know if we changed the URL
|
||||
unless base_path_original == base_path
|
||||
puts <<MSG
|
||||
Warning: your base-path has been sanitized:
|
||||
- original: "#{base_path_original}"
|
||||
- sanitized: "#{base_path}"
|
||||
MSG
|
||||
end
|
||||
|
||||
# and finally, let others enjoy our hard work:
|
||||
wiki_options[:base_path] = base_path unless base_path.empty?
|
||||
end
|
||||
opts.on('--page-file-dir [PATH]', 'Specify the subdirectory for all pages. Default: repository root.',
|
||||
'Example: setting this to \'pages\' will make Gollum serve only pages at \'<git-repo>/pages/*\'.') do |path|
|
||||
wiki_options[:page_file_dir] = path
|
||||
end
|
||||
opts.on('--static', 'Use static assets. Defaults to false in development/test, defaults to true in production/staging.') do
|
||||
wiki_options[:static] = true
|
||||
end
|
||||
opts.on('--no-static', 'Do not use static assets (even when in production/staging).') do
|
||||
wiki_options[:static] = false
|
||||
end
|
||||
opts.on('--assets [PATH]', 'Set the path to look for static assets. Only used if --static is set to true, or environment is production/staging. Default: ./public/assets') do |path|
|
||||
wiki_options[:static_assets_path] = path
|
||||
end
|
||||
opts.on('--css', 'Inject custom CSS into each page. The \'<wiki-root>/custom.css\' file is used (must be committed).') do
|
||||
wiki_options[:css] = true
|
||||
end
|
||||
opts.on('--js', 'Inject custom JavaScript into each page. The \'<wiki-root>/custom.js\' file is used (must be committed).') do
|
||||
wiki_options[:js] = true
|
||||
end
|
||||
opts.on('--no-edit', 'Disable the feature of editing pages.') do
|
||||
wiki_options[:allow_editing] = false
|
||||
end
|
||||
opts.on('--follow-renames', 'Follow pages across renames in the History view. Default: true.') do
|
||||
wiki_options[:follow_renames] = true
|
||||
end
|
||||
opts.on('--no-follow-renames', 'Do not follow pages across renames in the History view.') do
|
||||
wiki_options[:follow_renames] = false
|
||||
end
|
||||
opts.on('--allow-uploads [MODE]', [:dir, :page], 'Enable file uploads.',
|
||||
'If set to \'dir\', Gollum will store all uploads in the \'<git-repo>/uploads/\' directory.',
|
||||
'If set to \'page\', Gollum will store uploads per page in \'<git-repo>/uploads/[pagename]\'.') do |mode|
|
||||
wiki_options[:allow_uploads] = true
|
||||
wiki_options[:per_page_uploads] = true if mode == :page
|
||||
end
|
||||
opts.on('--mathjax', 'Enable MathJax (renders mathematical equations).',
|
||||
'By default, uses the \'TeX-AMS-MML_HTMLorMML\' config with the \'autoload-all\' extension.') do
|
||||
wiki_options[:mathjax] = true
|
||||
wiki_options[:mathjax_config] = 'mathjax.config.js'
|
||||
end
|
||||
opts.on('--critic-markup', 'Enable support for annotations using CriticMarkup.') do
|
||||
wiki_options[:critic_markup] = true
|
||||
end
|
||||
opts.on('--irb', 'Launch Gollum in \'console mode\', with a predefined API.') do
|
||||
options[:irb] = true
|
||||
end
|
||||
|
||||
opts.on("--host [HOST]", "Hostname or IP address to listen on (default 0.0.0.0).") do |host|
|
||||
options['bind'] = host
|
||||
end
|
||||
opts.separator ''
|
||||
opts.separator ' Minor:'
|
||||
|
||||
opts.on("--version", "Display current version.") do
|
||||
puts "Gollum " + Gollum::VERSION
|
||||
opts.on('--h1-title', 'Use the first \'<h1>\' as page title.') do
|
||||
wiki_options[:h1_title] = true
|
||||
end
|
||||
opts.on('--no-display-metadata', 'Do not render metadata tables in pages.') do
|
||||
wiki_options[:display_metadata] = false
|
||||
end
|
||||
opts.on('--user-icons [MODE]', [:gravatar, :identicon], 'Use specific user-icons for history view.',
|
||||
'Can be set to \'gravatar\' or \'identicon\'. Default: standard avatar.') do |mode|
|
||||
wiki_options[:user_icons] = mode.to_s
|
||||
end
|
||||
opts.on('--template-dir [PATH]', 'Specify custom mustache template directory. Only overrides templates that exist in this directory.') do |path|
|
||||
wiki_options[:template_dir] = path
|
||||
end
|
||||
opts.on('--template-page', 'Use _Template.{ext} as a template for new pages.') do
|
||||
wiki_options[:template_page] = true
|
||||
end
|
||||
opts.on('--lenient-tag-lookup', 'Internal links resolve case-insensitively, will treat spaces as hyphens, and will match the first page found with a certain filename, anywhere in the repository. Provides compatibility with Gollum 4.x.') do
|
||||
wiki_options[:case_insensitive_tag_lookup] = true
|
||||
wiki_options[:global_tag_lookup] = true
|
||||
wiki_options[:hyphened_tag_lookup] = true
|
||||
end
|
||||
opts.on('--emoji', 'Parse and interpret emoji tags (e.g. :heart:) except when the leading colon is backslashed (e.g. \\:heart:).') do
|
||||
wiki_options[:emoji] = true
|
||||
end
|
||||
opts.separator ''
|
||||
opts.separator ' Common:'
|
||||
|
||||
opts.on('--help', 'Display this message.') do
|
||||
puts opts
|
||||
exit 0
|
||||
end
|
||||
opts.on('--version', 'Display the current version of Gollum.') do
|
||||
puts 'Gollum ' + Gollum::VERSION
|
||||
exit 0
|
||||
end
|
||||
opts.on('--versions', 'Display the current version of Gollum and auxiliary gems.') do
|
||||
require 'gollum-lib'
|
||||
puts 'Gollum ' + Gollum::VERSION
|
||||
puts "Running on: #{RUBY_PLATFORM} with Ruby version #{RUBY_VERSION}"
|
||||
puts 'Using:'
|
||||
loaded_gemspecs = Gem.loaded_specs
|
||||
gollum_gems = ['gollum-lib', 'gollum-rjgit_adapter', 'rjgit', 'gollum-rugged_adapter', 'rugged']
|
||||
puts Gem.loaded_specs.select{|name, spec| gollum_gems.include?(name)}.map {|name, spec| "#{name} #{spec.version}"}
|
||||
puts "Markdown rendering gem: #{GitHub::Markup::Markdown.implementation_name}"
|
||||
puts 'Other renderering gems:'
|
||||
renderer_gems = ['RedCloth', 'org-ruby', 'creole', 'asciidoctor', 'wikicloth']
|
||||
renderer_gems.each do |renderer|
|
||||
begin
|
||||
require renderer
|
||||
rescue LoadError
|
||||
end
|
||||
end
|
||||
results = Gem.loaded_specs.select{|name, spec| renderer_gems.include?(name)}.map {|name, spec| "#{name} #{spec.version}"}
|
||||
puts results.empty? ? 'none' : results
|
||||
exit 0
|
||||
end
|
||||
|
||||
opts.on("--config [CONFIG]", "Path to additional configuration file") do |config|
|
||||
options['config'] = config
|
||||
end
|
||||
|
||||
opts.on("--irb", "Start an irb process with gollum loaded for the current wiki.") do
|
||||
options['irb'] = true
|
||||
end
|
||||
|
||||
opts.on("--css", "Inject custom css. Uses custom.css from root repository") do
|
||||
wiki_options[:css] = true
|
||||
end
|
||||
|
||||
opts.on("--page-file-dir [PATH]", "Specify the sub directory for all page files (default: repository root).") do |path|
|
||||
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
|
||||
|
||||
opts.on("--user-icons [SOURCE]", "Set the history user icons. Valid values: gravatar, identicon, none. Default: none.") do |source|
|
||||
wiki_options[:user_icons] = source
|
||||
end
|
||||
|
||||
opts.on("--show-all", "Shows all files in file view. By default only valid pages are shown.") do
|
||||
wiki_options[:show_all] = true
|
||||
end
|
||||
|
||||
opts.on("--collapse-tree", "Collapse file view tree. By default, expanded tree is shown.") do
|
||||
wiki_options[:collapse_tree] = true
|
||||
end
|
||||
opts.on("--h1-title", "Sets page title to value of first h1") do
|
||||
wiki_options[:h1_title] = true
|
||||
end
|
||||
opts.separator ''
|
||||
end
|
||||
|
||||
# Read command line options into `options` hash
|
||||
begin
|
||||
opts.parse!
|
||||
rescue OptionParser::InvalidOption
|
||||
puts "gollum: #{$!.message}"
|
||||
puts "gollum: try 'gollum --help' for more information"
|
||||
exit
|
||||
rescue OptionParser::InvalidOption => e
|
||||
puts "gollum: #{e.message}"
|
||||
puts 'gollum: try \'gollum --help\' for more information'
|
||||
exit 1
|
||||
end
|
||||
|
||||
# --gollum-path wins over ARGV[0]
|
||||
gollum_path = wiki_options[:gollum_path] ?
|
||||
wiki_options[:gollum_path] :
|
||||
ARGV[0] || Dir.pwd
|
||||
gollum_path = ARGV[0] || Dir.pwd
|
||||
|
||||
if options['irb']
|
||||
if options[:irb]
|
||||
require 'irb'
|
||||
# http://jameskilton.com/2009/04/02/embedding-irb-into-your-ruby-application/
|
||||
module IRB # :nodoc:
|
||||
@@ -129,31 +238,41 @@ if options['irb']
|
||||
end
|
||||
|
||||
begin
|
||||
require 'gollum-lib'
|
||||
wiki = Gollum::Wiki.new(gollum_path, wiki_options)
|
||||
if !wiki.exist? then raise Grit::InvalidGitRepositoryError end
|
||||
puts "Loaded Gollum wiki at #{File.expand_path(gollum_path).inspect}."
|
||||
if !wiki.exist? then
|
||||
raise Gollum::InvalidGitRepositoryError
|
||||
end
|
||||
|
||||
puts
|
||||
puts 'Loaded Gollum wiki at:'
|
||||
puts "#{File.expand_path(gollum_path).inspect}"
|
||||
puts
|
||||
puts 'Example API calls:'
|
||||
puts %( page = wiki.page('page-name'))
|
||||
puts %( # => <Gollum::Page>)
|
||||
puts
|
||||
puts %( page.raw_data)
|
||||
puts %( # => "# My wiki page")
|
||||
puts %( # => '# My wiki page')
|
||||
puts
|
||||
puts %( page.formatted_data)
|
||||
puts %( # => "<h1>My wiki page</h1>")
|
||||
puts %( # => '<h1>My wiki page</h1>')
|
||||
puts
|
||||
puts 'Full API documentation at:'
|
||||
puts 'https://github.com/gollum/gollum-lib'
|
||||
puts
|
||||
puts "Check out the Gollum README for more."
|
||||
IRB.start_session(binding)
|
||||
rescue Grit::InvalidGitRepositoryError, Grit::NoSuchPathError
|
||||
rescue Gollum::InvalidGitRepositoryError, Gollum::NoSuchPathError
|
||||
puts "Invalid Gollum wiki at #{File.expand_path(gollum_path).inspect}"
|
||||
exit 0
|
||||
end
|
||||
else
|
||||
require 'gollum/frontend/app'
|
||||
require 'gollum/app'
|
||||
Precious::App.set(:environment, ENV.fetch('RACK_ENV', :production).to_sym)
|
||||
Precious::App.set(:gollum_path, gollum_path)
|
||||
Precious::App.set(:wiki_options, wiki_options)
|
||||
|
||||
if cfg = options['config']
|
||||
if cfg = options[:config]
|
||||
# If the path begins with a '/' it will be considered an absolute path,
|
||||
# otherwise it will be relative to the CWD
|
||||
cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR
|
||||
@@ -162,29 +281,12 @@ else
|
||||
|
||||
base_path = wiki_options[:base_path]
|
||||
|
||||
if wiki_options[:base_path].nil?
|
||||
if 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'], :Host => options['bind']).start
|
||||
Rack::Server.new(:app => Precious::MapGollum.new(base_path), :Port => options[:port], :Host => options[:bind]).start
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env ruby
|
||||
#coding:utf-8
|
||||
require 'optparse'
|
||||
require 'pathname'
|
||||
require 'rubygems'
|
||||
|
||||
wiki_options = {}
|
||||
options = {}
|
||||
|
||||
migrate_options = {
|
||||
:hyphenate => true
|
||||
}
|
||||
|
||||
def setting(const)
|
||||
Object.const_defined?(const.upcase) && Object.const_get(const.upcase)
|
||||
end
|
||||
|
||||
opts = OptionParser.new do |opts|
|
||||
opts.banner = <<EOF
|
||||
Use this tool to migrate a wiki repository created under Gollum versions 4.x or earlier to a 5.x compatibile repo.
|
||||
It finds and repairs Gollum link tags that no longer work under 5.x for three reasons:
|
||||
|
||||
* 5.x wiki internal links may contain spaces. [[Bilbo Baggins]] and [[Bilbo-Baggins]] therefore link to distinct pages.
|
||||
* 5.x wiki internal links are case senitive
|
||||
* 5.x wiki internal links are no longer 'global'.
|
||||
|
||||
* NB: you can use the --lenient-tag-lookup option in gollum >= 5.x to enable 4.x-backwards compatible tags.
|
||||
|
||||
See https://github.com/gollum/gollum/wiki/5.0-release-notes#filename-handling for more information.
|
||||
Usage of this script comes without any warranty.
|
||||
|
||||
Usage: gollum-migrate-tags /path/to/repo
|
||||
|
||||
NB: without the --write flag, this will be a 'dry run' that doesn't actually make any changes, but outputs the changes that would be made.
|
||||
|
||||
You can use the --page-file-dir and --config options as you would normally with gollum.
|
||||
|
||||
Requires a non-bare repository. Recommended usage:
|
||||
|
||||
1. Clone your wiki's repository to create a backup.
|
||||
2. Run this script on your cloned repo.
|
||||
3. If all looks sane, run the script with the --write option. This will overwrite files in your working directory, but not commit the changes, so you have time to review them.
|
||||
4. Do a 'git diff' to inspect the changes.
|
||||
5. Commit the changes if all looks sane, and push/pull them back into your original repo.
|
||||
|
||||
Options:
|
||||
EOF
|
||||
opts.on('-c', '--config [FILE]', 'Specify path to the Gollum\'s configuration file.') do |file|
|
||||
options[:config] = file
|
||||
end
|
||||
|
||||
opts.on('--page-file-dir [PATH]', 'Specify the subdirectory for all pages. Default: repository root.') do |path|
|
||||
wiki_options[:page_file_dir] = path
|
||||
end
|
||||
|
||||
opts.on('--prefer-relative-links', 'When specified, will try to replace broken links with relative links (\'[[Foo/Bar]]\' instead of \'[[/Subdir/Foo/Bar]]\') where possible.') do
|
||||
migrate_options[:prefer_relative] = true
|
||||
end
|
||||
|
||||
opts.on('--hyphenate', 'Default. Repair links that use spaces instead of hyphens: [[Bilbo Baggins]] -> [[Bilbo-Baggins]]') do
|
||||
migrate_options[:hyphenate] = true
|
||||
end
|
||||
|
||||
opts.on('--no-hyphenate', 'Turn off the --hyphenate option.') do
|
||||
migrate_options[:hyphenate] = false
|
||||
end
|
||||
|
||||
opts.on('--run-silent', 'Don\'t output anything.') do
|
||||
migrate_options[:run_silent] = true
|
||||
end
|
||||
|
||||
opts.on('--write', 'No dry run: actually perform the substitutions.') do
|
||||
migrate_options[:no_dry_run] = true
|
||||
end
|
||||
end
|
||||
|
||||
# Read command line options into `options` hash
|
||||
begin
|
||||
opts.parse!
|
||||
migrate_options.each do |setting, value|
|
||||
const = setting.to_s.upcase
|
||||
Object.const_set(const, value) unless Object.const_defined?(const)
|
||||
end
|
||||
wiki_options[:page_file_dir] = setting(:page_file_dir) ? setting(:page_file_dir) : wiki_options[:page_file_dir] # Allow settings :page_file_dir through PAGE_FILE_DIR constant.
|
||||
rescue OptionParser::InvalidOption
|
||||
puts "gollum-migrate-tags: #{$!.message}"
|
||||
puts "gollum-migrate-tags: try 'gollum-migrate-tags --help' for more information"
|
||||
exit
|
||||
end
|
||||
|
||||
REPO = ARGV[0] || Dir.pwd
|
||||
|
||||
require 'gollum-lib'
|
||||
|
||||
if cfg = options[:config]
|
||||
# If the path begins with a '/' it will be considered an absolute path,
|
||||
# otherwise it will be relative to the CWD
|
||||
cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR
|
||||
require cfg
|
||||
end
|
||||
|
||||
class Gollum::Filter::CodeMigrator < Gollum::Filter::Code
|
||||
def extract(data)
|
||||
case @markup.format
|
||||
when :asciidoc
|
||||
data.gsub!(/^(\[source,([^\r\n]*)\]\n)?----\n(.+?)\n----$/m) do
|
||||
cache_codeblock($~.to_s)
|
||||
end
|
||||
when :org
|
||||
org_headers = %r{([ \t]*#\+HEADER[S]?:[^\r\n]*\n)*}
|
||||
org_name = %r{([ \t]*#\+NAME:[^\r\n]*\n)?}
|
||||
org_lang = %r{[ ]*([^\n \r]*)[ ]*[^\r\n]*}
|
||||
org_begin = %r{([ \t]*)#\+BEGIN_SRC#{org_lang}\r?\n}
|
||||
org_end = %r{\r?\n[ \t]*#\+END_SRC[ \t\r]*}
|
||||
data.gsub!(/^#{org_headers}#{org_name}#{org_begin}(.+?)#{org_end}$/mi) do
|
||||
cache_codeblock($~.to_s)
|
||||
end
|
||||
when :markdown
|
||||
data.gsub!(/^([ ]{0,3})(~~~+) ?([^\r\n]+)?\r?\n(.+?)\r?\n[ ]{0,3}(~~~+)[ \t\r]*$/m) do
|
||||
m_indent = Regexp.last_match[1]
|
||||
m_start = Regexp.last_match[2] # ~~~
|
||||
m_lang = Regexp.last_match[3]
|
||||
m_code = Regexp.last_match[4]
|
||||
m_end = Regexp.last_match[5] # ~~~
|
||||
# The closing code fence must be at least as long as the opening fence
|
||||
next '' if m_end.length < m_start.length
|
||||
lang = m_lang ? m_lang.strip.split.first : nil
|
||||
cache_codeblock($~.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
data.gsub!(/^([ ]{0,3})``` ?([^\r\n]+)?\r?\n(.+?)\r?\n[ ]{0,3}```[ \t]*\r?$/m) do
|
||||
cache_codeblock($~.to_s)
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
def process(data)
|
||||
return data if data.nil? || data.size.zero? || @map.size.zero?
|
||||
@map.each do |id, block| ## Just put the code blocks back in verbatim
|
||||
data.gsub!(id, block)
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
def cache_codeblock(block)
|
||||
id = "#{open_pattern}#{Digest::SHA1.hexdigest(block)}#{close_pattern}"
|
||||
@map[id] = block
|
||||
id
|
||||
end
|
||||
end
|
||||
|
||||
class ::Gollum::Filter::TagMigrator < Gollum::Filter::Tags
|
||||
def process_tag(tag)
|
||||
link_part, extra = parse_tag_parts(tag)
|
||||
orig_tag = %{[[#{tag}]]}
|
||||
return orig_tag if link_part.nil?
|
||||
|
||||
img_args = extra ? [extra, link_part] : [link_part]
|
||||
mime = MIME::Types.type_for(::File.extname(img_args.first.to_s)).first
|
||||
|
||||
# For any kind of tag other than an internal link: just return the tag.
|
||||
if tag =~ /^_TOC_/ || link_part =~ /^_$/ || link_part =~ /^#{INCLUDE_TAG}/ || (mime && mime.content_type =~ /^image/) || process_external_link_tag(link_part, extra) || process_file_link_tag(link_part, extra)
|
||||
return orig_tag
|
||||
end
|
||||
|
||||
# Try to resolve it as an internal Page link tag.
|
||||
link = link_part
|
||||
page = find_page_or_file_from_path(link)
|
||||
anchor = nil
|
||||
|
||||
if page.nil? # No match yet, now try finding the page with anchor removed
|
||||
if pos = link.rindex('#')
|
||||
anchor = link[pos..-1]
|
||||
link = link[0...pos]
|
||||
end
|
||||
|
||||
if link.empty? && anchor # Internal anchor link, don't search for the page but return the original tag
|
||||
return orig_tag
|
||||
end
|
||||
|
||||
page = find_page_or_file_from_path(link)
|
||||
end
|
||||
|
||||
if page
|
||||
# Great, the link is not broken. Return the original tag.
|
||||
return orig_tag
|
||||
else
|
||||
possibles = find_linked(link)
|
||||
if possibles.empty?
|
||||
log(:info, "Found no candidates for broken link: #{orig_tag}")
|
||||
return orig_tag
|
||||
else
|
||||
if possibles.size > 1
|
||||
log(:empty)
|
||||
log(:warn, "Found multiple possibilities for the link '#{orig_tag}':")
|
||||
possibles.map! {|p| Pathname.new(p)}
|
||||
possibles.sort!
|
||||
possibles.each{|p| log(:none, "* #{p}")}
|
||||
log(:warn,"Picking #{possibles.first}")
|
||||
log(:empty)
|
||||
end
|
||||
pick = possibles.first
|
||||
return tag_for_pick(pick, orig_tag, extra, anchor, @markup.page.path)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def tag_for_pick(pick, orig_tag, extra, anchor, linking_page_path)
|
||||
pick = if setting(:prefer_relative)
|
||||
overlapping_path = Pathname.new(linking_page_path).dirname.to_s
|
||||
overlapping_path = overlapping_path == '.' ? '' : ::File.join('/', overlapping_path)
|
||||
relative_path = pick.to_s.match(/^#{overlapping_path}\/(.+)/)
|
||||
relative_path ? relative_path[1] : pick
|
||||
else
|
||||
pick
|
||||
end
|
||||
new_tag = extra.nil? ? %{[[#{pick}#{anchor}]]} : %{[[#{extra}|#{pick}#{anchor}]]}
|
||||
log(:info, "#{@markup.page.path}: Changing #{orig_tag} -> #{new_tag}")
|
||||
new_tag
|
||||
end
|
||||
end
|
||||
|
||||
class ::Gollum::Filter::PlainTextMigrator < Gollum::Filter::PlainText
|
||||
def extract(data)
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
filter_chain = [:PlainTextMigrator, :CodeMigrator, :TagMigrator]
|
||||
|
||||
wiki = ::Gollum::Wiki.new(REPO, wiki_options.merge({:filter_chain => filter_chain}))
|
||||
TREE = wiki.tree_list(wiki.ref, true, true).map {|file| ::File.join('/', file.path)}
|
||||
|
||||
def find_linked(link)
|
||||
link.gsub!(' ', '-') if setting(:hyphenate) # Match paths containing dashes instead of spaces
|
||||
# If the link has no explicit file extension, test against the link + the '.' character.
|
||||
# This is to avoid that 'Samwi' matches 'Samwise.md'
|
||||
# If it has an explicit file extension ('Samwi.md'), just test against that.
|
||||
test_path = ::File.extname(link).empty? ? /#{link}\..+/ : link
|
||||
# Select pages from the wiki whose path =~ 'Foo/Bar/Samwi.*'
|
||||
# Match case-insenstively to mimic 4.x behavior!
|
||||
TREE.select {|path| path =~ /^\/(.*\/)?#{test_path}/i}
|
||||
end
|
||||
|
||||
def log(kind, msg = nil)
|
||||
unless setting(:run_silent)
|
||||
if kind == :none
|
||||
puts msg
|
||||
elsif kind == :empty
|
||||
puts
|
||||
else
|
||||
puts "[#{kind.to_s.upcase}] #{msg}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wiki.pages.each do |page|
|
||||
log(:info,"Page #{page.path}")
|
||||
new_data = page.formatted_data
|
||||
if setting(:no_dry_run)
|
||||
path = ::File.join(wiki.path, page.path)
|
||||
f = File.new(path, 'w')
|
||||
f.write(new_data)
|
||||
f.close
|
||||
end
|
||||
log(:none, '====')
|
||||
end
|
||||
@@ -1,28 +1,11 @@
|
||||
# Example gollum config
|
||||
# gollum ../wiki --config config.rb
|
||||
#
|
||||
# or run from source with
|
||||
#
|
||||
# bundle exec bin/gollum ../wiki/ --config config.rb
|
||||
|
||||
# Remove const to avoid
|
||||
# warning: already initialized constant FORMAT_NAMES
|
||||
#
|
||||
# only remove if it's defined.
|
||||
# constant Gollum::Page::FORMAT_NAMES not defined (NameError)
|
||||
Gollum::Page.send :remove_const, :FORMAT_NAMES if defined? Gollum::Page::FORMAT_NAMES
|
||||
# limit to one format
|
||||
Gollum::Page::FORMAT_NAMES = { :markdown => "Markdown" }
|
||||
|
||||
=begin
|
||||
Valid formats are:
|
||||
{ :markdown => "Markdown",
|
||||
:textile => "Textile",
|
||||
:rdoc => "RDoc",
|
||||
:org => "Org-mode",
|
||||
:creole => "Creole",
|
||||
:rest => "reStructuredText",
|
||||
:asciidoc => "AsciiDoc",
|
||||
:mediawiki => "MediaWiki",
|
||||
:pod => "Pod" }
|
||||
This file can be used to (e.g.):
|
||||
- alter certain inner parts of Gollum,
|
||||
- extend it with your stuff.
|
||||
|
||||
It is especially useful for customizing supported formats/markups. For more information and examples:
|
||||
- https://github.com/gollum/gollum#config-file
|
||||
|
||||
=end
|
||||
|
||||
# enter your Ruby code here ...
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
=begin
|
||||
You should use this file, if you wish to:
|
||||
- launch Gollum as a Rack app,
|
||||
- alter certain startup behaviour of Gollum.
|
||||
|
||||
For more information and examples:
|
||||
- https://github.com/gollum/gollum/wiki/Gollum-via-Rack
|
||||
- https://github.com/gollum/gollum#config-file
|
||||
|
||||
=end
|
||||
|
||||
# enter your Ruby code here ...
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# Distributed under the terms of the MIT License.
|
||||
#
|
||||
# Author: Sam Baskinger <basking2@yahoo.com>
|
||||
#
|
||||
# Description: gollum-post is an example script that shows how
|
||||
# to post a file to Gollum. This may be used
|
||||
# to build scripts around CI/CD pipelines that
|
||||
# publish their documentation to Gollum.
|
||||
#
|
||||
|
||||
require 'uri'
|
||||
require 'mechanize'
|
||||
require 'digest'
|
||||
|
||||
GOLLUM=URI('https://mygollum.server')
|
||||
|
||||
m = Mechanize.new()
|
||||
|
||||
page="TestPage"
|
||||
path="/automated/docs"
|
||||
format="asciidoc"
|
||||
content="""
|
||||
= This is #{page}
|
||||
|
||||
This page is automatically generated.
|
||||
"""
|
||||
message='Posting current documentation.'
|
||||
|
||||
# Check if the page exists.
|
||||
p = m.get("#{GOLLUM}#{path}/#{page}")
|
||||
|
||||
# If we were redirected to the creat page...
|
||||
if p.uri.to_s =~ /\/gollum\/create/
|
||||
|
||||
# ... then create the page.
|
||||
p = m.post("#{GOLLUM}/gollum/create",
|
||||
'keybinding' => 'default',
|
||||
'page' => page,
|
||||
'path' => path,
|
||||
'format' => 'asciidoc',
|
||||
'message' => 'Publish bot.',
|
||||
'content' => content)
|
||||
else
|
||||
# ... else, get the previous content and update it.
|
||||
p = m.get("#{GOLLUM}/gollum/edit#{path}/#{page}")
|
||||
|
||||
# Get the previous content. You _could_ check if this is unchanged at this
|
||||
# step and post nothing.
|
||||
previous_content = p.xpath('//textarea[@id="gollum-editor-body"]')[0].text
|
||||
|
||||
# The previous ETag is the Git SHA-1. We need this to replace the previous contents.
|
||||
prev_etag = Digest::SHA1.hexdigest("blob #{previous_content.length}\0#{previous_content}")
|
||||
|
||||
# Post the updated document using the ETag of the previous document to avoid collisions.
|
||||
p = m.post("#{GOLLUM}/gollum/edit#{path}/#{page}",
|
||||
'keybinding' => 'default',
|
||||
'page' => page,
|
||||
'path' => path,
|
||||
'format' => 'asciidoc',
|
||||
'message' => message,
|
||||
'etag' => prev_etag,
|
||||
'content' => content)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
GOLLUM_USER=gollum
|
||||
GOLLUM_BASE=/home/gollum/wiki
|
||||
GOLLUM_OPTS="--config /home/gollum/config.rb"
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/sbin/runscript
|
||||
# Distributed under the terms of the MIT License
|
||||
|
||||
NAME=gollum
|
||||
PID=/var/run/${NAME}.pid
|
||||
EXEC=/usr/local/bin/gollum
|
||||
LOG=/var/log/gollum.log
|
||||
|
||||
depend() {
|
||||
need net
|
||||
}
|
||||
|
||||
start() {
|
||||
# Change log file to be owned by GOLLUM_USER
|
||||
touch "${LOG}"
|
||||
chown "${GOLLUM_USER}" "${LOG}"
|
||||
|
||||
ebegin "Starting Gollum"
|
||||
start-stop-daemon --start \
|
||||
--name "${NAME}" \
|
||||
--user "${GOLLUM_USER}" \
|
||||
--pidfile "${PID}" \
|
||||
--make-pidfile --background \
|
||||
--stderr "${LOG}" \
|
||||
--exec "${EXEC}" -- $GOLLUM_OPTS "$GOLLUM_BASE"
|
||||
eend $?
|
||||
}
|
||||
|
||||
stop() {
|
||||
ebegin "Stopping Gollum"
|
||||
start-stop-daemon --stop \
|
||||
--name "${NAME}" \
|
||||
--user "${GOLLUM_USER}" \
|
||||
--pidfile "${PID}"
|
||||
eend $?
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=Gollum wiki server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=%i
|
||||
ExecStart=/usr/bin/gollum
|
||||
Restart=on-abort
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: gollum
|
||||
# Required-Start: $local_fs $remote_fs $network $syslog
|
||||
# Required-Stop: $local_fs $remote_fs $network $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# X-Interactive: true
|
||||
# Short-Description: Start/stop gollum wiki
|
||||
### END INIT INFO
|
||||
|
||||
# Distributed under the terms of the MIT License
|
||||
|
||||
set -e
|
||||
|
||||
# Edit these settings to your liking:
|
||||
GOLLUM_USER=gollum
|
||||
GOLLUM_BASE=/var/lib/gollum/.git
|
||||
GOLLUM_OPTS="--bare"
|
||||
|
||||
NAME=gollum
|
||||
PID=/var/run/${NAME}.pid
|
||||
EXEC=/usr/local/bin/gollum
|
||||
LOG=/var/log/gollum.log
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
start ()
|
||||
{
|
||||
# Change log file to be owned by GOLLUM_USER
|
||||
touch "${LOG}"
|
||||
chown "${GOLLUM_USER}" "${LOG}"
|
||||
|
||||
log_daemon_msg "Starting Gollum"
|
||||
start-stop-daemon --start \
|
||||
--name "${NAME}" \
|
||||
--user "${GOLLUM_USER}" \
|
||||
--chuid "${GOLLUM_USER}" \
|
||||
--pidfile "${PID}" \
|
||||
--make-pidfile --background \
|
||||
--startas /bin/sh -- -c "exec ${EXEC} $GOLLUM_OPTS \"$GOLLUM_BASE\" > \"${LOG}\" 2>&1"
|
||||
log_end_msg $?
|
||||
}
|
||||
|
||||
stop ()
|
||||
{
|
||||
log_daemon_msg "Stopping Gollum"
|
||||
start-stop-daemon --stop \
|
||||
--user "${GOLLUM_USER}" \
|
||||
--signal INT \
|
||||
--pidfile "${PID}" \
|
||||
--retry 10
|
||||
log_end_msg $?
|
||||
}
|
||||
|
||||
status ()
|
||||
{
|
||||
status_of_proc -p $PID $EXEC $NAME
|
||||
}
|
||||
|
||||
case $1 in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
*)
|
||||
log_success_msg "Usage: $0 {start|stop|restart|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Initialize the wiki
|
||||
if [ ! -d .git ]; then
|
||||
git init
|
||||
fi
|
||||
|
||||
# Start gollum service
|
||||
[[ "$@" != *--mathjax* ]] && echo "WARNING: Mathjax will soon be disabled by default. To explicitly enable it, use --mathjax" >&2
|
||||
exec gollum $@ --mathjax
|
||||
@@ -1,32 +0,0 @@
|
||||
Sanitization Rules
|
||||
==================
|
||||
|
||||
Gollum uses the [Sanitize](http://wonko.com/post/sanitize) gem for HTML
|
||||
sanitization.
|
||||
|
||||
See `lib/gollum.rb` for actual settings.
|
||||
|
||||
## ALLOWED TAGS
|
||||
|
||||
a, abbr, acronym, address, area, b, big, blockquote, br, button, caption,
|
||||
center, cite, code, col, colgroup, dd, del, dfn, dir, div, dl, dt, em,
|
||||
fieldset, font, form, h1, h2, h3, h4, h5, h6, hr, i, img, input, ins, kbd,
|
||||
label, legend, li, map, menu, ol, optgroup, option, p, pre, q, s, samp,
|
||||
select, small, span, strike, strong, sub, sup, table, tbody, td, textarea,
|
||||
tfoot, th, thead, tr, tt, u, ul, var
|
||||
|
||||
## ALLOWED ATTRIBUTES
|
||||
|
||||
abbr, accept, accept-charset, accesskey, action, align, alt, axis, border,
|
||||
cellpadding, cellspacing, char, charoff, charset, checked, cite, class, clear,
|
||||
cols, colspan, color, compact, coords, datetime, dir, disabled, enctype, for,
|
||||
frame, headers, height, href, hreflang, hspace, id, ismap, label, lang,
|
||||
longdesc, maxlength, media, method, multiple, name, nohref, noshade, nowrap,
|
||||
prompt, readonly, rel, rev, rows, rowspan, rules, scope, selected, shape,
|
||||
size, span, src, start, summary, tabindex, target, title, type, usemap,
|
||||
valign, value, vspace, width
|
||||
|
||||
## ALLOWED PROTOCOLS
|
||||
|
||||
a href: http, https, mailto
|
||||
img src: http, https
|
||||
@@ -5,48 +5,35 @@ require 'digest/sha1'
|
||||
require 'ostruct'
|
||||
|
||||
# external
|
||||
require 'grit'
|
||||
require 'i18n'
|
||||
require 'github/markup'
|
||||
require 'sanitize'
|
||||
require 'rhino' if RUBY_PLATFORM == 'java'
|
||||
|
||||
# internal
|
||||
require File.expand_path('../gollum/git_access', __FILE__)
|
||||
require File.expand_path('../gollum/committer', __FILE__)
|
||||
require File.expand_path('../gollum/pagination', __FILE__)
|
||||
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/web_sequence_diagram', __FILE__)
|
||||
require File.expand_path('../gollum/frontend/uri_encode_component', __FILE__)
|
||||
|
||||
# Set ruby to UTF-8 mode
|
||||
# This is required for Ruby 1.8.7 which gollum still supports.
|
||||
$KCODE = 'U' if RUBY_VERSION[0,3] == '1.8'
|
||||
require ::File.expand_path('../gollum/uri_encode_component', __FILE__)
|
||||
|
||||
module Gollum
|
||||
VERSION = '2.4.11'
|
||||
VERSION = '5.2.3'
|
||||
|
||||
::I18n.available_locales = [:en]
|
||||
::I18n.load_path = Dir[::File.expand_path("lib/gollum/locales") + "/*.yml"]
|
||||
|
||||
def self.assets_path
|
||||
::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__))
|
||||
::File.expand_path('gollum/public', ::File.dirname(__FILE__))
|
||||
end
|
||||
|
||||
class Error < StandardError; end
|
||||
class TemplateFilter
|
||||
@@filters = {}
|
||||
|
||||
class DuplicatePageError < Error
|
||||
attr_accessor :dir
|
||||
attr_accessor :existing_path
|
||||
attr_accessor :attempted_path
|
||||
def self.add_filter(pattern, &replacement)
|
||||
@@filters[pattern] = replacement
|
||||
end
|
||||
|
||||
def initialize(dir, existing, attempted, message = nil)
|
||||
@dir = dir
|
||||
@existing_path = existing
|
||||
@attempted_path = attempted
|
||||
super(message || "Cannot write #{@dir}/#{@attempted_path}, found #{@dir}/#{@existing_path}.")
|
||||
def self.apply_filters(data)
|
||||
@@filters.each do |pattern, replacement|
|
||||
data.gsub!(pattern, replacement.call)
|
||||
end
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,695 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require 'cgi'
|
||||
require 'sinatra'
|
||||
require 'sinatra/namespace'
|
||||
require 'gollum-lib'
|
||||
require 'mustache/sinatra'
|
||||
require 'json'
|
||||
require 'sprockets'
|
||||
require 'sprockets-helpers'
|
||||
require 'octicons'
|
||||
require 'sass'
|
||||
require 'pathname'
|
||||
|
||||
require 'gollum'
|
||||
require 'gollum/assets'
|
||||
require 'gollum/views/helpers'
|
||||
require 'gollum/views/helpers/locale_helpers'
|
||||
require 'gollum/views/layout'
|
||||
require 'gollum/views/editable'
|
||||
require 'gollum/views/has_page'
|
||||
require 'gollum/views/has_user_icons'
|
||||
require 'gollum/views/has_math'
|
||||
require 'gollum/views/pagination'
|
||||
require 'gollum/views/rss.rb'
|
||||
require 'gollum/views/template_cascade'
|
||||
|
||||
require File.expand_path '../helpers', __FILE__
|
||||
|
||||
#required to upload bigger binary files
|
||||
Gollum::set_git_timeout(120)
|
||||
Gollum::set_git_max_filesize(190 * 10**6)
|
||||
|
||||
# Run the frontend, based on Sinatra
|
||||
#
|
||||
# There are a number of wiki options that can be set for the frontend
|
||||
#
|
||||
# Example
|
||||
# require 'gollum/app'
|
||||
# Precious::App.set(:wiki_options, {
|
||||
# :universal_toc => false,
|
||||
# }
|
||||
#
|
||||
# See the wiki.rb file for more details on wiki options
|
||||
|
||||
module Precious
|
||||
|
||||
# For use with the --base-path option.
|
||||
class MapGollum
|
||||
def initialize(base_path)
|
||||
@mg = Rack::Builder.new do
|
||||
|
||||
map "/#{base_path}" do
|
||||
run Precious::App
|
||||
end
|
||||
map '/' do
|
||||
run Proc.new { [302, { 'Location' => "/#{base_path}" }, []] }
|
||||
end
|
||||
map '/*' do
|
||||
run Proc.new { [302, { 'Location' => "/#{base_path}" }, []] }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@mg.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
class App < Sinatra::Base
|
||||
register Mustache::Sinatra
|
||||
register Sinatra::Namespace
|
||||
include Precious::Helpers
|
||||
|
||||
Encoding.default_external = "UTF-8"
|
||||
|
||||
dir = File.dirname(File.expand_path(__FILE__))
|
||||
|
||||
set :sprockets, ::Precious::Assets.sprockets(dir)
|
||||
|
||||
set :default_markup, :markdown
|
||||
|
||||
set :mustache, {
|
||||
# Tell mustache where the Views constant lives
|
||||
:namespace => Precious,
|
||||
|
||||
# Mustache templates live here
|
||||
:templates => "#{dir}/templates",
|
||||
|
||||
# Tell mustache where the views are
|
||||
:views => "#{dir}/views"
|
||||
}
|
||||
|
||||
# Sinatra error handling
|
||||
configure :development, :staging do
|
||||
enable :show_exceptions, :dump_errors
|
||||
disable :raise_errors, :clean_trace
|
||||
end
|
||||
|
||||
configure :test do
|
||||
enable :logging, :raise_errors, :dump_errors
|
||||
end
|
||||
|
||||
before do
|
||||
settings.wiki_options[:allow_editing] = settings.wiki_options.fetch(:allow_editing, true)
|
||||
@allow_editing = settings.wiki_options[:allow_editing]
|
||||
@critic_markup = settings.wiki_options[:critic_markup]
|
||||
@redirects_enabled = settings.wiki_options.fetch(:redirects_enabled, true)
|
||||
@per_page_uploads = settings.wiki_options[:per_page_uploads]
|
||||
|
||||
@wiki_title = settings.wiki_options.fetch(:title, 'Gollum Wiki')
|
||||
|
||||
forbid unless @allow_editing || request.request_method == 'GET'
|
||||
|
||||
if settings.wiki_options[:template_dir]
|
||||
Precious::Views::Layout.extend Precious::Views::TemplateCascade
|
||||
Precious::Views::Layout.template_priority_path = settings.wiki_options[:template_dir]
|
||||
end
|
||||
|
||||
@base_url = url('/', false).chomp('/').force_encoding('utf-8')
|
||||
@page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
|
||||
# above will detect base_path when it's used with map in a config.ru
|
||||
settings.wiki_options.merge!({ :base_path => @base_url })
|
||||
@css = settings.wiki_options[:css]
|
||||
@js = settings.wiki_options[:js]
|
||||
@mathjax_config = settings.wiki_options[:mathjax_config]
|
||||
@mathjax = settings.wiki_options[:mathjax]
|
||||
|
||||
@use_static_assets = settings.wiki_options.fetch(:static, settings.environment != :development)
|
||||
@static_assets_path = settings.wiki_options.fetch(:static_assets_path, ::File.join(File.dirname(__FILE__), 'public/assets'))
|
||||
@mathjax_path = ::File.join(File.dirname(__FILE__), 'public/gollum/javascript/MathJax')
|
||||
|
||||
Sprockets::Helpers.configure do |config|
|
||||
config.environment = settings.sprockets
|
||||
config.environment.context_class.class_variable_set(:@@base_url, @base_url)
|
||||
config.prefix = "#{@base_url}/#{Precious::Assets::ASSET_URL}"
|
||||
config.digest = @use_static_assets
|
||||
if @use_static_assets
|
||||
config.public_path = @static_assets_path
|
||||
config.manifest = Sprockets::Manifest.new(settings.sprockets, @static_assets_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
get '/' do
|
||||
redirect clean_url(::File.join(@base_url, wiki_new.index_page))
|
||||
end
|
||||
|
||||
namespace '/gollum' do
|
||||
get '/feed/' do
|
||||
url = "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}"
|
||||
changes = wiki_new.latest_changes(::Gollum::Page.log_pagination_options(
|
||||
per_page: settings.wiki_options.fetch(:pagination_count, 10),
|
||||
page_num: 0)
|
||||
)
|
||||
content_type :rss
|
||||
RSSView.new(@base_url, @wiki_title, url, changes).render
|
||||
end
|
||||
|
||||
get '/assets/mathjax/*' do
|
||||
env['PATH_INFO'].sub!('/gollum/assets/mathjax', '')
|
||||
Rack::Static.new(not_found_proc, {:root => @mathjax_path, :urls => ['']}).call(env)
|
||||
end
|
||||
|
||||
get '/assets/*' do
|
||||
env['PATH_INFO'].sub!("/#{Precious::Assets::ASSET_URL}", '')
|
||||
if @use_static_assets
|
||||
env['PATH_INFO'].sub!(Sprockets::Helpers.prefix, '') if @base_url
|
||||
Rack::Static.new(not_found_proc, {:root => @static_assets_path, :urls => ['']}).call(env)
|
||||
else
|
||||
settings.sprockets.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
get '/last_commit_info' do
|
||||
content_type :json
|
||||
if page = wiki_page(params[:path]).page
|
||||
version = page.last_version
|
||||
{:author => version.author.name, :date => version.authored_date}.to_json
|
||||
end
|
||||
end
|
||||
|
||||
get '/emoji/:name' do
|
||||
begin
|
||||
[200, {'Content-Type' => 'image/png'}, emoji(params['name'])]
|
||||
rescue ArgumentError
|
||||
not_found
|
||||
end
|
||||
end
|
||||
|
||||
get '/data/*' do
|
||||
if page = wiki_page(params[:splat].first).page
|
||||
page.raw_data
|
||||
end
|
||||
end
|
||||
|
||||
get %r{/(edit|create)/(\.redirects.gollum|(custom|mathjax\.config)\.(js|css))} do
|
||||
forbid('Changing this resource is not allowed.')
|
||||
end
|
||||
|
||||
post %r{/(delete|rename|edit|create)/(\.redirects.gollum|(custom|mathjax\.config)\.(js|css))} do
|
||||
forbid('Changing this resource is not allowed.')
|
||||
end
|
||||
|
||||
post %r{/revert/(\.redirects.gollum|(custom|mathjax\.config\.)\.(js|css)/.*/.*)} do
|
||||
forbid('Changing this resource is not allowed.')
|
||||
end
|
||||
|
||||
get '/edit/*' do
|
||||
forbid unless @allow_editing
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
@name = wikip.fullname
|
||||
@path = wikip.path
|
||||
@upload_dest = find_upload_dest(wikip.fullpath)
|
||||
wiki = wikip.wiki
|
||||
@allow_uploads = wiki.allow_uploads
|
||||
if page = wikip.page
|
||||
@page = page
|
||||
@content = page.text_data
|
||||
@etag = page.sha
|
||||
mustache :edit
|
||||
else
|
||||
path = ::File.join('gollum/create', @path, @name)
|
||||
redirect to(clean_url(encodeURIComponent(path)))
|
||||
end
|
||||
end
|
||||
|
||||
# AJAX calls only
|
||||
post '/upload_file' do
|
||||
|
||||
wiki = wiki_new
|
||||
halt 405 unless wiki.allow_uploads
|
||||
|
||||
if params[:file]
|
||||
fullname = params[:file][:filename]
|
||||
tempfile = params[:file][:tempfile]
|
||||
end
|
||||
halt 500 unless tempfile.is_a? Tempfile
|
||||
|
||||
if wiki.per_page_uploads
|
||||
dir = request.referer.match(/^https?:\/\/#{request.host_with_port}\/(.*)/)[1]
|
||||
# remove base path if it is set
|
||||
dir.sub!(/^#{wiki.base_path}/, '') if wiki.base_path
|
||||
# remove base_url and gollum/* subpath if necessary
|
||||
dir.sub!(/^\/gollum\/[-\w]+\//, '')
|
||||
# remove file extension
|
||||
dir.sub!(/#{::File.extname(dir)}$/, '')
|
||||
# revert escaped whitespaces
|
||||
dir.gsub!(/%20/, ' ')
|
||||
dir = ::File.join('uploads', dir)
|
||||
else
|
||||
# store all uploads together
|
||||
dir = 'uploads'
|
||||
end
|
||||
halt 500 if dir.include?('..')
|
||||
halt 500 unless Pathname(dir).relative?
|
||||
|
||||
ext = ::File.extname(fullname)
|
||||
format = ext.split('.').last || 'txt'
|
||||
filename = ::File.basename(fullname, ext)
|
||||
contents = ::File.read(tempfile)
|
||||
reponame = "#{dir}/#{filename}.#{format}"
|
||||
|
||||
options = { :message => "Uploaded file to #{reponame}" }
|
||||
options[:parent] = wiki.repo.head.commit if wiki.repo.head
|
||||
|
||||
author = session['gollum.author']
|
||||
unless author.nil?
|
||||
options.merge! author
|
||||
end
|
||||
|
||||
normalize = Gollum::Page.valid_extension?(fullname)
|
||||
|
||||
begin
|
||||
wiki.write_file(reponame, contents, options)
|
||||
redirect to(request.referer)
|
||||
rescue Gollum::IllegalDirectoryPath => e
|
||||
@message = e.message
|
||||
mustache :error
|
||||
rescue Gollum::DuplicatePageError
|
||||
halt 409 # Signal conflict
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
post '/rename/*' do
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
halt 500 if wikip.nil?
|
||||
wiki = wikip.wiki
|
||||
page = wikip.page
|
||||
rename = params[:rename]
|
||||
halt 500 if page.nil?
|
||||
halt 500 if rename.nil? or rename.empty?
|
||||
|
||||
# Fixup the rename if it is a relative path
|
||||
# In 1.8.7 rename[0] != rename[0..0]
|
||||
if rename[0..0] != '/'
|
||||
source_dir = ::File.dirname(page.path)
|
||||
source_dir = '' if source_dir == '.'
|
||||
(target_dir, target_name) = ::File.split(rename)
|
||||
target_dir = target_dir == '' ? source_dir : "#{source_dir}/#{target_dir}"
|
||||
rename = "#{target_dir}/#{target_name}"
|
||||
end
|
||||
|
||||
committer = Gollum::Committer.new(wiki, commit_message)
|
||||
commit = { :committer => committer }
|
||||
|
||||
success = wiki.rename_page(page, rename, commit)
|
||||
if !success
|
||||
# This occurs on NOOPs, for example renaming A => A
|
||||
redirect to("/#{page.escaped_url_path}")
|
||||
return
|
||||
end
|
||||
|
||||
# Renaming preserves format, so add the page's format to the renamed path to retrieve the renamed page
|
||||
new_path = "#{rename}.#{Gollum::Page.format_to_ext(page.format)}"
|
||||
# Add a redirect from the old page to the new
|
||||
wiki.add_redirect(page.url_path, clean_url(new_path), commit) if @redirects_enabled
|
||||
|
||||
committer.commit
|
||||
|
||||
page = wiki_page(new_path).page
|
||||
return if page.nil?
|
||||
redirect to("/#{page.escaped_url_path}")
|
||||
end
|
||||
|
||||
post '/edit/*' do
|
||||
etag = params[:etag]
|
||||
path = "/#{clean_url(sanitize_empty_params(params[:path]))}"
|
||||
wiki = wiki_new
|
||||
page = wiki.page(::File.join(path, params[:page]))
|
||||
|
||||
return if page.nil?
|
||||
if etag != page.sha
|
||||
# Signal edit collision and return the page's most recent version
|
||||
halt 412, {etag: page.sha, text_data: page.text_data}.to_json
|
||||
end
|
||||
|
||||
committer = Gollum::Committer.new(wiki, commit_message)
|
||||
commit = { :committer => committer }
|
||||
|
||||
update_wiki_page(wiki, page, params[:content], commit, page.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
|
||||
|
||||
end
|
||||
|
||||
post '/delete/*' do
|
||||
forbid unless @allow_editing
|
||||
wiki = wiki_new
|
||||
filepath = params[:splat].first
|
||||
unless filepath.nil?
|
||||
commit = commit_message
|
||||
commit[:message] = "Deleted #{filepath}"
|
||||
wiki.delete_file(filepath, commit)
|
||||
end
|
||||
end
|
||||
|
||||
get '/create/*' do
|
||||
forbid unless @allow_editing
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
@name = wikip.name
|
||||
@ext = wikip.ext
|
||||
@path = wikip.path
|
||||
@template_page = load_template(@path) if settings.wiki_options[:template_page]
|
||||
@allow_uploads = wikip.wiki.allow_uploads
|
||||
@upload_dest = find_upload_dest(wikip.fullpath)
|
||||
|
||||
page = wikip.page
|
||||
if page
|
||||
redirect to("/#{clean_url(page.escaped_url_path)}")
|
||||
else
|
||||
unless Gollum::Page.format_for("#{@name}#{@ext}")
|
||||
@name = "#{@name}#{@ext}"
|
||||
@ext = nil
|
||||
end
|
||||
mustache :create
|
||||
end
|
||||
end
|
||||
|
||||
post '/create' do
|
||||
name = params[:page]
|
||||
path = sanitize_empty_params(params[:path]) || ''
|
||||
format = params[:format].intern
|
||||
wiki = wiki_new
|
||||
|
||||
path.gsub!(/^\//, '')
|
||||
|
||||
begin
|
||||
wiki.write_page(::File.join(path, name), format, params[:content], commit_message)
|
||||
|
||||
redirect to("/#{clean_url(::File.join(encodeURIComponent(path), encodeURIComponent(wiki.page_file_name(name, format))))}")
|
||||
rescue Gollum::DuplicatePageError, Gollum::IllegalDirectoryPath => e
|
||||
@message = e.message
|
||||
mustache :error
|
||||
end
|
||||
end
|
||||
|
||||
post '/revert/*/:sha1/:sha2' do
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
@path = wikip.path
|
||||
@name = wikip.fullname
|
||||
wiki = wikip.wiki
|
||||
@page = wikip.page
|
||||
sha1 = params[:sha1]
|
||||
sha2 = params[:sha2]
|
||||
|
||||
commit = commit_message
|
||||
commit[:message] = "Revert commit #{sha2.chars.take(7).join}"
|
||||
if wiki.revert_page(@page, sha1, sha2, commit)
|
||||
redirect to("/#{@page.escaped_url_path}")
|
||||
else
|
||||
sha2, sha1 = sha1, "#{sha1}^" if !sha2
|
||||
@versions = [sha1, sha2]
|
||||
@diff = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@message = 'The patch does not apply.'
|
||||
mustache :compare
|
||||
end
|
||||
end
|
||||
|
||||
post '/preview' do
|
||||
wiki = wiki_new
|
||||
@name = params[:page] ? strip_page_name(params[:page]) : 'Preview'
|
||||
@page = wiki.preview_page(@name, params[:content], params[:format])
|
||||
['sidebar', 'header', 'footer'].each do |subpage|
|
||||
@page.send("set_#{subpage}".to_sym, params[subpage]) if params[subpage]
|
||||
end
|
||||
@content = @page.formatted_data
|
||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||
@h1_title = wiki.h1_title
|
||||
@editable = false
|
||||
@bar_side = wiki.bar_side
|
||||
@allow_uploads = false
|
||||
@navbar = false
|
||||
@preview = true
|
||||
mustache :page
|
||||
end
|
||||
|
||||
get '/history/*' do
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
@name = wikip.fullname
|
||||
@page = wikip.page
|
||||
@page_num = [params[:page_num].to_i, 1].max
|
||||
@max_count = settings.wiki_options.fetch(:pagination_count, 10)
|
||||
unless @page.nil?
|
||||
@wiki = @page.wiki
|
||||
@versions = @page.versions(
|
||||
per_page: @max_count,
|
||||
page_num: @page_num,
|
||||
follow: settings.wiki_options.fetch(:follow_renames, true)
|
||||
)
|
||||
mustache :history
|
||||
else
|
||||
redirect to("/")
|
||||
end
|
||||
end
|
||||
|
||||
get '/latest_changes' do
|
||||
@wiki = wiki_new
|
||||
@page_num = [params[:page_num].to_i, 1].max
|
||||
@max_count = settings.wiki_options.fetch(:pagination_count, 10)
|
||||
@versions = @wiki.latest_changes(::Gollum::Page.log_pagination_options(per_page: @max_count, page_num: @page_num))
|
||||
mustache :latest_changes
|
||||
end
|
||||
|
||||
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.fullname
|
||||
@versions = [start_version, end_version]
|
||||
wiki = wikip.wiki
|
||||
@page = wikip.page
|
||||
@diff = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
if @diff.empty?
|
||||
@message = 'Could not compare these two revisions, no differences were found.'
|
||||
mustache :error
|
||||
else
|
||||
mustache :compare
|
||||
end
|
||||
end
|
||||
|
||||
get '/compare/*' do
|
||||
@file = clean_url(encodeURIComponent(params[:splat].first))
|
||||
@versions = params[:versions] || []
|
||||
if @versions.size == 1
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
commit = wikip.wiki.repo.commit(@versions.first)
|
||||
parent = commit.parent
|
||||
if parent.nil?
|
||||
redirect to("#{@file}/#{@commit.id}")
|
||||
else
|
||||
@versions.push(parent.id)
|
||||
end
|
||||
end
|
||||
if @versions.empty?
|
||||
redirect to("gollum/history/#{@file}")
|
||||
else
|
||||
redirect to("gollum/compare/%s/%s...%s" % [
|
||||
@file,
|
||||
@versions.last,
|
||||
@versions.first]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
get %r{
|
||||
/commit/ # match any URL beginning with /show/
|
||||
(\w+) # match the SHA1
|
||||
}x do |version|
|
||||
@version = version
|
||||
wiki = wiki_new
|
||||
begin
|
||||
@commit = wiki.repo.commit(version)
|
||||
parent = @commit.parent
|
||||
parent_id = parent.nil? ? nil : parent.id
|
||||
@diff = wiki.repo.diff(parent_id, version)
|
||||
mustache :commit
|
||||
rescue Gollum::Git::NoSuchShaFound
|
||||
@message = "Invalid commit: #{@version}"
|
||||
mustache :error
|
||||
end
|
||||
end
|
||||
|
||||
get '/search' do
|
||||
@query = params[:q] || ''
|
||||
@name = @query
|
||||
if @query.empty?
|
||||
@results = []
|
||||
@search_terms = []
|
||||
else
|
||||
@page_num = [params[:page_num].to_i, 1].max
|
||||
@max_count = 10
|
||||
wiki = wiki_new
|
||||
@results, @search_terms = wiki.search(@query)
|
||||
end
|
||||
mustache :search
|
||||
end
|
||||
|
||||
get %r{
|
||||
/overview # match any URL beginning with /overview
|
||||
(?: # begin an optional non-capturing group
|
||||
/(.+) # capture any path after the "/overview" excluding the leading slash
|
||||
)? # end the optional non-capturing group
|
||||
}x do |path|
|
||||
wiki = wiki_new
|
||||
@results = wiki.tree_list
|
||||
|
||||
if path
|
||||
@path = Pathname.new(path).cleanpath.to_s
|
||||
check_path = wiki.page_file_dir ? ::File.join(wiki.page_file_dir, @path, '/') : "#{@path}/"
|
||||
@results.select! {|result| result.path.start_with?(check_path) }
|
||||
end
|
||||
|
||||
@results.sort_by! {|result| result.name.downcase}
|
||||
|
||||
@ref = wiki.ref
|
||||
@newable = true
|
||||
mustache :overview
|
||||
end
|
||||
end # gollum namespace
|
||||
|
||||
get %r{/(.+?)/([0-9a-f]{40})} do
|
||||
file_path = params[:captures][0]
|
||||
version = params[:captures][1]
|
||||
wikip = wiki_page(file_path, version)
|
||||
name = wikip.fullname
|
||||
path = wikip.path
|
||||
if page = wikip.page
|
||||
@page = page
|
||||
@name = name
|
||||
@content = page.formatted_data
|
||||
@version = version
|
||||
@historical = true
|
||||
@bar_side = wikip.wiki.bar_side
|
||||
@navbar = true
|
||||
mustache :page
|
||||
elsif file = wikip.wiki.file(file_path, version, true)
|
||||
show_file(file)
|
||||
else
|
||||
halt 404
|
||||
end
|
||||
end
|
||||
|
||||
get '/\.redirects\.gollum' do
|
||||
forbid('Accessing this resource is not allowed.')
|
||||
end
|
||||
|
||||
get '/*' do
|
||||
show_page_or_file(params[:splat].first)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def show_page_or_file(fullpath)
|
||||
wiki = wiki_new
|
||||
if page = wiki.page(fullpath)
|
||||
@page = page
|
||||
@name = page.filename_stripped
|
||||
@content = page.formatted_data
|
||||
@upload_dest = find_upload_dest(Pathname.new(fullpath).cleanpath.to_s)
|
||||
|
||||
# Extensions and layout data
|
||||
@editable = true
|
||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||
@h1_title = wiki.h1_title
|
||||
@bar_side = wiki.bar_side
|
||||
@allow_uploads = wiki.allow_uploads
|
||||
@navbar = true
|
||||
mustache :page
|
||||
elsif file = wiki.file(fullpath, wiki.ref, true)
|
||||
show_file(file)
|
||||
elsif @redirects_enabled && redirect_path = wiki.redirects[fullpath]
|
||||
redirect to("#{encodeURIComponent(redirect_path)}?redirected_from=#{encodeURIComponent(fullpath)}")
|
||||
else
|
||||
if @allow_editing
|
||||
path = fullpath[-1] == '/' ? "#{fullpath}#{wiki.index_page}" : fullpath # Append default index page if no page name is supplied
|
||||
redirect to("/gollum/create/#{clean_url(encodeURIComponent(path))}")
|
||||
else
|
||||
@message = "The requested page does not exist."
|
||||
status 404
|
||||
return mustache :error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def show_file(file)
|
||||
return unless file
|
||||
if file.on_disk?
|
||||
send_file file.on_disk_path, :disposition => 'inline'
|
||||
else
|
||||
content_type file.mime_type
|
||||
file.raw_data
|
||||
end
|
||||
end
|
||||
|
||||
def load_template(path)
|
||||
template_page = wiki_page(::File.join(path, '_Template')).page || wiki_page('/_Template').page
|
||||
template_page ? Gollum::TemplateFilter.apply_filters(template_page.text_data) : nil
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
def wiki_page(path, version = nil)
|
||||
pathname = (Pathname.new('/') + path).cleanpath
|
||||
wiki = wiki_new
|
||||
OpenStruct.new(:wiki => wiki, :page => wiki.page(pathname.to_s, version = version),
|
||||
:name => pathname.basename.sub_ext('').to_s, :path => pathname.dirname.to_s, :ext => pathname.extname, :fullname => pathname.basename.to_s, :fullpath => pathname.to_s)
|
||||
end
|
||||
|
||||
def wiki_new
|
||||
Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
end
|
||||
|
||||
# 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
|
||||
msg = (params[:message].nil? or params[:message].empty?) ? "[no message]" : params[:message]
|
||||
commit_message = { :message => msg }
|
||||
author_parameters = session['gollum.author']
|
||||
commit_message.merge! author_parameters unless author_parameters.nil?
|
||||
commit_message
|
||||
end
|
||||
|
||||
def find_upload_dest(path)
|
||||
settings.wiki_options[:allow_uploads] ?
|
||||
(settings.wiki_options[:per_page_uploads] ?
|
||||
path : 'uploads'
|
||||
) : ''
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
require 'octicons'
|
||||
|
||||
module Precious
|
||||
module Assets
|
||||
MANIFEST = %w(app.js editor.js app.css criticmarkup.css fileview.css ie7.css print.css *.png *.jpg *.svg *.eot *.ttf)
|
||||
ASSET_URL = 'gollum/assets'
|
||||
|
||||
def self.sprockets(dir = File.dirname(File.expand_path(__FILE__)))
|
||||
env = Sprockets::Environment.new
|
||||
env.append_path ::File.join(dir, 'public/gollum/stylesheets/')
|
||||
env.append_path ::File.join(dir, 'public/gollum/javascript')
|
||||
env.append_path ::File.join(dir, 'public/gollum/images')
|
||||
env.append_path ::File.join(dir, 'public/gollum/fonts')
|
||||
|
||||
env.js_compressor = :uglify unless Precious::App.development?
|
||||
env.css_compressor = :scss
|
||||
|
||||
env.context_class.class_eval do
|
||||
def base_url
|
||||
self.class.class_variable_get(:@@base_url)
|
||||
end
|
||||
include ::Octicons
|
||||
include ::Precious::Views::RouteHelpers
|
||||
include ::Precious::Views::OcticonHelpers
|
||||
end
|
||||
env
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,91 +0,0 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
module Gollum
|
||||
class BlobEntry
|
||||
# Gets the String SHA for this blob.
|
||||
attr_reader :sha
|
||||
|
||||
# Gets the full path String for this blob.
|
||||
attr_reader :path
|
||||
|
||||
# Gets the Fixnum size of this blob.
|
||||
attr_reader :size
|
||||
|
||||
def initialize(sha, path, size = nil)
|
||||
@sha = sha
|
||||
@path = path
|
||||
@size = size
|
||||
@dir = @name = @blob = nil
|
||||
end
|
||||
|
||||
# Gets the normalized directory path String for this blob.
|
||||
def dir
|
||||
@dir ||= self.class.normalize_dir(::File.dirname(@path))
|
||||
end
|
||||
|
||||
# Gets the file base name String for this blob.
|
||||
def name
|
||||
@name ||= ::File.basename(@path)
|
||||
end
|
||||
|
||||
# Gets a Grit::Blob instance for this blob.
|
||||
#
|
||||
# repo - Grit::Repo instance for the Grit::Blob.
|
||||
#
|
||||
# Returns an unbaked Grit::Blob instance.
|
||||
def blob(repo)
|
||||
@blob ||= Grit::Blob.create(repo,
|
||||
:id => @sha, :name => name, :size => @size)
|
||||
end
|
||||
|
||||
# Gets a Page instance for this blob.
|
||||
#
|
||||
# wiki - Gollum::Wiki instance for the Gollum::Page
|
||||
#
|
||||
# Returns a Gollum::Page instance.
|
||||
def page(wiki, commit)
|
||||
blob = self.blob(wiki.repo)
|
||||
page = wiki.page_class.new(wiki).populate(blob, self.dir)
|
||||
page.version = commit
|
||||
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
|
||||
|
||||
# Normalizes a given directory name for searching through tree paths.
|
||||
# Ensures that a directory begins with a slash, or
|
||||
#
|
||||
# normalize_dir("") # => ""
|
||||
# normalize_dir(".") # => ""
|
||||
# normalize_dir("foo") # => "/foo"
|
||||
# normalize_dir("/foo/") # => "/foo"
|
||||
# normalize_dir("/") # => ""
|
||||
# normalize_dir("c:/") # => ""
|
||||
#
|
||||
# dir - String directory name.
|
||||
#
|
||||
# Returns a normalized String directory name, or nil if no directory
|
||||
# is given.
|
||||
def self.normalize_dir(dir)
|
||||
return '' if dir =~ /^.:\/$/
|
||||
if dir
|
||||
dir = ::File.expand_path(dir, '/')
|
||||
dir = '' if dir == '/'
|
||||
end
|
||||
dir
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,236 +0,0 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
module Gollum
|
||||
# Responsible for handling the commit process for a Wiki. It sets up the
|
||||
# Git index, provides methods for modifying the tree, and stores callbacks
|
||||
# to be fired after the commit has been made. This is specifically
|
||||
# designed to handle multiple updated pages in a single commit.
|
||||
class Committer
|
||||
# Gets the instance of the Gollum::Wiki that is being updated.
|
||||
attr_reader :wiki
|
||||
|
||||
# Gets a Hash of commit options.
|
||||
attr_reader :options
|
||||
|
||||
# Initializes the Committer.
|
||||
#
|
||||
# wiki - The Gollum::Wiki instance that is being updated.
|
||||
# options - The commit Hash details:
|
||||
# :message - The String commit message.
|
||||
# :name - The String author full name.
|
||||
# :email - The String email address.
|
||||
# :parent - Optional Grit::Commit parent to this update.
|
||||
# :tree - Optional String SHA of the tree to create the
|
||||
# index from.
|
||||
# :committer - Optional Gollum::Committer instance. If provided,
|
||||
# assume that this operation is part of batch of
|
||||
# updates and the commit happens later.
|
||||
#
|
||||
# Returns the Committer instance.
|
||||
def initialize(wiki, options = {})
|
||||
@wiki = wiki
|
||||
@options = options
|
||||
@callbacks = []
|
||||
end
|
||||
|
||||
# Public: References the Git index for this commit.
|
||||
#
|
||||
# Returns a Grit::Index.
|
||||
def index
|
||||
@index ||= begin
|
||||
idx = @wiki.repo.index
|
||||
if tree = options[:tree]
|
||||
idx.read_tree(tree)
|
||||
elsif parent = parents.first
|
||||
idx.read_tree(parent.tree.id)
|
||||
end
|
||||
idx
|
||||
end
|
||||
end
|
||||
|
||||
# Public: The committer for this commit.
|
||||
#
|
||||
# Returns a Grit::Actor.
|
||||
def actor
|
||||
@actor ||= begin
|
||||
@options[:name] = @wiki.default_committer_name if @options[:name].to_s.empty?
|
||||
@options[:email] = @wiki.default_committer_email if @options[:email].to_s.empty?
|
||||
Grit::Actor.new(@options[:name], @options[:email])
|
||||
end
|
||||
end
|
||||
|
||||
# Public: The parent commits to this pending commit.
|
||||
#
|
||||
# Returns an array of Grit::Commit instances.
|
||||
def parents
|
||||
@parents ||= begin
|
||||
arr = [@options[:parent] || @wiki.repo.commit(@wiki.ref)]
|
||||
arr.flatten!
|
||||
arr.compact!
|
||||
arr
|
||||
end
|
||||
end
|
||||
|
||||
# Adds a page to the given Index.
|
||||
#
|
||||
# dir - The String subdirectory of the Gollum::Page without any
|
||||
# prefix or suffix slashes (e.g. "foo/bar").
|
||||
# name - The String Gollum::Page filename_stripped.
|
||||
# format - The Symbol Gollum::Page format.
|
||||
# data - The String wiki data to store in the tree map.
|
||||
# allow_same_ext - A Boolean determining if the tree map allows the same
|
||||
# filename with the same extension.
|
||||
#
|
||||
# Raises Gollum::DuplicatePageError if a matching filename already exists.
|
||||
# This way, pages are not inadvertently overwritten.
|
||||
#
|
||||
# Returns nothing (modifies the Index in place).
|
||||
def add_to_index(dir, name, format, data, allow_same_ext = false)
|
||||
# spaces must be dashes
|
||||
dir.gsub!(' ', '-')
|
||||
name.gsub!(' ', '-')
|
||||
|
||||
path = @wiki.page_file_name(name, format)
|
||||
|
||||
dir = '/' if dir.strip.empty?
|
||||
|
||||
fullpath = ::File.join(*[@wiki.page_file_dir, dir, path].compact)
|
||||
fullpath = fullpath[1..-1] if fullpath =~ /^\//
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
# Update the given file in the repository's working directory if there
|
||||
# is a working directory present.
|
||||
#
|
||||
# dir - The String directory in which the file lives.
|
||||
# name - The String name of the page or the stripped filename
|
||||
# (should be pre-canonicalized if required).
|
||||
# format - The Symbol format of the page.
|
||||
#
|
||||
# Returns nothing.
|
||||
def update_working_dir(dir, name, format)
|
||||
unless @wiki.repo.bare
|
||||
if @wiki.page_file_dir
|
||||
dir = dir.size.zero? ? @wiki.page_file_dir : ::File.join(dir, @wiki.page_file_dir)
|
||||
end
|
||||
|
||||
path =
|
||||
if dir == ''
|
||||
@wiki.page_file_name(name, format)
|
||||
else
|
||||
::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)
|
||||
else
|
||||
@wiki.repo.git.checkout({}, 'HEAD', '--', path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Writes the commit to Git and runs the after_commit callbacks.
|
||||
#
|
||||
# Returns the String SHA1 of the new commit.
|
||||
def commit
|
||||
sha1 = index.commit(@options[:message], parents, actor, nil, @wiki.ref)
|
||||
@callbacks.each do |cb|
|
||||
cb.call(self, sha1)
|
||||
end
|
||||
sha1
|
||||
end
|
||||
|
||||
# Adds a callback to be fired after a commit.
|
||||
#
|
||||
# block - A block that expects this Committer instance and the created
|
||||
# commit's SHA1 as the arguments.
|
||||
#
|
||||
# Returns nothing.
|
||||
def after_commit(&block)
|
||||
@callbacks << block
|
||||
end
|
||||
|
||||
# Determine if a given page (regardless of format) is scheduled to be
|
||||
# deleted in the next commit for the given Index.
|
||||
#
|
||||
# map - The Hash map:
|
||||
# key - The String directory or filename.
|
||||
# val - The Hash submap or the String contents of the file.
|
||||
# path - The String path of the page file. This may include the format
|
||||
# extension in which case it will be ignored.
|
||||
#
|
||||
# Returns the Boolean response.
|
||||
def page_path_scheduled_for_deletion?(map, path)
|
||||
parts = path.split('/')
|
||||
if parts.size == 1
|
||||
deletions = map.keys.select { |k| !map[k] }
|
||||
downfile = parts.first.downcase.sub(/\.\w+$/, '')
|
||||
deletions.any? { |d| d.downcase.sub(/\.\w+$/, '') == downfile }
|
||||
else
|
||||
part = parts.shift
|
||||
if rest = map[part]
|
||||
page_path_scheduled_for_deletion?(rest, parts.join('/'))
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Determine if a given file is scheduled to be deleted in the next commit
|
||||
# for the given Index.
|
||||
#
|
||||
# map - The Hash map:
|
||||
# key - The String directory or filename.
|
||||
# val - The Hash submap or the String contents of the file.
|
||||
# path - The String path of the file including extension.
|
||||
#
|
||||
# Returns the Boolean response.
|
||||
def file_path_scheduled_for_deletion?(map, path)
|
||||
parts = path.split('/')
|
||||
if parts.size == 1
|
||||
deletions = map.keys.select { |k| !map[k] }
|
||||
deletions.any? { |d| d == parts.first }
|
||||
else
|
||||
part = parts.shift
|
||||
if rest = map[part]
|
||||
file_path_scheduled_for_deletion?(rest, parts.join('/'))
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# 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
|
||||
end
|
||||
@@ -1,94 +0,0 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
module Gollum
|
||||
class File
|
||||
Wiki.file_class = self
|
||||
|
||||
# Public: Initialize a file.
|
||||
#
|
||||
# wiki - The Gollum::Wiki in question.
|
||||
#
|
||||
# Returns a newly initialized Gollum::File.
|
||||
def initialize(wiki)
|
||||
@wiki = wiki
|
||||
@blob = nil
|
||||
@path = nil
|
||||
end
|
||||
|
||||
# Public: The url path required to reach this page within the repo.
|
||||
#
|
||||
# Returns the String url_path
|
||||
def url_path
|
||||
path = self.path
|
||||
path = path.sub(/\/[^\/]+$/, '/') if path.include?('/')
|
||||
path
|
||||
end
|
||||
|
||||
# Public: The url_path, but CGI escaped.
|
||||
#
|
||||
# Returns the String url_path
|
||||
def escaped_url_path
|
||||
CGI.escape(self.url_path).gsub('%2F','/')
|
||||
end
|
||||
|
||||
# Public: The on-disk filename of the file.
|
||||
#
|
||||
# Returns the String name.
|
||||
def name
|
||||
@blob && @blob.name
|
||||
end
|
||||
alias filename name
|
||||
|
||||
# Public: The raw contents of the page.
|
||||
#
|
||||
# Returns the String data.
|
||||
def raw_data
|
||||
@blob && @blob.data
|
||||
end
|
||||
|
||||
# Public: The Grit::Commit version of the file.
|
||||
attr_accessor :version
|
||||
|
||||
# Public: The String path of the file.
|
||||
attr_reader :path
|
||||
|
||||
# Public: The String mime type of the file.
|
||||
def mime_type
|
||||
@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
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
# Find a file in the given Gollum repo.
|
||||
#
|
||||
# name - The full String path.
|
||||
# version - The String version ID to find.
|
||||
#
|
||||
# Returns a Gollum::File or nil if the file could not be found.
|
||||
def find(name, version)
|
||||
checked = name.downcase
|
||||
map = @wiki.tree_map_for(version)
|
||||
if entry = map.detect { |entry| entry.path.downcase == checked }
|
||||
@path = name
|
||||
@blob = entry.blob(@wiki.repo)
|
||||
@version = version.is_a?(Grit::Commit) ? version : @wiki.commit_for(version)
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,155 +0,0 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
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
|
||||
# common use cases:
|
||||
# set pages to wiki.pages and show_all to false
|
||||
# set pages to wiki.pages + wiki.files and show_all to true
|
||||
def initialize pages, options = {}
|
||||
@pages = pages
|
||||
@show_all = options[:show_all] || false
|
||||
@checked = options[:collapse_tree] ? '' : "checked"
|
||||
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}"><span class="icon"></span>#{name}</a></li>)
|
||||
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
|
||||
"</ol></li>\n"
|
||||
end
|
||||
|
||||
def url_for_page page
|
||||
url = ''
|
||||
if @show_all
|
||||
# Remove ext for valid pages.
|
||||
filename = page.filename
|
||||
filename = Page::valid_page_name?(filename) ? filename.chomp(::File.extname(filename)) : filename
|
||||
|
||||
url = ::File.join(::File.dirname(page.path), filename)
|
||||
else
|
||||
url = ::File.join(::File.dirname(page.path), page.filename_stripped)
|
||||
end
|
||||
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 ]
|
||||
html += <<-HTML
|
||||
<li>
|
||||
<label>#{::File.dirname(page.path)}</label> <input type="checkbox" #{@checked} />
|
||||
<ol>
|
||||
#{new_page page}
|
||||
</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
|
||||
@@ -1,397 +0,0 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
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?
|
||||
upstream_to_url :exclude => ['_Header', '_Footer', '_Sidebar']
|
||||
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
|
||||
set :default_markup, :markdown
|
||||
|
||||
set :mustache, {
|
||||
# Tell mustache where the Views constant lives
|
||||
:namespace => Precious,
|
||||
|
||||
# Mustache templates live here
|
||||
:templates => "#{dir}/templates",
|
||||
|
||||
# Tell mustache where the views are
|
||||
:views => "#{dir}/views"
|
||||
}
|
||||
|
||||
# Sinatra error handling
|
||||
configure :development, :staging do
|
||||
enable :show_exceptions, :dump_errors
|
||||
disable :raise_errors, :clean_trace
|
||||
end
|
||||
|
||||
configure :test do
|
||||
enable :logging, :raise_errors, :dump_errors
|
||||
end
|
||||
|
||||
before do
|
||||
@base_url = url('/', false).chomp('/')
|
||||
# above will detect base_path when it's used with map in a config.ru
|
||||
settings.wiki_options.merge!({ :base_path => @base_url })
|
||||
@css = settings.wiki_options[:css]
|
||||
end
|
||||
|
||||
get '/' do
|
||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
redirect clean_url(::File.join(@base_url, page_dir, '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
|
||||
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_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
unless page_dir.empty?
|
||||
# --page-file-dir docs
|
||||
# /docs/Home should be created in /Home
|
||||
# not /docs/Home because write_page will append /docs
|
||||
@path = @path.sub(page_dir, '/') if @path.start_with? page_dir
|
||||
end
|
||||
|
||||
page = wikip.page
|
||||
if page
|
||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
redirect to("/#{clean_url(::File.join(page_dir, page.escaped_url_path))}")
|
||||
else
|
||||
mustache :create
|
||||
end
|
||||
end
|
||||
|
||||
post '/create' do
|
||||
name = params[:page].to_url
|
||||
path = sanitize_empty_params(params[:path]) || ''
|
||||
format = params[:format].intern
|
||||
wiki = wiki_new
|
||||
|
||||
begin
|
||||
wiki.write_page(name, format, params[:content], commit_message, path)
|
||||
|
||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
redirect to("/#{clean_url(::File.join(page_dir, path, name))}")
|
||||
rescue Gollum::DuplicatePageError => e
|
||||
@message = "Duplicate page: #{e.message}"
|
||||
mustache :error
|
||||
end
|
||||
end
|
||||
|
||||
post '/revert/:page/*' do
|
||||
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 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."
|
||||
mustache :compare
|
||||
end
|
||||
end
|
||||
|
||||
post '/preview' do
|
||||
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
|
||||
@h1_title = wiki.h1_title
|
||||
@editable = false
|
||||
mustache :page
|
||||
end
|
||||
|
||||
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/*' do
|
||||
@file = params[:splat].first
|
||||
@versions = params[:versions] || []
|
||||
if @versions.size < 2
|
||||
redirect to("/history/#{@file}")
|
||||
else
|
||||
redirect to("/compare/%s/%s...%s" % [
|
||||
@file,
|
||||
@versions.last,
|
||||
@versions.first]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
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 %r{/(.+?)/([0-9a-f]{40})} do
|
||||
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
|
||||
@editable = true
|
||||
mustache :page
|
||||
else
|
||||
halt 404
|
||||
end
|
||||
end
|
||||
|
||||
get '/search' do
|
||||
@query = params[:q]
|
||||
wiki = wiki_new
|
||||
# Sort wiki search results by count (desc) and then by name (asc)
|
||||
@results = wiki.search(@query).sort{ |a, b| (a[:count] <=> b[:count]).nonzero? || b[:name] <=> a[:name] }.reverse
|
||||
@name = @query
|
||||
mustache :search
|
||||
end
|
||||
|
||||
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
|
||||
@results += wiki.files if settings.wiki_options[:show_all]
|
||||
@ref = wiki.ref
|
||||
mustache :pages
|
||||
end
|
||||
|
||||
get '/fileview' do
|
||||
wiki = wiki_new
|
||||
options = settings.wiki_options
|
||||
content = wiki.pages
|
||||
# if showing all files include wiki.files
|
||||
content += wiki.files if options[:show_all]
|
||||
|
||||
# must pass wiki_options to FileView
|
||||
# --show-all and --collapse-tree can be set.
|
||||
@results = Gollum::FileView.new(content, options).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(fullpath)
|
||||
name = extract_name(fullpath)
|
||||
path = extract_path(fullpath) || '/'
|
||||
wiki = wiki_new
|
||||
|
||||
if page = wiki.paged(name, path, exact = true)
|
||||
@page = page
|
||||
@name = name
|
||||
@editable = true
|
||||
@content = page.formatted_data
|
||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||
@mathjax = wiki.mathjax
|
||||
@h1_title = wiki.h1_title
|
||||
mustache :page
|
||||
elsif file = wiki.file(fullpath)
|
||||
content_type file.mime_type
|
||||
file.raw_data
|
||||
else
|
||||
page_path = [path, name].compact.join('/')
|
||||
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
||||
end
|
||||
end
|
||||
|
||||
def update_wiki_page(wiki, page, content, commit, name = nil, format = nil)
|
||||
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)
|
||||
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
|
||||
commit_message = { :message => params[:message] }
|
||||
author_parameters = session['gollum.author']
|
||||
commit_message.merge! author_parameters unless author_parameters.nil?
|
||||
commit_message
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,36 +0,0 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
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.
|
||||
# Remove all double slashes
|
||||
def clean_url url
|
||||
return url if url.nil?
|
||||
url.gsub('%2F','/').gsub(/^\/+/,'').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
|
||||
@@ -1,128 +0,0 @@
|
||||
*, 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
|
||||
{
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
li.file a span.icon
|
||||
{
|
||||
width: 14px;
|
||||
height: 18px;
|
||||
background: url(../images/fileview/document.png) 0 0 no-repeat;
|
||||
display: inline-block;
|
||||
margin-right: 7px;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
li.file a[href *= '.pdf'] span.icon { background: url(../images/fileview/document.png) 0 0 no-repeat; }
|
||||
li.file a[href *= '.html'] span.icon { background: url(../images/fileview/document.png) 0 0 no-repeat; }
|
||||
li.file a[href $= '.css'] span.icon { background: url(../images/fileview/document.png) 0 0 no-repeat; }
|
||||
li.file a[href $= '.js'] span.icon { 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 */ }
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
/* @control dialog */
|
||||
|
||||
#gollum-dialog-dialog {
|
||||
display: block;
|
||||
overflow: visible;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-inner {
|
||||
margin: 0 0 0 -225px;
|
||||
position: relative;
|
||||
width: 450px;
|
||||
|
||||
border: 7px solid #999;
|
||||
border: 7px solid rgba(0, 0, 0, 0.3);
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-bg {
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
padding: 1em;
|
||||
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#ffffff));
|
||||
background: -moz-linear-gradient(top, #f7f7f7, #ffffff);
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-inner h4 {
|
||||
border-bottom: 1px solid #ddd;
|
||||
color: #000;
|
||||
font-size: 1.8em;
|
||||
line-height: normal;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0.75em 0;
|
||||
padding: 0 0 0.3em 0;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body fieldset {
|
||||
display: block;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body fieldset .field {
|
||||
margin: 0 0 1.5em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body fieldset .field label {
|
||||
color: #000;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body fieldset .field input[type="text"] {
|
||||
border: 1px solid #ddd;
|
||||
display: block;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
margin: 0.3em 0 0 0;
|
||||
padding: 0.3em 0.5em;
|
||||
width: 96.5%;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body fieldset .field input.code {
|
||||
font-family: 'Monaco', 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-body fieldset .field:last-child {
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog-buttons {
|
||||
border-top: 1px solid #ddd;
|
||||
overflow: hidden;
|
||||
margin: 1.5em 0 0 0;
|
||||
padding: 1em 0 0 0;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog a.minibutton {
|
||||
float: right;
|
||||
margin-right: 0.5em;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog a.minibutton,
|
||||
#gollum-dialog-dialog a.minibutton:visited {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #d4d4d4;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0 0.8em;
|
||||
padding: 0.4em 1em;
|
||||
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
|
||||
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
|
||||
|
||||
border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
#gollum-dialog-dialog a.minibutton:hover {
|
||||
background: #3072b3;
|
||||
border-color: #518cc6 #518cc6 #2a65a0;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
text-decoration: none;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
|
||||
background: -moz-linear-gradient(top, #599bdc, #3072b3);
|
||||
}
|
||||
@@ -1,539 +0,0 @@
|
||||
/*
|
||||
editor.css
|
||||
Wiki editor formatting
|
||||
*/
|
||||
|
||||
a {
|
||||
-moz-outline: none !important;
|
||||
}
|
||||
|
||||
.jaws {
|
||||
/* JAWS should see it, but you can't */
|
||||
display: block;
|
||||
height: 1px;
|
||||
left: -5000px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: -5000px;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
#gollum-editor {
|
||||
border: 1px solid #e4e4e4;
|
||||
background: #f9f9f9;
|
||||
margin: 1em 0 5em;
|
||||
overflow: hidden;
|
||||
padding: 1em 1em 0.4em;
|
||||
|
||||
border-radius: 1em;
|
||||
-moz-border-radius: 1em;
|
||||
-webkit-border-radius: 1em;
|
||||
}
|
||||
|
||||
.ff #gollum-editor,
|
||||
.ie #gollum-editor {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
#gollum-editor form fieldset {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#gollum-editor .singleline {
|
||||
display: block;
|
||||
margin: 0 0 0.7em 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#gollum-editor .singleline input {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
color: #000;
|
||||
font-size: 1.1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5em;
|
||||
margin: 1em 0 0.4em;
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
#gollum-editor .singleline input.ph {
|
||||
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;
|
||||
}
|
||||
|
||||
#gollum-editor-title-field.active {
|
||||
border-bottom: 1px solid #ddd;
|
||||
display: block;
|
||||
margin: 0 0 0.3em 0;
|
||||
padding: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
#gollum-editor-title-field input#gollum-editor-page-title.ph {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* @control editor-view-tab */
|
||||
#gollum-editor #gollum-editor-type-switcher {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* @control function-bar */
|
||||
#gollum-editor #gollum-editor-function-bar {
|
||||
border-bottom: 1px solid #ddd;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
#gollum-editor-title-field + #gollum-editor-function-bar {
|
||||
margin-top: 0.6em;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar #gollum-editor-function-buttons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar.active #gollum-editor-function-buttons {
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
padding: 0 0 1.1em 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar a.function-button {
|
||||
background: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
display: block;
|
||||
float: left;
|
||||
height: 25px;
|
||||
overflow: hidden;
|
||||
margin: 0.2em 0.5em 0 0;
|
||||
/* text-indent: -5000px; */
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
width: 25px;
|
||||
|
||||
border-radius: 0.3em;
|
||||
-moz-border-radius: 0.3em;
|
||||
-webkit-border-radius: 0.3em;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
|
||||
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar a.function-button:hover {
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
text-decoration: none;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
|
||||
background: -moz-linear-gradient(top, #599bdc, #3072b3);
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar a span {
|
||||
background-image: url(../images/icon-sprite.png);
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
height: 25px;
|
||||
overflow: hidden;
|
||||
text-indent: -5000px;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
a#function-bold span { background-position: 0 0; }
|
||||
a#function-italic span { background-position: -27px 0; }
|
||||
a#function-underline span { background-position: -54px 0; }
|
||||
a#function-code span { background-position: -82px 0; }
|
||||
a#function-ul span { background-position: -109px 0; }
|
||||
a#function-ol span { background-position: -136px 0; }
|
||||
a#function-blockquote span { background-position: -163px 0; }
|
||||
a#function-hr span { background-position: -190px 0; }
|
||||
a#function-h1 span { background-position: -217px 0; }
|
||||
a#function-h2 span { background-position: -244px 0; }
|
||||
a#function-h3 span { background-position: -271px 0; }
|
||||
a#function-link span { background-position: -298px 0; }
|
||||
a#function-image span { background-position: -324px 0; }
|
||||
a#function-help span { background-position: -405px 0; }
|
||||
|
||||
a#function-bold:hover span { background-position: 0 -28px; }
|
||||
a#function-italic:hover span { background-position: -27px -28px; }
|
||||
a#function-underline:hover span { background-position: -54px -28px; }
|
||||
a#function-code:hover span { background-position: -82px -28px; }
|
||||
a#function-ul:hover span { background-position: -109px -28px; }
|
||||
a#function-ol:hover span { background-position: -136px -28px; }
|
||||
a#function-blockquote:hover span { background-position: -163px -28px; }
|
||||
a#function-hr:hover span { background-position: -190px -28px; }
|
||||
a#function-h1:hover span { background-position: -217px -28px; }
|
||||
a#function-h2:hover span { background-position: -244px -28px; }
|
||||
a#function-h3:hover span { background-position: -271px -28px; }
|
||||
a#function-link:hover span { background-position: -298px -28px; }
|
||||
a#function-image:hover span { background-position: -324px -28px; }
|
||||
a#function-help:hover span { background-position: -405px -28px; }
|
||||
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar a.disabled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar span.function-divider {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 0.5em;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar #gollum-editor-format-selector {
|
||||
overflow: hidden;
|
||||
padding: .2em 0 .5em 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector select {
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
|
||||
float: right;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
padding: 0.3em 0.4em;
|
||||
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector label {
|
||||
color: #999;
|
||||
float: right;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
padding: .3em 0.5em 0 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector label:after {
|
||||
content: ':';
|
||||
}
|
||||
|
||||
|
||||
/* @section form-fields */
|
||||
|
||||
#gollum-editor textarea {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.4em;
|
||||
margin: 1em 0 0.4em;
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
height: 20em;
|
||||
}
|
||||
|
||||
#gollum-editor input#gollum-editor-submit {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #d4d4d4;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0.4em 1em;
|
||||
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
|
||||
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
|
||||
|
||||
border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
.webkit #gollum-editor input#gollum-editor-submit {
|
||||
padding: 0.5em 1em 0.45em;
|
||||
}
|
||||
|
||||
.ie #gollum-editor input#gollum-editor-submit {
|
||||
padding: 0.4em 1em 0.5em;
|
||||
}
|
||||
|
||||
#gollum-editor input#gollum-editor-submit:hover {
|
||||
background: #3072b3;
|
||||
border-color: #518cc6 #518cc6 #2a65a0;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
text-decoration: none;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
|
||||
background: -moz-linear-gradient(top, #599bdc, #3072b3);
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed,
|
||||
#gollum-editor .expanded {
|
||||
border-bottom: 1px solid #ddd;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding: 0.5em 0 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-body + .collapsed,
|
||||
#gollum-editor #gollum-editor-body + .expanded {
|
||||
border-top: 1px solid #ddd;
|
||||
margin-top: 0.7em;
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed a.button,
|
||||
#gollum-editor .expanded a.button {
|
||||
background: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
display: block;
|
||||
float: left;
|
||||
height: 25px;
|
||||
overflow: hidden;
|
||||
margin: 0.2em 0.5em 0.75em 0;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
width: 25px;
|
||||
|
||||
border-radius: 0.3em;
|
||||
-moz-border-radius: 0.3em;
|
||||
-webkit-border-radius: 0.3em;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
|
||||
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed h4,
|
||||
#gollum-editor .expanded h4 {
|
||||
font-size: 1.6em;
|
||||
float: left;
|
||||
margin: 0;
|
||||
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 a.button:hover {
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
text-decoration: none;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
|
||||
background: -moz-linear-gradient(top, #599bdc, #3072b3);
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed a span,
|
||||
#gollum-editor .expanded a span {
|
||||
background-image: url(../images/icon-sprite.png);
|
||||
background-position: -351px -1px;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
height: 25px;
|
||||
overflow: hidden;
|
||||
text-indent: -5000px;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed a:hover span {
|
||||
background-position: -351px -28px;
|
||||
}
|
||||
|
||||
#gollum-editor .expanded a span {
|
||||
background-position: -378px 0;
|
||||
}
|
||||
|
||||
#gollum-editor .expanded a:hover span {
|
||||
background-position: -378px -28px;
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed textarea {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#gollum-editor .expanded textarea {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
clear: both;
|
||||
display: block;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
height: 7em;
|
||||
line-height: 1.4em;
|
||||
margin: 0.7em 0;
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
/* @control minibutton */
|
||||
|
||||
#gollum-editor a.minibutton,
|
||||
#gollum-editor a.minibutton:visited {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #d4d4d4;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.2em;
|
||||
margin: 0 0 0 0.8em;
|
||||
padding: 0.5em 1em;
|
||||
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
|
||||
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
|
||||
|
||||
border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
#gollum-editor a.minibutton:hover {
|
||||
background: #3072b3;
|
||||
border-color: #518cc6 #518cc6 #2a65a0;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
text-decoration: none;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
|
||||
background: -moz-linear-gradient(top, #599bdc, #3072b3);
|
||||
}
|
||||
|
||||
|
||||
#gollum-editor #gollum-editor-preview {
|
||||
float: left;
|
||||
font-weight: normal;
|
||||
padding: left;
|
||||
}
|
||||
|
||||
|
||||
/* @section help */
|
||||
#gollum-editor-help {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
border: 1px solid #ddd;
|
||||
border-width: 0 1px 1px 1px;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent,
|
||||
#gollum-editor-help-list {
|
||||
display: block;
|
||||
float: left;
|
||||
height: 17em;
|
||||
list-style-type: none;
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
padding: 1em 0;
|
||||
width: 18%;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent {
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
|
||||
#gollum-editor-help-list {
|
||||
background: #fafafa;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent li,
|
||||
#gollum-editor-help-list li {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent li a,
|
||||
#gollum-editor-help-list li a {
|
||||
border: 1px solid transparent;
|
||||
border-width: 1px 0;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
padding: 0.2em 1em;
|
||||
text-shadow: 0 -1px 0 #fff;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent li a:hover,
|
||||
#gollum-editor-help-list li a:hover {
|
||||
background: #fff;
|
||||
border-color: #f0f0f0;
|
||||
text-decoration: none;
|
||||
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent li a.selected,
|
||||
#gollum-editor-help-list li a.selected {
|
||||
border: 1px solid #eee;
|
||||
border-bottom-color: #e7e7e7;
|
||||
border-width: 1px 0;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
|
||||
box-shadow: 0 1px 2px #f0f0f0;
|
||||
}
|
||||
|
||||
#gollum-editor-help-wrapper {
|
||||
background: #fff;
|
||||
overflow: auto;
|
||||
height: 17em;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#gollum-editor-help-content {
|
||||
font-size: 1.2em;
|
||||
margin: 0 1em 0 0.5em;
|
||||
padding: 0;
|
||||
line-height: 1.8em;
|
||||
}
|
||||
|
||||
#gollum-editor-help-content p {
|
||||
margin: 0 0 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* IE */
|
||||
.ie #gollum-editor .singleline input {
|
||||
padding-top: 0.25em;
|
||||
padding-bottom: 0.75em;
|
||||
}
|
||||
@@ -1,718 +0,0 @@
|
||||
#wiki-wrapper #template blockquote {
|
||||
margin: 1em 0;
|
||||
border-left: 4px solid #ddd;
|
||||
padding-left: .8em;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
/*
|
||||
gollum.css
|
||||
A basic stylesheet for Gollum
|
||||
*/
|
||||
|
||||
/* @section core */
|
||||
body, html {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 10px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#wiki-wrapper {
|
||||
margin: 0 auto;
|
||||
overflow: visible;
|
||||
width: 920px;
|
||||
padding-left:20px;
|
||||
padding-right:20px;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #4183c4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover, a:visited {
|
||||
color: #4183c4;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/* @section head */
|
||||
#head {
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 4em 0 1.5em;
|
||||
padding-bottom: 0.3em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#head h1 {
|
||||
font-size: 33px;
|
||||
float: left;
|
||||
line-height: normal;
|
||||
margin: 0;
|
||||
padding: 2px 0 0 0;
|
||||
}
|
||||
|
||||
#head ul.actions {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* @section content */
|
||||
#wiki-content {
|
||||
height: 1%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#wiki-content .wrap {
|
||||
height: 1%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* @section comments */
|
||||
#wiki-body #inline-comment {
|
||||
display: none; /* todo */
|
||||
}
|
||||
|
||||
/* @section body */
|
||||
#wiki-body {
|
||||
display: block;
|
||||
float: left;
|
||||
clear: left;
|
||||
margin-right: 3%;
|
||||
margin-bottom: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.has-rightbar #wiki-body {
|
||||
width: 68%;
|
||||
}
|
||||
|
||||
/* @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;
|
||||
}
|
||||
#wiki-toc-main > div {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* @section rightbar */
|
||||
#wiki-rightbar {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 13px;
|
||||
float: right;
|
||||
padding: 7px;
|
||||
width: 25%;
|
||||
color: #555;
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
|
||||
#wiki-rightbar p {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
|
||||
#wiki-rightbar > p:first-child {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/* Back arrow */
|
||||
#wiki-rightbar p.parent:before {
|
||||
color: #666;
|
||||
content: "← ";
|
||||
}
|
||||
|
||||
/* @section footer */
|
||||
|
||||
#wiki-footer {
|
||||
clear: both;
|
||||
margin: 2em 0 5em;
|
||||
}
|
||||
|
||||
.has-rightbar #wiki-footer {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#wiki-header #header-content,
|
||||
#wiki-footer #footer-content {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
padding: 1em;
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
#wiki-header #header-content {
|
||||
margin-bottom: 1.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 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 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:first-child {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ff #wiki-footer #footer-content ul.links li:first-child {
|
||||
margin: 0 -0.75em 0 0;
|
||||
}
|
||||
|
||||
/* @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 span.username {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* @section history */
|
||||
.history h1 {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.history h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#wiki-history {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#wiki-history fieldset {
|
||||
border: 0;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#wiki-history table, #wiki-history tbody {
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#wiki-history table tr {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#wiki-history table tr {
|
||||
background-color: #ebf2f6;
|
||||
}
|
||||
|
||||
#wiki-history table tr td {
|
||||
border: 1px solid #c0dce9;
|
||||
font-size: 1em;
|
||||
line-height: 1.6em;
|
||||
margin: 0;
|
||||
padding: 0.3em 0.7em;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.checkbox {
|
||||
width: 4em;
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
#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:nth-child(2n),
|
||||
#wiki-history table tr.alt-row {
|
||||
background-color: #f3f7fa;
|
||||
}
|
||||
|
||||
#wiki-history table tr.selected {
|
||||
background-color: #ffffea !important;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.commit-name {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.commit-name span.time-elapsed {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.author {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.author a {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.author a span.username {
|
||||
display: block;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
#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 {
|
||||
margin: 0 0.6em 0 0;
|
||||
}
|
||||
|
||||
|
||||
/* @section edit */
|
||||
.edit h1 {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.edit h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* @section search */
|
||||
.results h1 {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.results h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.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 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 p#no-results {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.results #footer ul.actions li {
|
||||
margin: 0 1em 0 0;
|
||||
}
|
||||
|
||||
|
||||
/* @section compare */
|
||||
.compare h1 {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.compare h1 strong {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.compare #compare-content {
|
||||
margin-top: 3em;
|
||||
}
|
||||
|
||||
.compare .data {
|
||||
border: 1px solid #ddd;
|
||||
margin: 1em 0 2em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.compare .data table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.compare .data pre {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.compare .data pre div {
|
||||
padding: 0 0 0 1em;
|
||||
}
|
||||
|
||||
.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 {
|
||||
margin-left: 0;
|
||||
margin-right: 0.6em;
|
||||
}
|
||||
|
||||
.compare #footer {
|
||||
margin-bottom: 7em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* @control syntax */
|
||||
.highlight { background: #ffffff; }
|
||||
.highlight .c { color: #999988; font-style: italic }
|
||||
.highlight .err { color: #a61717; background-color: #e3d2d2 }
|
||||
.highlight .k { font-weight: bold }
|
||||
.highlight .o { font-weight: bold }
|
||||
.highlight .cm { color: #999988; font-style: italic }
|
||||
.highlight .cp { color: #999999; font-weight: bold }
|
||||
.highlight .c1 { color: #999988; font-style: italic }
|
||||
.highlight .cs { color: #999999; font-weight: bold; font-style: italic }
|
||||
.highlight .gd { color: #000000; background-color: #ffdddd }
|
||||
.highlight .gd .x { color: #000000; background-color: #ffaaaa }
|
||||
.highlight .ge { font-style: italic }
|
||||
.highlight .gr { color: #aa0000 }
|
||||
.highlight .gh { color: #999999 }
|
||||
.highlight .gi { color: #000000; background-color: #ddffdd }
|
||||
.highlight .gi .x { color: #000000; background-color: #aaffaa }
|
||||
.highlight .gc { color: #999; background-color: #EAF2F5 }
|
||||
.highlight .go { color: #888888 }
|
||||
.highlight .gp { color: #555555 }
|
||||
.highlight .gs { font-weight: bold }
|
||||
.highlight .gu { color: #aaaaaa }
|
||||
.highlight .gt { color: #aa0000 }
|
||||
|
||||
|
||||
/* @control minibutton */
|
||||
ul.actions {
|
||||
display: block;
|
||||
list-style-type: none;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.actions li {
|
||||
float: left;
|
||||
font-size: 0.9em;
|
||||
margin-left: 0.6em;
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
.minibutton a {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #d4d4d4;
|
||||
color: #333;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0.4em 1em;
|
||||
height: 1.4em;
|
||||
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
|
||||
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
|
||||
|
||||
border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
#search-submit {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #d4d4d4;
|
||||
color: #333;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0.4em 1em;
|
||||
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
|
||||
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
|
||||
|
||||
border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
.minibutton a:hover,
|
||||
#search-submit:hover {
|
||||
background: #3072b3;
|
||||
border-color: #518cc6 #518cc6 #2a65a0;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
text-decoration: none;
|
||||
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
|
||||
background: -moz-linear-gradient(top, #599bdc, #3072b3);
|
||||
}
|
||||
|
||||
.minibutton a:visited {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
/* @special error */
|
||||
#wiki-wrapper.error {
|
||||
height: 1px;
|
||||
position: absolute;
|
||||
overflow: visible;
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#error {
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #e4e4e4;
|
||||
left: 50%;
|
||||
overflow: hidden;
|
||||
padding: 2%;
|
||||
margin: -10% 0 0 -35%;
|
||||
position: absolute;
|
||||
width: 70%;
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
|
||||
#error h1 {
|
||||
font-size: 3em;
|
||||
line-height: normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#error p {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.6em;
|
||||
margin: 1em 0 0.5em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
/* @control searchbar */
|
||||
#head #searchbar {
|
||||
float: right;
|
||||
padding: 0;
|
||||
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;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
.ie8 #head #searchbar #searchbar-fauxtext input#search-query {
|
||||
padding: 0.5em 0 0 0.5em;
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#pages li a.file,
|
||||
#pages li a.folder {
|
||||
background-image: url(../images/fileview/document.png);
|
||||
background-position: 0 1px;
|
||||
background-repeat: no-repeat;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/* IE7-specific styles */
|
||||
|
||||
.ie #head #searchbar #searchbar-fauxtext input#search-query {
|
||||
border: 0;
|
||||
float: left;
|
||||
padding: 0.4em 0 0 0.5em;
|
||||
}
|
||||
|
||||
.ie #head #searchbar #searchbar-fauxtext #search-submit span {
|
||||
height: 2.25em;
|
||||
}
|
||||
|
||||
#head #searchbar,
|
||||
#head ul.actions {
|
||||
margin: 1em 0 0 0;
|
||||
}
|
||||
|
||||
ul.actions {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.compare #footer ul.actions {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.compare div.data {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.history #version-form {
|
||||
margin: -0.5em 0 -0.5em !important;
|
||||
}
|
||||
|
||||
#gollum-editor {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
#gollum-editor-help-parent li a,
|
||||
#gollum-editor-help-list li a {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-format-selector {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
#gollum-editor .singleline input {
|
||||
padding-top: 0.25em;
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed {
|
||||
padding-bottom: 1.1em;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-submit {
|
||||
padding: 0.5em 1em 0.3em !important;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-preview {
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
#gollum-editor form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-format-selector label {
|
||||
padding-top: 0.1em !important;
|
||||
}
|
||||
@@ -1,629 +0,0 @@
|
||||
/*
|
||||
Gollum v3 Template
|
||||
*/
|
||||
|
||||
/* margin & padding reset*/
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 13.34px helvetica,arial,freesans,clean,sans-serif;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4183C4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.absent {
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
.markdown-body a[id].wiki-toc-anchor {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.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: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.markdown-body h2 {
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
color: #000;
|
||||
}
|
||||
.markdown-body h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
.markdown-body h4 {
|
||||
font-size: 16px;
|
||||
}
|
||||
.markdown-body h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
.markdown-body h6 {
|
||||
color: #777;
|
||||
font-size: 14px;
|
||||
}
|
||||
.markdown-body p,
|
||||
.markdown-body blockquote,
|
||||
.markdown-body ul,
|
||||
.markdown-body ol,
|
||||
.markdown-body dl,
|
||||
.markdown-body table,
|
||||
.markdown-body pre {
|
||||
margin: 0px 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.markdown-body li {
|
||||
margin: 0px;
|
||||
}
|
||||
.markdown-body hr {
|
||||
background: transparent url(../images/dirty-shade.png) repeat-x 0 0;
|
||||
border: 0 none;
|
||||
color: #ccc;
|
||||
height: 4px;
|
||||
padding: 0;
|
||||
}
|
||||
.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 {
|
||||
}
|
||||
.markdown-body h1+h2+h3{
|
||||
margin-top: 30px;
|
||||
}
|
||||
.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;
|
||||
border-spacing: 0;
|
||||
}
|
||||
.markdown-body table tr {
|
||||
border-top: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.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%;
|
||||
}
|
||||
.markdown-body span.frame {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.markdown-body span.float-left span {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
.markdown-body span.float-right {
|
||||
display: block;
|
||||
margin-left: 13px;
|
||||
overflow: hidden;
|
||||
float: right;
|
||||
}
|
||||
.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-radius: 3px;
|
||||
}
|
||||
.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;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.markdown-body pre pre,
|
||||
.markdown-body pre code,
|
||||
.markdown-body pre tt {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 939 B |
|
Before Width: | Height: | Size: 177 B |
|
Before Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 433 B |
|
Before Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 376 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* ASCIIDoc Language Definition
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
var ASCIIDoc = {
|
||||
|
||||
'function-bold' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "*$1*$2"
|
||||
},
|
||||
|
||||
'function-italic' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "_$1_$2"
|
||||
},
|
||||
|
||||
'function-code' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "+$1+$2"
|
||||
},
|
||||
|
||||
'function-ul' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
'function-ol' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: ". $1$2"
|
||||
},
|
||||
|
||||
'function-blockquote' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "----\n$1$2\n----\n"
|
||||
},
|
||||
|
||||
'function-link' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
$.GollumEditor.Dialog.init({
|
||||
title: 'Insert Link',
|
||||
fields: [
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
help: 'The text to display to the user.',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
name: 'URL',
|
||||
type: 'text',
|
||||
help: 'The URL to link to.'
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var h = '';
|
||||
if ( res['text'] && res['href'] ) {
|
||||
h = res['href'] + '[' +
|
||||
res['text'] + ']';
|
||||
}
|
||||
$.GollumEditor.replaceSelection( h );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
'function-image' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
$.GollumEditor.Dialog.init({
|
||||
title: 'Insert Image',
|
||||
fields: [
|
||||
{
|
||||
id: 'url',
|
||||
name: 'Image URL',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
id: 'alt',
|
||||
name: 'Alt Text',
|
||||
type: 'text'
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var h = '';
|
||||
if ( res['url'] && res['alt'] ) {
|
||||
h = 'image::' + res['url'] +
|
||||
'[' + res['alt'] + ']';
|
||||
}
|
||||
$.GollumEditor.replaceSelection( h );
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.GollumEditor.defineLanguage('asciidoc', ASCIIDoc);
|
||||
|
||||
|
||||
var ASCIIDocHelp = [
|
||||
{
|
||||
menuName: 'Text Formatting',
|
||||
content: [
|
||||
{
|
||||
menuName: 'Headers',
|
||||
data: '<p>ASCIIDoc headers can be written in two ways: with differing underlines or with different indentation using <code>=</code> (equals sign). ASCIIDoc supports headings 1-4. The editor will automatically use the <code>=</code> notation. To create a level one header, prefix your line with one <code>=</code>. Level two headers are created with <code>==</code> and so on.</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Bold / Italic',
|
||||
data: '<p>To display text as <strong>bold</strong>, wrap the text in <code>*</code> (asterisks). To display text as <em>italic</em>, wrap the text in <code>_</code> (underscores). To create <code>monospace</code> text, wrap the text in <code>+</code> (plus signs).'
|
||||
},
|
||||
{
|
||||
menuName: 'Scripts',
|
||||
data: '<p>Superscript and subscript is created the same way as other inline formats. To create superscript text, wrap your text in <code>^</code> (carats). To create subscript text, wrap your text in <code>~</code> (tildes).</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Special Characters',
|
||||
data: '<p>ASCIIDoc will automatically convert textual representations of commonly-used special characters. For example, <code>(R)</code> becomes ®, <code>(C)</code> becomes © and <code>(TM)</code> becomes ™.</p>'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
menuName: 'Blocks',
|
||||
content: [
|
||||
{
|
||||
menuName: 'Paragraphs',
|
||||
data: '<p>ASCIIDoc allows paragraphs to have optional titles or icons to denote special sections. To make a normal paragraph, simply add a line between blocks and a new paragraph will start. If you want to title your paragraphs, adda line prefixed by <code>.</code> (full stop). An example paragraph with optional title is displayed below:<br><br><code>.Optional Title<br><br>This is my paragraph. It is two sentences long.</code></p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Source Blocks',
|
||||
data: '<p>To create source blocks (long blocks of code), follow the same syntax as above but with an extra line denoting the inline source and lines of four dashes (<code>----</code>) delimiting the source block.. An example of Python source is below:<br><br><code>.python.py<br>[source,python]<br>----<br># i just wrote a comment in python<br># and maybe one more<br>----</code></p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Comment Blocks',
|
||||
data: '<p>Comment blocks are useful if you want to keep notes for yourself inline but do not want them displayed to the public. To create a comment block, simply wrap the paragraph in dividers with four slashes (<code>////</code>). An example comment block is below:<br><br><code>////<br>My comment block is here now<br><br>It can be multiple paragraphs. Really.<br>////</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Quote Blocks',
|
||||
data: '<p>Quote blocks work much like comment blocks — simply create dividers using four underscores (<code>____</code>) around your quote. An example quote block is displayed below:<br><code>____<br>This is my quote block. Quote something nice here, otherwise there is no point in quoting.<br>____</code></p>'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
menuName: 'Macros',
|
||||
content: [
|
||||
{
|
||||
menuName: 'Links',
|
||||
data: '<p>To create links to external pages, you can simply write the URI if you want the URI to link to itself. (i.e., <code>http://github.com/</code> will automatically be parsed to <a href="javascript:void(0);">http://github.com/</a>. If you want different text to be displayed, simply append it to the end of the URI in between <code>[</code> (brackets.) For example, <code>http://github.com/[GitHub]</code> will be parsed as <a href="javascript:void(0);">GitHub</a>, with the URI pointing to <code>http://github.com</code>.</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Images',
|
||||
data: '<p>Images in ASCIIDoc work much like hyperlinks, but image URLs are prefixed with <code>image:</code>. For example, to link to an image at <code>images/icons/home.png</code>, write <code>image:images/icons/home.png</code>. Alt text can be added by appending the text to the URI in <code>[</code> (brackets).</p>'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
$.GollumEditor.defineHelp('asciidoc', ASCIIDocHelp);
|
||||
|
||||
})(jQuery);
|
||||
@@ -1,105 +0,0 @@
|
||||
/**
|
||||
* Creole Language Definition
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
|
||||
var Creole = {
|
||||
|
||||
'function-bold' : {
|
||||
search: /([^\n]+)([\n]*)/gi,
|
||||
replace: "**$1**$2"
|
||||
},
|
||||
|
||||
'function-italic' : {
|
||||
search: /([^\n]+)([\n]*)/gi,
|
||||
replace: "//$1//$2"
|
||||
},
|
||||
|
||||
'function-code' : {
|
||||
search: /([^\n]+)([\n]*)/gi,
|
||||
replace: "{{{$1}}}$2"
|
||||
},
|
||||
|
||||
'function-hr' : {
|
||||
append: "\n\n----\n\n"
|
||||
},
|
||||
|
||||
'function-ul' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
/* This looks silly but is completely valid Markdown */
|
||||
'function-ol' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "# $1$2"
|
||||
},
|
||||
|
||||
'function-link' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
$.GollumEditor.Dialog.init({
|
||||
title: 'Insert Link',
|
||||
fields: [
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
help: 'The text to display to the user.',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
name: 'URL',
|
||||
type: 'text',
|
||||
help: 'The URL to link to.'
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var h = '[[' + res['href'] + '|' +
|
||||
res['text'] + ']]';
|
||||
$.GollumEditor.replaceSelection( h );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
'function-image' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
$.GollumEditor.Dialog.init({
|
||||
title: 'Insert Image',
|
||||
fields: [
|
||||
{
|
||||
id: 'url',
|
||||
name: 'Image URL',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
id: 'alt',
|
||||
name: 'Alt Text',
|
||||
type: 'text'
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var h = '';
|
||||
if ( res['url'] && res['alt'] ) {
|
||||
h = '{{' + res['url'];
|
||||
if ( res['alt'] != '' ) {
|
||||
h += '|' + res['alt'] + '}}';
|
||||
}
|
||||
}
|
||||
$.GollumEditor.replaceSelection( h );
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.GollumEditor.defineLanguage('creole', Creole);
|
||||
|
||||
})(jQuery);
|
||||
@@ -1,223 +0,0 @@
|
||||
/**
|
||||
* Markdown Language Definition
|
||||
*
|
||||
* A language definition for string manipulation operations, in this case
|
||||
* for the Markdown, uh, markup language. Uses regexes for various functions
|
||||
* by default. If regexes won't do and you need to do some serious
|
||||
* manipulation, you can declare a function in the object instead.
|
||||
*
|
||||
* Code example:
|
||||
* 'functionbar-id' : {
|
||||
* exec: function(text, selectedText) {
|
||||
* functionStuffHere();
|
||||
* },
|
||||
* search: /somesearchregex/gi,
|
||||
* replace: 'replace text for RegExp.replace',
|
||||
* append: "just add this where the cursor is"
|
||||
* }
|
||||
*
|
||||
**/
|
||||
(function($) {
|
||||
|
||||
var MarkDown = {
|
||||
|
||||
'function-bold' : {
|
||||
search: /([^\n]+)([\n\s]*)/g,
|
||||
replace: "**$1**$2"
|
||||
},
|
||||
|
||||
'function-italic' : {
|
||||
search: /([^\n]+)([\n\s]*)/g,
|
||||
replace: "_$1_$2"
|
||||
},
|
||||
|
||||
'function-code' : {
|
||||
search: /([^\n]+)([\n\s]*)/g,
|
||||
replace: "`$1`$2"
|
||||
},
|
||||
|
||||
'function-hr' : {
|
||||
append: "\n***\n"
|
||||
},
|
||||
|
||||
'function-ul' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
/* based on rdoc.js */
|
||||
'function-ol' : {
|
||||
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' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "> $1$2"
|
||||
},
|
||||
|
||||
'function-h1' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "# $1$2"
|
||||
},
|
||||
|
||||
'function-h2' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "## $1$2"
|
||||
},
|
||||
|
||||
'function-h3' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "### $1$2"
|
||||
},
|
||||
|
||||
'function-link' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
$.GollumEditor.Dialog.init({
|
||||
title: 'Insert Link',
|
||||
fields: [
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
name: 'URL',
|
||||
type: 'text'
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var rep = '';
|
||||
if ( res['text'] && res['href'] ) {
|
||||
rep = '[' + res['text'] + '](' +
|
||||
res['href'] + ')';
|
||||
}
|
||||
$.GollumEditor.replaceSelection( rep );
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
'function-image' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
$.GollumEditor.Dialog.init({
|
||||
title: 'Insert Image',
|
||||
fields: [
|
||||
{
|
||||
id: 'url',
|
||||
name: 'Image URL',
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
id: 'alt',
|
||||
name: 'Alt Text',
|
||||
type: 'text'
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var rep = '';
|
||||
if ( res['url'] && res['alt'] ) {
|
||||
rep = '![' + res['alt'] + ']' +
|
||||
'(' + res['url'] + ')';
|
||||
}
|
||||
$.GollumEditor.replaceSelection( rep );
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var MarkDownHelp = [
|
||||
|
||||
{
|
||||
menuName: 'Block Elements',
|
||||
content: [
|
||||
{
|
||||
menuName: 'Paragraphs & Breaks',
|
||||
data: '<p>To create a paragraph, simply create a block of text that is not separated by one or more blank lines. Blocks of text separated by one or more blank lines will be parsed as paragraphs.</p><p>If you want to create a line break, end a line with two or more spaces, then hit Return/Enter.</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Headers',
|
||||
data: '<p>Markdown supports two header formats. The wiki editor uses the “atx’-style headers. Simply prefix your header text with the number of <code>#</code> characters to specify heading depth. For example: <code># Header 1</code>, <code>## Header 2</code> and <code>### Header 3</code> will be progressively smaller headers. You may end your headers with any number of hashes.</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Blockquotes',
|
||||
data: '<p>Markdown creates blockquotes email-style by prefixing each line with the <code>></code>. This looks best if you decide to hard-wrap text and prefix each line with a <code>></code> character, but Markdown supports just putting <code>></code> before your paragraph.</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Lists',
|
||||
data: '<p>Markdown supports both ordered and unordered lists. To create an ordered list, simply prefix each line with a number (any number will do — this is why the editor only uses one number.) To create an unordered list, you can prefix each line with <code>*</code>, <code>+</code> or <code>-</code>.</p> List items can contain multiple paragraphs, however each paragraph must be indented by at least 4 spaces or a tab.'
|
||||
},
|
||||
{
|
||||
menuName: 'Code Blocks',
|
||||
data: '<p>Markdown wraps code blocks in pre-formatted tags to preserve indentation in your code blocks. To create a code block, indent the entire block by at least 4 spaces or one tab. Markdown will strip the extra indentation you’ve added to the code block.</p>'
|
||||
},
|
||||
{
|
||||
menuName: 'Horizontal Rules',
|
||||
data: 'Horizontal rules are created by placing three or more hyphens, asterisks or underscores on a line by themselves. Spaces are allowed between the hyphens, asterisks or underscores.'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
menuName: 'Span Elements',
|
||||
content: [
|
||||
{
|
||||
menuName: 'Links',
|
||||
data: '<p>Markdown has two types of links: <strong>inline</strong> and <strong>reference</strong>. For both types of links, the text you want to display to the user is placed in square brackets. For example, if you want your link to display the text “GitHub”, you write <code>[GitHub]</code>.</p><p>To create an inline link, create a set of parentheses immediately after the brackets and write your URL within the parentheses. (e.g., <code>[GitHub](http://github.com/)</code>). Relative paths are allowed in inline links.</p><p>To create a reference link, use two sets of square brackets. <code>[my internal link][internal-ref]</code> will link to the internal reference <code>internal-ref</code>.</p>'
|
||||
},
|
||||
|
||||
{
|
||||
menuName: 'Emphasis',
|
||||
data: '<p>Asterisks (<code>*</code>) and underscores (<code>_</code>) are treated as emphasis and are wrapped with an <code><em></code> tag, which usually displays as italics in most browsers. Double asterisks (<code>**</code>) or double underscores (<code>__</code>) are treated as bold using the <code><strong></code> tag. To create italic or bold text, simply wrap your words in single/double asterisks/underscores. For example, <code>**My double emphasis text**</code> becomes <strong>My double emphasis text</strong>, and <code>*My single emphasis text*</code> becomes <em>My single emphasis text</em>.</p>'
|
||||
},
|
||||
|
||||
{
|
||||
menuName: 'Code',
|
||||
data: '<p>To create inline spans of code, simply wrap the code in backticks (<code>`</code>). Markdown will turn <code>`myFunction`</code> into <code>myFunction</code>.</p>'
|
||||
},
|
||||
|
||||
{
|
||||
menuName: 'Images',
|
||||
data: '<p>Markdown image syntax looks a lot like the syntax for links; it is essentially the same syntax preceded by an exclamation point (<code>!</code>). For example, if you want to link to an image at <code>http://github.com/unicorn.png</code> with the alternate text <code>My Unicorn</code>, you would write <code></code>.</p>'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
menuName: 'Miscellaneous',
|
||||
content: [
|
||||
{
|
||||
menuName: 'Automatic Links',
|
||||
data: '<p>If you want to create a link that displays the actual URL, markdown allows you to quickly wrap the URL in <code><</code> and <code>></code> to do so. For example, the link <a href="javascript:void(0);">http://github.com/</a> is easily produced by writing <code><http://github.com/></code>.</p>'
|
||||
},
|
||||
|
||||
{
|
||||
menuName: 'Escaping',
|
||||
data: '<p>If you want to use a special Markdown character in your document (such as displaying literal asterisks), you can escape the character with the backslash (<code>\\</code>). Markdown will ignore the character directly after a backslash.'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
$.GollumEditor.defineLanguage('markdown', MarkDown);
|
||||
$.GollumEditor.defineHelp('markdown', MarkDownHelp);
|
||||
|
||||
})(jQuery);
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* Markdown Language Definition
|
||||
*
|
||||
* A language definition for string manipulation operations, in this case
|
||||
* for the Markdown, uh, markup language. Uses regexes for various functions
|
||||
* by default. If regexes won't do and you need to do some serious
|
||||
* manipulation, you can declare a function in the object instead.
|
||||
*
|
||||
* Code example:
|
||||
* 'functionbar-id' : {
|
||||
* exec: function(text, selectedText) {
|
||||
* functionStuffHere();
|
||||
* },
|
||||
* search: /somesearchregex/gi,
|
||||
* replace: 'replace text for RegExp.replace',
|
||||
* append: "just add this where the cursor is"
|
||||
* }
|
||||
*
|
||||
**/
|
||||
(function($) {
|
||||
|
||||
var RDoc = {
|
||||
|
||||
'function-bold' : {
|
||||
search: /([^\n]+)([\n\s]*)/g,
|
||||
replace: "((*$1*))$2"
|
||||
},
|
||||
'function-code' : {
|
||||
search: /([^\n]+)([\n\s]*)/g,
|
||||
replace: "(({$1}))$2"
|
||||
},
|
||||
|
||||
'function-ul' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
'function-ol' : {
|
||||
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];
|
||||
}
|
||||
}
|
||||
$.GollumEditor.replaceSelection( repText );
|
||||
}
|
||||
},
|
||||
|
||||
'function-h1' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "= $1$2"
|
||||
},
|
||||
|
||||
'function-h2' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "== $1$2"
|
||||
},
|
||||
|
||||
'function-h3' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "=== $1$2"
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.GollumEditor.defineLanguage('rdoc', RDoc);
|
||||
|
||||
})(jQuery);
|
||||
@@ -1,248 +0,0 @@
|
||||
// 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,
|
||||
|
||||
selectNodeRange: function( n1, n2 ) {
|
||||
if ( nodeSelector.node1 && nodeSelector.node2 ) {
|
||||
$('#wiki-history td.selected').removeClass('selected');
|
||||
nodeSelector.node1.addClass('selected');
|
||||
nodeSelector.node2.addClass('selected');
|
||||
|
||||
// swap the nodes around if they went in reverse
|
||||
if ( nodeSelector.nodeComesAfter( nodeSelector.node1,
|
||||
nodeSelector.node2 ) ) {
|
||||
var n = nodeSelector.node1;
|
||||
nodeSelector.node1 = nodeSelector.node2;
|
||||
nodeSelector.node2 = n;
|
||||
}
|
||||
|
||||
var s = true;
|
||||
var $nextNode = nodeSelector.node1.next();
|
||||
while ( $nextNode ) {
|
||||
$nextNode.addClass('selected');
|
||||
if ( $nextNode[0] == nodeSelector.node2[0] ) {
|
||||
break;
|
||||
}
|
||||
$nextNode = $nextNode.next();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
nodeComesAfter: function ( n1, n2 ) {
|
||||
var s = false;
|
||||
$(n1).prevAll().each(function() {
|
||||
if ( $(this)[0] == $(n2)[0] ) {
|
||||
s = true;
|
||||
}
|
||||
});
|
||||
return s;
|
||||
},
|
||||
|
||||
checkNode: function( nodeCheckbox ) {
|
||||
var $nodeCheckbox = nodeCheckbox;
|
||||
var $node = $(nodeCheckbox).parent().parent();
|
||||
// if we're unchecking
|
||||
if ( !$nodeCheckbox.is(':checked') ) {
|
||||
|
||||
// remove the range, since we're breaking it
|
||||
$('#wiki-history tr.selected').each(function() {
|
||||
if ( $(this).find('td.checkbox input').is(':checked') ) {
|
||||
return;
|
||||
}
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
|
||||
// no longer track this
|
||||
if ( $node[0] == nodeSelector.node1[0] ) {
|
||||
nodeSelector.node1 = null;
|
||||
if ( nodeSelector.node2 ) {
|
||||
nodeSelector.node1 = nodeSelector.node2;
|
||||
nodeSelector.node2 = null;
|
||||
}
|
||||
} else if ( $node[0] == nodeSelector.node2[0] ) {
|
||||
nodeSelector.node2 = null;
|
||||
}
|
||||
|
||||
} else {
|
||||
if ( !nodeSelector.node1 ) {
|
||||
nodeSelector.node1 = $node;
|
||||
nodeSelector.node1.addClass('selected');
|
||||
} else if ( !nodeSelector.node2 ) {
|
||||
// okay, we don't have a node 2 but have a node1
|
||||
nodeSelector.node2 = $node;
|
||||
nodeSelector.node2.addClass('selected');
|
||||
nodeSelector.selectNodeRange( nodeSelector.node1,
|
||||
nodeSelector.node2 );
|
||||
} else {
|
||||
// we have two selected already
|
||||
$nodeCheckbox[0].checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ua detection
|
||||
if ($.browser.mozilla) {
|
||||
$('body').addClass('ff');
|
||||
} else if ($.browser.webkit) {
|
||||
$('body').addClass('webkit');
|
||||
} else if ($.browser.msie) {
|
||||
$('body').addClass('ie');
|
||||
if ($.browser.version == "7.0") {
|
||||
$('body').addClass('ie7');
|
||||
} else if ($.browser.version == "8.0") {
|
||||
$('body').addClass('ie8');
|
||||
}
|
||||
}
|
||||
|
||||
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',
|
||||
defaultValue: ''
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var name = 'New Page';
|
||||
if ( res['name'] ) {
|
||||
name = res['name'];
|
||||
}
|
||||
window.location = baseUrl + '/' + encodeURIComponent(name);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ($('#wiki-wrapper').hasClass('history')) {
|
||||
$('#wiki-history td.checkbox input').each(function() {
|
||||
$(this).click(function() {
|
||||
nodeSelector.checkNode($(this));
|
||||
});
|
||||
if ( $(this).is(':checked') ) {
|
||||
nodeSelector.checkNode($(this));
|
||||
}
|
||||
});
|
||||
|
||||
if ($('.history a.action-compare-revision').length) {
|
||||
$('.history a.action-compare-revision').click(function() {
|
||||
$("#version-form").submit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ($('#searchbar a#search-submit').length) {
|
||||
$.GollumPlaceholder.add($('#searchbar #search-query'));
|
||||
$('#searchbar a#search-submit').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('#searchbar #search-form')[0].submit();
|
||||
});
|
||||
$('#searchbar #search-form').submit(function(e) {
|
||||
$.GollumPlaceholder.clearAll();
|
||||
$(this).unbind('submit');
|
||||
$(this).submit();
|
||||
});
|
||||
}
|
||||
|
||||
if ($('#gollum-revert-form').length &&
|
||||
$('.gollum-revert-button').length ) {
|
||||
$('a.gollum-revert-button').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('#gollum-revert-form').submit();
|
||||
});
|
||||
}
|
||||
|
||||
if( $('#wiki-wrapper.edit').length ){
|
||||
$("#gollum-editor-submit").click( function() { window.onbeforeunload = null; } );
|
||||
$("#gollum-editor-body").one('change', function(){
|
||||
window.onbeforeunload = function(){ return "Leaving will discard all edits!" };
|
||||
});
|
||||
$.GollumEditor();
|
||||
}
|
||||
|
||||
if( $('#wiki-wrapper.create').length ){
|
||||
$("#gollum-editor-submit").click( function() { window.onbeforeunload = null; } );
|
||||
$("#gollum-editor-body").one('change', function(){
|
||||
window.onbeforeunload = function(){ return "Leaving will not create a new page!" };
|
||||
});
|
||||
$.GollumEditor({ NewFile: true, MarkupType: default_markup });
|
||||
}
|
||||
|
||||
if( $('#wiki-history').length ){
|
||||
var lookup = {};
|
||||
$('img.identicon').each(function(index, element){
|
||||
var $item = $(element);
|
||||
var code = parseInt($item.data('identicon'), 10);
|
||||
var img_bin = lookup[code];
|
||||
if( img_bin === undefined ){
|
||||
var size = 16;
|
||||
var canvas = $('<canvas width=16 height=16/>').get(0);
|
||||
render_identicon(canvas, code, 16);
|
||||
img_bin = canvas.toDataURL("image/png");
|
||||
lookup[code] = img_bin;
|
||||
}
|
||||
$item.attr('src', img_bin);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
Client-side Canvas tag based Identicon rendering code
|
||||
|
||||
@author Don Park
|
||||
@version 0.2
|
||||
@date January 21th, 2007
|
||||
*/
|
||||
|
||||
var patch0 = new Array( 0, 4, 24, 20 );
|
||||
var patch1 = new Array( 0, 4, 20 );
|
||||
var patch2 = new Array( 2, 24, 20 );
|
||||
var patch3 = new Array( 0, 2, 20, 22 );
|
||||
var patch4 = new Array( 2, 14, 22, 10 );
|
||||
var patch5 = new Array( 0, 14, 24, 22 );
|
||||
var patch6 = new Array( 2, 24, 22, 13, 11, 22, 20 );
|
||||
var patch7 = new Array( 0, 14, 22 );
|
||||
var patch8 = new Array( 6, 8, 18, 16 );
|
||||
var patch9 = new Array( 4, 20, 10, 12, 2 );
|
||||
var patch10 = new Array( 0, 2, 12, 10 );
|
||||
var patch11 = new Array( 10, 14, 22 );
|
||||
var patch12 = new Array( 20, 12, 24 );
|
||||
var patch13 = new Array( 10, 2, 12 );
|
||||
var patch14 = new Array( 0, 2, 10 );
|
||||
var patchTypes = new Array( patch0, patch1, patch2, patch3, patch4,
|
||||
patch5, patch6, patch7, patch8, patch9, patch10, patch11,
|
||||
patch12, patch13, patch14, patch0 );
|
||||
var centerPatchTypes = new Array(0, 4, 8, 15);
|
||||
|
||||
function render_identicon_patch(ctx, x, y, size, patch, turn, invert, foreColor, backColor) {
|
||||
patch %= patchTypes.length;
|
||||
turn %= 4;
|
||||
if (patch == 15)
|
||||
invert = !invert;
|
||||
|
||||
var vertices = patchTypes[patch];
|
||||
var offset = size / 2;
|
||||
var scale = size / 4;
|
||||
|
||||
ctx.save();
|
||||
|
||||
// paint background
|
||||
ctx.fillStyle = invert ? foreColor : backColor;
|
||||
ctx.fillRect(x, y, size, size);
|
||||
|
||||
// build patch path
|
||||
ctx.translate(x + offset, y + offset);
|
||||
ctx.rotate(turn * Math.PI / 2);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo((vertices[0] % 5 * scale - offset), (Math.floor(vertices[0] / 5) * scale - offset));
|
||||
for (var i = 1; i < vertices.length; i++)
|
||||
ctx.lineTo((vertices[i] % 5 * scale - offset), (Math.floor(vertices[i] / 5) * scale - offset));
|
||||
ctx.closePath();
|
||||
|
||||
// offset and rotate coordinate space by patch position (x, y) and
|
||||
// 'turn' before rendering patch shape
|
||||
|
||||
// render rotated patch using fore color (back color if inverted)
|
||||
ctx.fillStyle = invert ? backColor : foreColor;
|
||||
ctx.fill();
|
||||
|
||||
// restore rotation
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function render_identicon(node, code, size) {
|
||||
if (!node || !code || !size) return;
|
||||
|
||||
var patchSize = size / 3;
|
||||
var middleType = centerPatchTypes[code & 3];
|
||||
var middleInvert = ((code >> 2) & 1) != 0;
|
||||
var cornerType = (code >> 3) & 15;
|
||||
var cornerInvert = ((code >> 7) & 1) != 0;
|
||||
var cornerTurn = (code >> 8) & 3;
|
||||
var sideType = (code >> 10) & 15;
|
||||
var sideInvert = ((code >> 14) & 1) != 0;
|
||||
var sideTurn = (code >> 15) & 3;
|
||||
var blue = (code >> 16) & 31;
|
||||
var green = (code >> 21) & 31;
|
||||
var red = (code >> 27) & 31;
|
||||
var foreColor = "rgb(" + (red << 3) + "," + (green << 3) + "," + (blue << 3) + ")";
|
||||
var backColor = "rgb(255,255,255)";
|
||||
|
||||
var ctx = node.getContext("2d");
|
||||
|
||||
// middle patch
|
||||
render_identicon_patch(ctx, patchSize, patchSize, patchSize, middleType, 0, middleInvert, foreColor, backColor);
|
||||
// side patchs, starting from top and moving clock-wise
|
||||
render_identicon_patch(ctx, patchSize, 0, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
|
||||
render_identicon_patch(ctx, patchSize * 2, patchSize, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
|
||||
render_identicon_patch(ctx, patchSize, patchSize * 2, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
|
||||
render_identicon_patch(ctx, 0, patchSize, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
|
||||
// corner patchs, starting from top left and moving clock-wise
|
||||
render_identicon_patch(ctx, 0, 0, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
|
||||
render_identicon_patch(ctx, patchSize * 2, 0, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
|
||||
render_identicon_patch(ctx, patchSize * 2, patchSize * 2, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
|
||||
render_identicon_patch(ctx, 0, patchSize * 2, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
|
||||
}
|
||||
|
||||
function render_identicon_canvases(prefix) {
|
||||
var canvases = document.getElementsByTagName("canvas");
|
||||
var n = canvases.length;
|
||||
for (var i = 0; i < n; i++) {
|
||||
var node = canvases[i];
|
||||
if (node.title && node.title.indexOf(prefix) == 0) {
|
||||
if (node.style.display == 'none') node.style.display = "inline";
|
||||
var code = node.title.substring(prefix.length) * 1;
|
||||
var size = node.width;
|
||||
render_identicon(node, code, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* jQuery Color Animations
|
||||
* Copyright 2007 John Resig
|
||||
* Released under the MIT and GPL licenses.
|
||||
*/
|
||||
|
||||
(function(jQuery){
|
||||
|
||||
// We override the animation for all of these color styles
|
||||
jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
|
||||
jQuery.fx.step[attr] = function(fx){
|
||||
if ( fx.state == 0 ) {
|
||||
fx.start = getColor( fx.elem, attr );
|
||||
fx.end = getRGB( fx.end );
|
||||
}
|
||||
|
||||
fx.elem.style[attr] = "rgb(" + [
|
||||
Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
|
||||
Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
|
||||
Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
|
||||
].join(",") + ")";
|
||||
}
|
||||
});
|
||||
|
||||
// Color Conversion functions from highlightFade
|
||||
// By Blair Mitchelmore
|
||||
// http://jquery.offput.ca/highlightFade/
|
||||
|
||||
// Parse strings looking for color tuples [255,255,255]
|
||||
function getRGB(color) {
|
||||
var result;
|
||||
|
||||
// Check if we're already dealing with an array of colors
|
||||
if ( color && color.constructor == Array && color.length == 3 )
|
||||
return color;
|
||||
|
||||
// Look for rgb(num,num,num)
|
||||
if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
|
||||
return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];
|
||||
|
||||
// Look for rgb(num%,num%,num%)
|
||||
if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
|
||||
return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];
|
||||
|
||||
// Look for #a0b1c2
|
||||
if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
|
||||
return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];
|
||||
|
||||
// Look for #fff
|
||||
if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
|
||||
return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];
|
||||
|
||||
// Otherwise, we're most likely dealing with a named color
|
||||
return colors[jQuery.trim(color).toLowerCase()];
|
||||
}
|
||||
|
||||
function getColor(elem, attr) {
|
||||
var color;
|
||||
|
||||
do {
|
||||
color = jQuery.curCSS(elem, attr);
|
||||
|
||||
// Keep going until we find an element that has color, or we hit the body
|
||||
if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
|
||||
break;
|
||||
|
||||
attr = "backgroundColor";
|
||||
} while ( elem = elem.parentNode );
|
||||
|
||||
return getRGB(color);
|
||||
};
|
||||
|
||||
// Some named colors to work with
|
||||
// From Interface by Stefan Petre
|
||||
// http://interface.eyecon.ro/
|
||||
|
||||
var colors = {
|
||||
aqua:[0,255,255],
|
||||
azure:[240,255,255],
|
||||
beige:[245,245,220],
|
||||
black:[0,0,0],
|
||||
blue:[0,0,255],
|
||||
brown:[165,42,42],
|
||||
cyan:[0,255,255],
|
||||
darkblue:[0,0,139],
|
||||
darkcyan:[0,139,139],
|
||||
darkgrey:[169,169,169],
|
||||
darkgreen:[0,100,0],
|
||||
darkkhaki:[189,183,107],
|
||||
darkmagenta:[139,0,139],
|
||||
darkolivegreen:[85,107,47],
|
||||
darkorange:[255,140,0],
|
||||
darkorchid:[153,50,204],
|
||||
darkred:[139,0,0],
|
||||
darksalmon:[233,150,122],
|
||||
darkviolet:[148,0,211],
|
||||
fuchsia:[255,0,255],
|
||||
gold:[255,215,0],
|
||||
green:[0,128,0],
|
||||
indigo:[75,0,130],
|
||||
khaki:[240,230,140],
|
||||
lightblue:[173,216,230],
|
||||
lightcyan:[224,255,255],
|
||||
lightgreen:[144,238,144],
|
||||
lightgrey:[211,211,211],
|
||||
lightpink:[255,182,193],
|
||||
lightyellow:[255,255,224],
|
||||
lime:[0,255,0],
|
||||
magenta:[255,0,255],
|
||||
maroon:[128,0,0],
|
||||
navy:[0,0,128],
|
||||
olive:[128,128,0],
|
||||
orange:[255,165,0],
|
||||
pink:[255,192,203],
|
||||
purple:[128,0,128],
|
||||
violet:[128,0,128],
|
||||
red:[255,0,0],
|
||||
silver:[192,192,192],
|
||||
white:[255,255,255],
|
||||
yellow:[255,255,0]
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -1,8 +0,0 @@
|
||||
/* 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={}}}}();
|
||||
@@ -1,132 +0,0 @@
|
||||
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 -- */
|
||||
|
Before Width: | Height: | Size: 525 B |
|
Before Width: | Height: | Size: 630 B |
|
Before Width: | Height: | Size: 919 B |
|
Before Width: | Height: | Size: 235 B |
|
Before Width: | Height: | Size: 278 B |
@@ -1,44 +0,0 @@
|
||||
<!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='preview' class='edit'><img src='images/globe_24.png' alt='Preview' title='Preview'></a>
|
||||
<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>
|
||||
@@ -1,107 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* The main class required to set up an Ace instance in the browser.
|
||||
*
|
||||
* @class Ace
|
||||
**/
|
||||
|
||||
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("./placeholder");
|
||||
require("./mode/folding/fold_mode");
|
||||
exports.config = require("./config");
|
||||
|
||||
/**
|
||||
* Provides access to require in packed noconflict mode
|
||||
* @param {String} moduleName
|
||||
* @returns {Object}
|
||||
*
|
||||
**/
|
||||
exports.require = require;
|
||||
|
||||
/**
|
||||
* Embeds the Ace editor into the DOM, at the element provided by `el`.
|
||||
* @param {String | DOMElement} el Either the id of an element, or the element itself
|
||||
*
|
||||
**/
|
||||
exports.edit = function(el) {
|
||||
if (typeof(el) == "string") {
|
||||
var _id = el;
|
||||
var el = document.getElementById(_id);
|
||||
if (!el)
|
||||
throw "ace.edit can't find div #" + _id;
|
||||
}
|
||||
|
||||
if (el.env && el.env.editor instanceof Editor)
|
||||
return el.env.editor;
|
||||
|
||||
var doc = exports.createEditSession(dom.getInnerText(el));
|
||||
el.innerHTML = '';
|
||||
|
||||
var editor = new Editor(new Renderer(el));
|
||||
new MultiSelect(editor);
|
||||
editor.setSession(doc);
|
||||
|
||||
var env = {
|
||||
document: doc,
|
||||
editor: editor,
|
||||
onResize: editor.resize.bind(editor)
|
||||
};
|
||||
event.addListener(window, "resize", env.onResize);
|
||||
el.env = editor.env = env;
|
||||
return editor;
|
||||
};
|
||||
|
||||
|
||||
exports.createEditSession = function(text, mode) {
|
||||
var doc = new EditSession(text, doc);
|
||||
doc.setUndoManager(new UndoManager());
|
||||
return doc;
|
||||
}
|
||||
exports.EditSession = EditSession;
|
||||
exports.UndoManager = UndoManager;
|
||||
});
|
||||
@@ -1,248 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
|
||||
/**
|
||||
*
|
||||
* Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated.
|
||||
*
|
||||
* @class Anchor
|
||||
**/
|
||||
|
||||
/**
|
||||
* Creates a new `Anchor` and associates it with a document.
|
||||
*
|
||||
* @param {Document} doc The document to associate with the anchor
|
||||
* @param {Number} row The starting row position
|
||||
* @param {Number} column The starting column position
|
||||
*
|
||||
* @constructor
|
||||
**/
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Returns an object identifying the `row` and `column` position of the current anchor.
|
||||
* @returns {Object}
|
||||
**/
|
||||
|
||||
this.getPosition = function() {
|
||||
return this.$clipPositionToDocument(this.row, this.column);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns the current document.
|
||||
* @returns {Document}
|
||||
**/
|
||||
|
||||
this.getDocument = function() {
|
||||
return this.document;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fires whenever the anchor position changes.
|
||||
*
|
||||
* Both of these objects have a `row` and `column` property corresponding to the position.
|
||||
*
|
||||
* Events that can trigger this function include [[Anchor.setPosition `setPosition()`]].
|
||||
*
|
||||
* @event change
|
||||
* @param {Object} e An object containing information about the anchor position. It has two properties:
|
||||
* - `old`: An object describing the old Anchor position
|
||||
* - `value`: An object describing the new Anchor position
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
this.onChange = function(e) {
|
||||
var delta = e.data;
|
||||
var range = delta.range;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped.
|
||||
* @param {Number} row The row index to move the anchor to
|
||||
* @param {Number} column The column index to move the anchor to
|
||||
* @param {Boolean} noClip Identifies if you want the position to be clipped
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
this.setPosition = function(row, column, noClip) {
|
||||
var pos;
|
||||
if (noClip) {
|
||||
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
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* When called, the `'change'` event listener is removed.
|
||||
*
|
||||
**/
|
||||
|
||||
this.detach = function() {
|
||||
this.document.removeEventListener("change", this.$onChange);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clips the anchor position to the specified row and column.
|
||||
* @param {Number} row The row index to clip the anchor to
|
||||
* @param {Number} column The column index to clip the anchor to
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.$clipPositionToDocument = function(row, column) {
|
||||
var pos = {};
|
||||
|
||||
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);
|
||||
|
||||
});
|
||||
@@ -1,177 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
|
||||
// tokenizing lines longer than this makes editor very slow
|
||||
var MAX_LINE_LENGTH = 5000;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use.
|
||||
*
|
||||
* If a certain row is changed, everything below that row is re-tokenized.
|
||||
*
|
||||
* @class BackgroundTokenizer
|
||||
**/
|
||||
|
||||
/**
|
||||
* Creates a new `BackgroundTokenizer` object.
|
||||
* @param {Tokenizer} tokenizer The tokenizer to use
|
||||
* @param {Editor} editor The editor to associate with
|
||||
*
|
||||
*
|
||||
*
|
||||
* @constructor
|
||||
**/
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Sets a new tokenizer for this object.
|
||||
*
|
||||
* @param {Tokenizer} tokenizer The new tokenizer to use
|
||||
*
|
||||
**/
|
||||
this.setTokenizer = function(tokenizer) {
|
||||
this.tokenizer = tokenizer;
|
||||
this.lines = [];
|
||||
this.states = [];
|
||||
|
||||
this.start(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a new document to associate with this object.
|
||||
* @param {Document} doc The new document to associate with
|
||||
**/
|
||||
this.setDocument = function(doc) {
|
||||
this.doc = doc;
|
||||
this.lines = [];
|
||||
this.states = [];
|
||||
|
||||
this.stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Fires whenever the background tokeniziers between a range of rows are going to be updated.
|
||||
*
|
||||
* @event update
|
||||
* @param {Object} e An object containing two properties, `first` and `last`, which indicate the rows of the region being updated.
|
||||
*
|
||||
**/
|
||||
/**
|
||||
* Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated.
|
||||
* @param {Number} firstRow The starting row region
|
||||
* @param {Number} lastRow The final row region
|
||||
*
|
||||
**/
|
||||
this.fireUpdateEvent = function(firstRow, lastRow) {
|
||||
var data = {
|
||||
first: firstRow,
|
||||
last: lastRow
|
||||
};
|
||||
this._emit("update", {data: data});
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts tokenizing at the row indicated.
|
||||
*
|
||||
* @param {Number} startRow The row to start at
|
||||
*
|
||||
**/
|
||||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stops tokenizing.
|
||||
*
|
||||
**/
|
||||
this.stop = function() {
|
||||
if (this.running)
|
||||
clearTimeout(this.running);
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gives list of tokens of the row. (tokens are cached)
|
||||
*
|
||||
* @param {Number} row The row to get tokens at
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getTokens = function(row) {
|
||||
return this.lines[row] || this.$tokenizeRow(row);
|
||||
};
|
||||
|
||||
/**
|
||||
* [Returns the state of tokenization at the end of a row.]{: #BackgroundTokenizer.getState}
|
||||
*
|
||||
* @param {Number} row The row to get state at
|
||||
**/
|
||||
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;
|
||||
});
|
||||
@@ -1,85 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
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)
|
||||
* @param {String} platform Identifier for the platform; must be either `'mac'` or `'win'`
|
||||
* @param {Array} commands A list of commands
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
var CommandManager = function(platform, commands) {
|
||||
this.platform = platform;
|
||||
this.commands = this.byName = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
this.addCommands(commands);
|
||||
|
||||
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(editor) {
|
||||
if (this.$inReplay)
|
||||
return;
|
||||
|
||||
editor && editor._emit("changeStatus");
|
||||
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(editor);
|
||||
|
||||
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;
|
||||
|
||||
});
|
||||
@@ -1,199 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
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(editor);
|
||||
},
|
||||
replay: function(editor) {
|
||||
editor.cm.replay();
|
||||
},
|
||||
cm1: function(editor, arg) {
|
||||
called += "1" + (arg || "");
|
||||
},
|
||||
cm2: function(editor) {
|
||||
called += "2";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var statusUpdateEmitted = false;
|
||||
this._emit = function() {statusUpdateEmitted = true};
|
||||
|
||||
this.cm.exec("togglerecording", this);
|
||||
assert.ok(this.cm.recording);
|
||||
assert.ok(statusUpdateEmitted);
|
||||
|
||||
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() {
|
||||
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);
|
||||
},
|
||||
|
||||
"test: binding keys without modifiers": function() {
|
||||
this.cm.bindKeys({
|
||||
"R": "cm1",
|
||||
"Shift-r": "cm2",
|
||||
"Return": "cm4",
|
||||
"Enter": "cm3"
|
||||
});
|
||||
|
||||
var command = this.cm.findKeyCommand(-1, "r");
|
||||
assert.equal(command, "cm1");
|
||||
|
||||
var command = this.cm.findKeyCommand(-1, "R");
|
||||
assert.equal(command, "cm2");
|
||||
|
||||
var command = this.cm.findKeyCommand(0, "return");
|
||||
assert.equal(command, "cm3");
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
@@ -1,467 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var 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(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotostart",
|
||||
bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"),
|
||||
exec: function(editor) { editor.navigateFileStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
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(editor); },
|
||||
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-Shift-P"),
|
||||
exec: function(editor) { editor.jumpToMatching(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttomatching",
|
||||
bindKey: bindKey("Ctrl-Shift-P", null),
|
||||
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: "sortlines",
|
||||
bindKey: bindKey("Ctrl-Alt-S", "Command-Alt-S"),
|
||||
exec: function(editor) { editor.sortLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "togglecomment",
|
||||
bindKey: bindKey("Ctrl-/", "Command-/"),
|
||||
exec: function(editor) { editor.toggleCommentLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "modifyNumberUp",
|
||||
bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"),
|
||||
exec: function(editor) { editor.modifyNumber(1); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "modifyNumberDown",
|
||||
bindKey: bindKey("Ctrl-Shift-Down", "Alt-Shift-Down"),
|
||||
exec: function(editor) { editor.modifyNumber(-1); },
|
||||
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"
|
||||
}];
|
||||
|
||||
});
|
||||
@@ -1,97 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
// 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-Alt-L", mac: "Ctrl-Alt-L"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "alignCursors",
|
||||
exec: function(editor) { editor.alignCursors(); },
|
||||
bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"}
|
||||
}];
|
||||
|
||||
// commands active only 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);
|
||||
|
||||
});
|
||||
@@ -1,139 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"no use strict";
|
||||
|
||||
var lang = require("./lib/lang");
|
||||
|
||||
var global = (function() {
|
||||
return this;
|
||||
})();
|
||||
|
||||
var options = {
|
||||
packaged: false,
|
||||
workerPath: null,
|
||||
modePath: null,
|
||||
themePath: null,
|
||||
basePath: "",
|
||||
suffix: ".js",
|
||||
$moduleUrls: {}
|
||||
};
|
||||
|
||||
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.moduleUrl = function(name, component) {
|
||||
if (options.$moduleUrls[name])
|
||||
return options.$moduleUrls[name];
|
||||
|
||||
var parts = name.split("/");
|
||||
component = component || parts[parts.length - 2] || "";
|
||||
var base = parts[parts.length - 1].replace(component, "").replace(/(^[\-_])|([\-_]$)/, "");
|
||||
|
||||
if (!base && parts.length > 1)
|
||||
base = parts[parts.length - 2];
|
||||
var path = options[component + "Path"];
|
||||
if (path == null)
|
||||
path = options.basePath;
|
||||
if (path && path.slice(-1) != "/")
|
||||
path += "/";
|
||||
return path + component + "-" + base + this.get("suffix");
|
||||
};
|
||||
|
||||
exports.setModuleUrl = function(name, subst) {
|
||||
return options.$moduleUrls[name] = subst;
|
||||
};
|
||||
|
||||
exports.init = function() {
|
||||
options.packaged = require.packaged || module.packaged || (global.define && define.packaged);
|
||||
|
||||
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(); });
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,71 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var config = require("./config");
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test path resolution" : function() {
|
||||
config.set("packaged", "true");
|
||||
var url = config.moduleUrl("kr_theme", "theme");
|
||||
assert.equal(url, "theme-kr.js");
|
||||
|
||||
config.set("basePath", "a/b");
|
||||
url = config.moduleUrl("m/theme", "theme");
|
||||
assert.equal(url, "a/b/theme-m.js");
|
||||
|
||||
url = config.moduleUrl("m/theme", "ext");
|
||||
assert.equal(url, "a/b/ext-theme.js");
|
||||
|
||||
config.set("workerPath", "c/");
|
||||
url = config.moduleUrl("foo/1", "worker");
|
||||
assert.equal(url, "c/worker-1.js");
|
||||
|
||||
config.setModuleUrl("foo/1", "a/b1.js");
|
||||
url = config.moduleUrl("foo/1", "theme");
|
||||
assert.equal(url, "a/b1.js");
|
||||
|
||||
assert.equal();
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
|
Before Width: | Height: | Size: 759 B |
@@ -1,368 +0,0 @@
|
||||
.ace_editor {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ace_scroller {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ace_content {
|
||||
position: absolute;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.ace_gutter {
|
||||
position: absolute;
|
||||
overflow : hidden;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.ace_gutter-active-line {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ace_scroller.ace_scroll-left {
|
||||
box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;
|
||||
}
|
||||
|
||||
.ace_gutter-cell {
|
||||
padding-left: 19px;
|
||||
padding-right: 6px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.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-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_scrollbar {
|
||||
position: absolute;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ace_scrollbar-inner {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ace_print-margin {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ace_text-input {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
width: 0.5em;
|
||||
height: 1em;
|
||||
opacity: 0;
|
||||
background: transparent;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: none;
|
||||
resize: none;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ace_text-input.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%;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
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-layer {
|
||||
position: relative;
|
||||
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;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ace_hidden-cursors .ace_cursor {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.ace_smooth-blinking .ace_cursor {
|
||||
-moz-transition: opacity 0.18s;
|
||||
-webkit-transition: opacity 0.18s;
|
||||
-o-transition: opacity 0.18s;
|
||||
-ms-transition: opacity 0.18s;
|
||||
transition: opacity 0.18s;
|
||||
}
|
||||
|
||||
.ace_cursor[style*="opacity: 0"]{
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
||||
}
|
||||
|
||||
.ace_editor.ace_multiselect .ace_cursor {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.ace_line {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_step {
|
||||
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;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ace_line .ace_fold {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
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_editor.ace_dragging .ace_content {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.ace_gutter-tooltip {
|
||||
background-color: #FFFFD5;
|
||||
border: 1px solid gray;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);
|
||||
color: black;
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
position: absolute;
|
||||
z-index: 300;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
white-space: pre-line;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.ace_folding-enabled > .ace_gutter-cell {
|
||||
padding-right: 13px;
|
||||
}
|
||||
|
||||
.ace_fold-widget {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
margin: 0 -12px 0 1px;
|
||||
display: inline-block;
|
||||
width: 11px;
|
||||
vertical-align: top;
|
||||
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAe%8A%B1%0D%000%0C%C2%F2%2CK%96%BC%D0%8F9%81%88H%E9%D0%0E%96%C0%10%92%3E%02%80%5E%82%E4%A9*-%EEsw%C8%CC%11%EE%96w%D8%DC%E9*Eh%0C%151(%00%00%00%00IEND%AEB%60%82");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.ace_fold-widget.ace_end {
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAm%C7%C1%09%000%08C%D1%8C%ECE%C8E(%8E%EC%02)%1EZJ%F1%C1'%04%07I%E1%E5%EE%CAL%F5%A2%99%99%22%E2%D6%1FU%B5%FE0%D9x%A7%26Wz5%0E%D5%00%00%00%00IEND%AEB%60%82");
|
||||
}
|
||||
|
||||
.ace_fold-widget.ace_closed {
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%03%00%00%00%06%08%06%00%00%00%06%E5%24%0C%00%00%009IDATx%DA5%CA%C1%09%000%08%03%C0%AC*(%3E%04%C1%0D%BA%B1%23%A4Uh%E0%20%81%C0%CC%F8%82%81%AA%A2%AArGfr%88%08%11%11%1C%DD%7D%E0%EE%5B%F6%F6%CB%B8%05Q%2F%E9tai%D9%00%00%00%00IEND%AEB%60%82");
|
||||
}
|
||||
|
||||
.ace_fold-widget:hover {
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.ace_fold-widget:active {
|
||||
border: 1px solid rgba(0, 0, 0, 0.4);
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
/**
|
||||
* 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.ace_end {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");
|
||||
}
|
||||
.ace_dark .ace_fold-widget.ace_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.ace_invalid {
|
||||
background-color: #FFB4B4;
|
||||
border-color: #DE5555;
|
||||
}
|
||||
|
||||
.ace_fade-fold-widgets .ace_fold-widget {
|
||||
-moz-transition: opacity 0.4s ease 0.05s;
|
||||
-webkit-transition: opacity 0.4s ease 0.05s;
|
||||
-o-transition: opacity 0.4s ease 0.05s;
|
||||
-ms-transition: opacity 0.4s ease 0.05s;
|
||||
transition: opacity 0.4s ease 0.05s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.ace_fade-fold-widgets:hover .ace_fold-widget {
|
||||
-moz-transition: opacity 0.05s ease 0.05s;
|
||||
-webkit-transition: opacity 0.05s ease 0.05s;
|
||||
-o-transition: opacity 0.05s ease 0.05s;
|
||||
-ms-transition: opacity 0.05s ease 0.05s;
|
||||
transition: opacity 0.05s ease 0.05s;
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
.ace_underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ace_bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ace_nobold .ace_bold {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.ace_italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 290 B |
@@ -1,598 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
var Range = require("./range").Range;
|
||||
var Anchor = require("./anchor").Anchor;
|
||||
|
||||
/**
|
||||
* Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s.
|
||||
*
|
||||
* At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index.
|
||||
*
|
||||
* @class Document
|
||||
**/
|
||||
|
||||
/**
|
||||
*
|
||||
* Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty.
|
||||
* @param {String | Array} text The starting text
|
||||
* @constructor
|
||||
**/
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Replaces all the lines in the current `Document` with the value of `text`.
|
||||
*
|
||||
* @param {String} text The text to use
|
||||
**/
|
||||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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());
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new `Anchor` to define a floating point in the document.
|
||||
* @param {Number} row The row number to use
|
||||
* @param {Number} column The column number to use
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.createAnchor = function(row, column) {
|
||||
return new Anchor(this, row, column);
|
||||
};
|
||||
|
||||
/**
|
||||
* Splits a string of text on any newline (`\n`) or carriage-return ('\r') characters.
|
||||
*
|
||||
* @method $split
|
||||
* @param {String} text The text to work with
|
||||
* @returns {String} A String array, with each index containing a piece of the original `text` string.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
// check for IE split bug
|
||||
if ("aaa".split(/a/).length == 0)
|
||||
this.$split = function(text) {
|
||||
return text.replace(/\r\n|\r/g, "\n").split("\n");
|
||||
}
|
||||
else
|
||||
this.$split = function(text) {
|
||||
return text.split(/\r\n|\r|\n/);
|
||||
};
|
||||
|
||||
|
||||
|
||||
this.$detectNewLine = function(text) {
|
||||
var match = text.match(/^.*?(\r\n|\r|\n)/m);
|
||||
if (match) {
|
||||
this.$autoNewLine = match[1];
|
||||
} else {
|
||||
this.$autoNewLine = "\n";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the newline character that's being used, depending on the value of `newLineMode`.
|
||||
* @returns {String} If `newLineMode == windows`, `\r\n` is returned.
|
||||
* If `newLineMode == unix`, `\n` is returned.
|
||||
* If `newLineMode == auto`, the value of `autoNewLine` is returned.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getNewLineCharacter = function() {
|
||||
switch (this.$newLineMode) {
|
||||
case "windows":
|
||||
return "\r\n";
|
||||
|
||||
case "unix":
|
||||
return "\n";
|
||||
|
||||
case "auto":
|
||||
return this.$autoNewLine;
|
||||
}
|
||||
};
|
||||
|
||||
this.$autoNewLine = "\n";
|
||||
this.$newLineMode = "auto";
|
||||
/**
|
||||
* [Sets the new line mode.]{: #Document.setNewLineMode.desc}
|
||||
* @param {String} newLineMode [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param}
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.setNewLineMode = function(newLineMode) {
|
||||
if (this.$newLineMode === newLineMode)
|
||||
return;
|
||||
|
||||
this.$newLineMode = newLineMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode}
|
||||
* @returns String
|
||||
**/
|
||||
this.getNewLineMode = function() {
|
||||
return this.$newLineMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`).
|
||||
* @param {String} text The text to check
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.isNewLine = function(text) {
|
||||
return (text == "\r\n" || text == "\r" || text == "\n");
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a verbatim copy of the given line as it is in the document
|
||||
* @param {Number} row The row index to retrieve
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getLine = function(row) {
|
||||
return this.$lines[row] || "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`.
|
||||
* @param {Number} firstRow The first row index to retrieve
|
||||
* @param {Number} lastRow The final row index to retrieve
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getLines = function(firstRow, lastRow) {
|
||||
return this.$lines.slice(firstRow, lastRow + 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all lines in the document as string array. Warning: The caller should not modify this array!
|
||||
**/
|
||||
this.getAllLines = function() {
|
||||
return this.getLines(0, this.getLength());
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the number of rows in the document.
|
||||
**/
|
||||
this.getLength = function() {
|
||||
return this.$lines.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc}
|
||||
* @param {Range} range The range to work with
|
||||
*
|
||||
*
|
||||
**/
|
||||
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());
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts a block of `text` and the indicated `position`.
|
||||
* @param {Object} position The position to start inserting at
|
||||
* @param {String} text A chunk of text to insert
|
||||
* @returns {Object} The position ({row, column}) of the last line of `text`. If the length of `text` is 0, this function simply returns `position`.
|
||||
*
|
||||
**/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fires whenever the document changes.
|
||||
*
|
||||
* Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available:
|
||||
*
|
||||
* * `"insertLines"` (emitted by [[Document.insertLines]])
|
||||
* * `range`: the [[Range]] of the change within the document
|
||||
* * `lines`: the lines in the document that are changing
|
||||
* * `"insertText"` (emitted by [[Document.insertNewLine]])
|
||||
* * `range`: the [[Range]] of the change within the document
|
||||
* * `text`: the text that's being added
|
||||
* * `"removeLines"` (emitted by [[Document.insertLines]])
|
||||
* * `range`: the [[Range]] of the change within the document
|
||||
* * `lines`: the lines in the document that were removed
|
||||
* * `nl`: the new line character (as defined by [[Document.getNewLineCharacter]])
|
||||
* * `"removeText"` (emitted by [[Document.removeInLine]] and [[Document.removeNewLine]])
|
||||
* * `range`: the [[Range]] of the change within the document
|
||||
* * `text`: the text that's being removed
|
||||
*
|
||||
* @event change
|
||||
* @param {Object} e Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties.
|
||||
*
|
||||
**/
|
||||
/**
|
||||
* Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event.
|
||||
* @param {Number} row The index of the row to insert at
|
||||
* @param {Array} lines An array of strings
|
||||
* @returns {Object} Contains the final row and column, like this:
|
||||
* ```
|
||||
* {row: endRow, column: 0}
|
||||
* ```
|
||||
* If `lines` is empty, this function returns an object containing the current row, and column, like this:
|
||||
* ```
|
||||
* {row: row, column: 0}
|
||||
* ```
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event.
|
||||
* @param {Object} position The position to insert at
|
||||
* @returns {Object} Returns an object containing the final row and column, like this:<br/>
|
||||
* ```
|
||||
* {row: endRow, column: 0}
|
||||
* ```
|
||||
*
|
||||
**/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event.
|
||||
* @param {Object} position The position to insert at
|
||||
* @param {String} text A chunk of text
|
||||
* @returns {Object} Returns an object containing the final row and column, like this:
|
||||
* ```
|
||||
* {row: endRow, column: 0}
|
||||
* ```
|
||||
*
|
||||
**/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the `range` from the document.
|
||||
* @param {Range} range A specified Range to remove
|
||||
* @returns {Object} Returns the new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.remove = function(range) {
|
||||
// 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the specified columns from the `row`. This method also triggers the `'change'` event.
|
||||
* @param {Number} row The row to remove from
|
||||
* @param {Number} startColumn The column to start removing at
|
||||
* @param {Number} endColumn The column to stop removing at
|
||||
* @returns {Object} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.<br/>If `startColumn` is equal to `endColumn`, this function returns nothing.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.removeInLine = function(row, startColumn, endColumn) {
|
||||
if (startColumn == endColumn)
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a range of full lines. This method also triggers the `'change'` event.
|
||||
* @param {Number} firstRow The first row to be removed
|
||||
* @param {Number} lastRow The last row to be removed
|
||||
* @returns {[String]} Returns all the removed lines.
|
||||
*
|
||||
*
|
||||
**/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the new line between `row` and the row immediately following it. This method also triggers the `'change'` event.
|
||||
* @param {Number} row The row to check
|
||||
*
|
||||
**/
|
||||
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 });
|
||||
};
|
||||
|
||||
/**
|
||||
* Replaces a range in the document with the new `text`.
|
||||
* @param {Range} range A specified Range to replace
|
||||
* @param {String} text The new text to use as a replacement
|
||||
* @returns {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.
|
||||
*
|
||||
*
|
||||
**/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
});
|
||||
@@ -1,306 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var TokenIterator = require("../token_iterator").TokenIterator;
|
||||
var Range = require("../range").Range;
|
||||
|
||||
|
||||
function BracketMatch() {
|
||||
|
||||
this.findMatchingBracket = function(position, char) {
|
||||
if (position.column == 0) return null;
|
||||
|
||||
var charBeforeCursor = char || 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;
|
||||
|
||||
});
|
||||
@@ -1,108 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
});
|
||||
@@ -1,268 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var 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;
|
||||
});
|
||||
@@ -1,751 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var 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 (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 != null) {
|
||||
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, dir) {
|
||||
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(/\..*/, "\\."));
|
||||
if (dir != 1) {
|
||||
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);
|
||||
|
||||
if (dir != -1) {
|
||||
do {
|
||||
token = iterator.stepForward();
|
||||
} while(token && re.test(token.type));
|
||||
token = iterator.stepBackward();
|
||||
} else
|
||||
token = iterator.getCurrentToken();
|
||||
|
||||
range.end.row = iterator.getCurrentTokenRow();
|
||||
range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2;
|
||||
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) {
|
||||
e = e.domEvent;
|
||||
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 || e.srcElement).className += " ace_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;
|
||||
|
||||
});
|
||||
@@ -1,188 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,555 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
.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;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var 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++) {
|
||||
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, ix, true, false);
|
||||
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
|
||||
};
|
||||
};
|
||||
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
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 result = highlighter.render(snippet, mode, theme);
|
||||
assert.equal(result.html, "<div class='ace-tomorrow'> <div class='ace_editor ace_scroller ace_text-layer'> <div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>1</span><span class='ace_comment ace_doc'>/** this is a function</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>2</span><span class='ace_comment ace_doc'>*</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>3</span><span class='ace_comment ace_doc'>*/</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>4</span><span class='ace_storage ace_type'>function</span> <span class='ace_entity ace_name ace_function'>hello</span> <span class='ace_paren ace_lparen'>(</span><span class='ace_variable ace_parameter'>a</span><span class='ace_punctuation ace_operator'>, </span><span class='ace_variable ace_parameter'>b</span><span class='ace_punctuation ace_operator'>, </span><span class='ace_variable ace_parameter'>c</span><span class='ace_paren ace_rparen'>)</span> <span class='ace_paren ace_lparen'>{</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>5</span>    <span class='ace_storage ace_type'>console</span><span class='ace_punctuation ace_operator'>.</span><span class='ace_support ace_function ace_firebug'>log</span><span class='ace_paren ace_lparen'>(</span><span class='ace_identifier'>a</span> <span class='ace_keyword ace_operator'>*</span> <span class='ace_identifier'>b</span> <span class='ace_keyword ace_operator'>+</span> <span class='ace_identifier'>c</span> <span class='ace_keyword ace_operator'>+</span> <span class='ace_string'>'sup?'</span><span class='ace_paren ace_rparen'>)</span><span class='ace_punctuation ace_operator'>;</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>6</span><span class='ace_paren ace_rparen'>}</span></div> </div> </div>");
|
||||
assert.ok(!!result.css);
|
||||
next();
|
||||
},
|
||||
|
||||
"test css from theme is used": function(next) {
|
||||
var theme = require("../theme/tomorrow");
|
||||
var snippet = "\
|
||||
/** this is a function\n\
|
||||
*\n\
|
||||
*/\n\
|
||||
function hello (a, b, c) {\n\
|
||||
console.log(a * b + c + 'sup?');\n\
|
||||
}";
|
||||
var 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();
|
||||
}
|
||||