Compare commits
822 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 404419d1c3 | |||
| 4ee94a6574 | |||
| f929df0419 | |||
| 57587dafbe | |||
| 31a95e81b3 | |||
| 70a4e9551b | |||
| e1a705f975 | |||
| 9057ec82d8 | |||
| 1b53e36666 | |||
| 10fa5c7bd2 | |||
| 06e72a5a60 | |||
| 8fa62fc300 | |||
| 6c345fc508 | |||
| a34eac4ecb | |||
| 10c121e603 | |||
| 2b910167f4 | |||
| 7d5311a075 | |||
| f5581c4b49 | |||
| e09f7cd49c | |||
| 4dab03b61b | |||
| 2b5e017aa1 | |||
| 8b3d944fd2 | |||
| 2d886fd38a | |||
| 80088832b9 | |||
| be1883f317 | |||
| 30119e0c77 | |||
| c90c3b1544 | |||
| 578386f083 | |||
| 3d21ed362e | |||
| 9cf469b035 | |||
| 462c93ae43 | |||
| bda3b7b24d | |||
| d861a22cdd | |||
| 0de1a182da | |||
| b030554348 | |||
| 858bfa9ccd | |||
| ee8ec78da7 | |||
| c8f684895c | |||
| 138a155ba4 | |||
| ad749bf345 | |||
| ff0d59c16b | |||
| df75d2d60c | |||
| 2713aabeaf | |||
| 796d1b44c2 | |||
| 470a7b8f52 | |||
| f699b82a9f | |||
| 44edb8c7da | |||
| bc4fc0edd9 | |||
| 6545fa691b | |||
| 4954553927 | |||
| 9c50ba9eeb | |||
| 9a67da145a | |||
| ca7d82278c | |||
| f6245c53dd | |||
| 6888420cc6 | |||
| c5631f5b7d | |||
| 34e0b49d72 | |||
| bd072264ef | |||
| cfb2d24c71 | |||
| fe0eb72fa3 | |||
| 2783257f06 | |||
| cc11cb866c | |||
| 6a02643bda | |||
| 7f269c8da3 | |||
| ef7f7cebd1 | |||
| 05c24fd5e3 | |||
| b08b97bd28 | |||
| dbb6ce2f71 | |||
| f66f14b593 | |||
| 8a52315dee | |||
| 7c4052906c | |||
| 3a56f39f6a | |||
| 6585ca5dd0 | |||
| 792abae07e | |||
| 74ce648c59 | |||
| 2686e96046 | |||
| 213e2bb432 | |||
| 79bb5c10ab | |||
| 7ea012d786 | |||
| 43591f75de | |||
| 05d82c0569 | |||
| 76c8d3206c | |||
| 00751d05b4 | |||
| b5be5df11a | |||
| 7d159273fc | |||
| 70127922ab | |||
| b95df93775 | |||
| dc06edcf5b | |||
| fdc437dcd5 | |||
| f6873c9612 | |||
| 93754ab32d | |||
| 5759334635 | |||
| f2f543b72d | |||
| 598b052be3 | |||
| a746062422 | |||
| c8868d369f | |||
| 52c6e7474c | |||
| be81f09b0e | |||
| 6fa4504e31 | |||
| 992ba01a12 | |||
| 72c5a74cf1 | |||
| 919f41a0f1 | |||
| 785921cb0f | |||
| 8c8cda5e7d | |||
| 64ef74e7e9 | |||
| 776df4e6ee | |||
| 68465a8651 | |||
| fa16c8960c | |||
| 2c57915781 | |||
| d0527f1aeb | |||
| 75083c5b56 | |||
| 82526594db | |||
| 941d39800c | |||
| a1ae2e8bc0 | |||
| 4af6f366ca | |||
| c7a9534ed9 | |||
| 00bcbbf72b | |||
| ed2254ff9f | |||
| b6633f0ecb | |||
| e08d2d3052 | |||
| fbc0548b43 | |||
| a9807bd1e1 | |||
| 554b80b39d | |||
| 99e74bf00b | |||
| f48e923f28 | |||
| 5400b4bfdd | |||
| f68bebe0f6 | |||
| 4c6019b439 | |||
| 66e08a6b17 | |||
| 7898db70ed | |||
| 7c357116ff | |||
| 69ce0eb0d0 | |||
| 4db31a297b | |||
| e1fca457e4 | |||
| 7f8485ce80 | |||
| 290061fd11 | |||
| a507836936 | |||
| 6524d20a96 | |||
| f1c523aa30 | |||
| 87c08f5613 | |||
| 82913cea20 | |||
| 2ad743e4bd | |||
| fa97b57a96 | |||
| 1b952b6d56 | |||
| 90cc512bd1 | |||
| b82556c9c0 | |||
| fbe3b4bb3b | |||
| 5ffd98ad31 | |||
| cb9dd4d228 | |||
| cd823bf10c | |||
| 5560ec52c2 | |||
| 065151a77f | |||
| 23454f556c | |||
| a2b3ddf931 | |||
| 44b0d2fcfc | |||
| aed4cc590a | |||
| 72ee08b5ab | |||
| 45547624e4 | |||
| f928cfa8be | |||
| 988984846a | |||
| 1149618653 | |||
| 168a033903 | |||
| 6a765c9791 | |||
| e16ae7b511 | |||
| 174334ea44 | |||
| dbdf06930d | |||
| c93e65ddc3 | |||
| 56101ed264 | |||
| 8269c8e574 | |||
| 2246419d1e | |||
| 118a0c318b | |||
| 5401cf2910 | |||
| 432f9b8d2f | |||
| 66fc8a2d31 | |||
| 2f3dd3d227 | |||
| c43fd9fa6c | |||
| 868518e0f5 | |||
| 039b5cce98 | |||
| 4a421842d5 | |||
| cfbb124f81 | |||
| dcb147cde2 | |||
| 8d06b5e67e | |||
| 4776d0b422 | |||
| 58bb340c33 | |||
| ee790a9b7c | |||
| ac432aad78 | |||
| 30207e0a39 | |||
| d98547a33c | |||
| b7cdeabbf6 | |||
| be9907a0cc | |||
| 30f42c50a9 | |||
| 7cba65b138 | |||
| f34a78b336 | |||
| e1942dda03 | |||
| 7142e284fa | |||
| 3c1c588953 | |||
| 52cc6bae34 | |||
| 955c608115 | |||
| 2e00cf312c | |||
| 09bbc144d1 | |||
| d02b63a434 | |||
| 9b63c67d8c | |||
| 05c4bf3374 | |||
| 424b4d3f4e | |||
| f9a6187fab | |||
| d406472882 | |||
| 749b5a5ff8 | |||
| 091d5fe750 | |||
| c8894fb465 | |||
| 2dd41cbfac | |||
| 1f2165e68b | |||
| e9b6bdbdd7 | |||
| c0c77c5ba7 | |||
| 12403172ac | |||
| 3b41ab8d75 | |||
| 7bcf35f5b1 | |||
| 9a7e1c94c7 | |||
| 30c2e675da | |||
| ac405803e8 | |||
| 7dee787a92 | |||
| ae4b1cdeca | |||
| 572982cbf9 | |||
| 74290874f9 | |||
| 847f08d952 | |||
| 0bcd616668 | |||
| 9dd701ccc4 | |||
| 56a5a7d92b | |||
| 0cf0fad50e | |||
| 5f9e91656e | |||
| a7a2479f85 | |||
| a8b230a490 | |||
| 041b01f171 | |||
| 1c475f3215 | |||
| ab699d94b0 | |||
| 942d32c9b6 | |||
| 97f15f0b18 | |||
| ed49358c50 | |||
| 85eeecd140 | |||
| 30fd40fbe5 | |||
| 2ed262cacd | |||
| 29a1ef8f8a | |||
| 772d18ee62 | |||
| dd604d9942 | |||
| 85abc83427 | |||
| 6d8220629c | |||
| 6ff7ada096 | |||
| 8575049de5 | |||
| bb6fb0c253 | |||
| eb2ad9f840 | |||
| d0dd23fc11 | |||
| 7ae4acbdb0 | |||
| 881590ab37 | |||
| 5e479dc5d9 | |||
| 7db9c2e762 | |||
| ce6b0ac095 | |||
| 420bb06988 | |||
| 20566f8acf | |||
| 1d5f69704a | |||
| 0da664299e | |||
| 6e8fb2b457 | |||
| d1c72a4ff3 | |||
| 0bf05392e4 | |||
| 7ecef0c045 | |||
| 33ca329253 | |||
| 01fa4770cb | |||
| b76257c49c | |||
| e2fbf22f38 | |||
| 134432d029 | |||
| 8d4d6e80b8 | |||
| 85e6ef3dca | |||
| 60f1467229 | |||
| 1757242382 | |||
| 55df7bb9c4 | |||
| 686b8acd38 | |||
| a5f9df6170 | |||
| 27f61a870a | |||
| a48e8d1c5c | |||
| b80f74bccd | |||
| 1e768734ef | |||
| 11c9cabeb3 | |||
| 3a14ab92f0 | |||
| 62d5f52398 | |||
| 2b4848566c | |||
| 7c825e877c | |||
| 8417c277e6 | |||
| 9cef423908 | |||
| e73c84490e | |||
| 6cfc807db0 | |||
| be366f8103 | |||
| 2d13bd796f | |||
| 523f8f80ca | |||
| b76fef9143 | |||
| e935af83d5 | |||
| d4e019ef42 | |||
| 2e738828c6 | |||
| fd7dc93778 | |||
| 3df407d9ee | |||
| 6fbba84725 | |||
| 37d20fa9cc | |||
| 410cd912ac | |||
| d234bbd861 | |||
| 3f68d96815 | |||
| 015cd895d2 | |||
| 5fa4b48d85 | |||
| 88a3783bbc | |||
| ea2254b9bd | |||
| 9a0c1f2605 | |||
| 008f26bb7d | |||
| 69e453ea0b | |||
| 88b0b608f4 | |||
| 19e3987ae3 | |||
| c72e91ddaf | |||
| c789dd5067 | |||
| 551949de29 | |||
| 80730ee87a | |||
| 71028adc9e | |||
| a2efebc06c | |||
| a4e277a86b | |||
| 494c80d8b1 | |||
| 02539bfdd3 | |||
| a0f05eaf67 | |||
| 72e26fc90b | |||
| 2261cfabf3 | |||
| c1afa2a0e3 | |||
| d28f454c6e | |||
| f471c80ac0 | |||
| be086d94b5 | |||
| ff719510b6 | |||
| 7b16116b67 | |||
| 8422b71204 | |||
| c9bc2a89f6 | |||
| 387a52a7ba | |||
| 96842d9742 | |||
| 8fcef5401b | |||
| 804c4c678d | |||
| 8558777ece | |||
| 77bb608878 | |||
| 2f574261a7 | |||
| 28c4a2c39e | |||
| bd36cb59b1 | |||
| 998358ada8 | |||
| 75a00e8821 | |||
| b5653464d2 | |||
| 0269cd0b3b | |||
| 88ed662fd4 | |||
| 7c180c86a4 | |||
| f811ac510e | |||
| 3e5054f357 | |||
| 3424a424a7 | |||
| 8eb8af8ef8 | |||
| 8eaf7fc497 | |||
| 3255709399 | |||
| 2dbea36b81 | |||
| e0b7009bff | |||
| 77fb5ec3cb | |||
| 7392bce5dc | |||
| 8188bbd35d | |||
| 80fdea7bfb | |||
| dc9f6ac709 | |||
| ba796bc23d | |||
| e0ecb4c44f | |||
| d4c05304e9 | |||
| ccdbd71517 | |||
| 454fce09c6 | |||
| be4b12b4c8 | |||
| 9fa629de31 | |||
| 78dd5774b3 | |||
| bb9a9cd0db | |||
| ab9d8fb3db | |||
| 6ce76af2be | |||
| 3199a4b2cb | |||
| 6a2d153c3d | |||
| bfd4ad9255 | |||
| 30224515fd | |||
| d7f3acfd05 | |||
| a9e9eeeb54 | |||
| 76fa52b313 | |||
| 67de8e6a3a | |||
| ff78998829 | |||
| 55786e2d29 | |||
| 20534a71b9 | |||
| 316b6feccb | |||
| 6c7417e0a2 | |||
| af89dc881e | |||
| 5714cef3de | |||
| 3d2c8e7cc5 | |||
| 772ffcc5e8 | |||
| 8c30bb3a9f | |||
| 89bc121d3f | |||
| 1cc9d7b647 | |||
| 50e494e8e9 | |||
| 19325930a2 | |||
| ac97f7e9a2 | |||
| 33f133b8b2 | |||
| 2e9995e80a | |||
| 53f676bf2e | |||
| 874d658d2a | |||
| d27c455ab7 | |||
| 9291431c61 | |||
| 2e5f51e9ae | |||
| 2aa7e466ed | |||
| 3767a11d21 | |||
| 8c8b72d482 | |||
| bb9effa282 | |||
| 52e96bfa0f | |||
| 00ded65b7f | |||
| f738aa4234 | |||
| 6ff939451c | |||
| 32930cee01 | |||
| 3f45c76f48 | |||
| 1511baf12d | |||
| 20dd0816a6 | |||
| 41cd43ebc6 | |||
| 4a63899722 | |||
| c31ead493a | |||
| 7485733fba | |||
| e930b5d07b | |||
| 4543781153 | |||
| 1d5bfbb162 | |||
| 7045f7f92d | |||
| 5e7974f30b | |||
| 1079a888d3 | |||
| b1837abbc2 | |||
| 611e1a536c | |||
| c152ae1557 | |||
| de3020c1aa | |||
| f12c3fe06f | |||
| 754485c306 | |||
| 088448a8a1 | |||
| 6e35a09abd | |||
| 8fd11e8fdb | |||
| 40855103ad | |||
| 02041dbdb7 | |||
| 18ccc01501 | |||
| 1ff3f9c0da | |||
| 7a251248f1 | |||
| 971cbb94f6 | |||
| b53c961db2 | |||
| 9c40cbea76 | |||
| a8ce7e93cd | |||
| 4b02b74d6f | |||
| 67dd3afd92 | |||
| 7aca7fa0ec | |||
| c0564a1467 | |||
| b0a8984d3b | |||
| 0f451d6833 | |||
| c704d1f3b3 | |||
| e6d568fd49 | |||
| ee56509302 | |||
| bc5896b51f | |||
| 3224f5f422 | |||
| f9cd97edaa | |||
| e1ce3d46de | |||
| 294a8e9642 | |||
| 44fb6d9648 | |||
| 74c1ba1653 | |||
| 0cb39f049f | |||
| f7a3a8aa55 | |||
| cbc37eb006 | |||
| 097f45eeb3 | |||
| 4c5b3dd76f | |||
| ccf70590a4 | |||
| 3c709a27ac | |||
| 8554654ee9 | |||
| 59ac86cf6e | |||
| a4ecc9a187 | |||
| cc67c8b68e | |||
| b41f660fec | |||
| 00edcbbf64 | |||
| c530c70575 | |||
| 21840bb344 | |||
| 57bc23779d | |||
| 78e649f30a | |||
| eaa7a61f71 | |||
| 150a019b8d | |||
| 5dd1158025 | |||
| c60ca4a8d2 | |||
| e1b28f0805 | |||
| aeeaeb1eae | |||
| 76f87f9094 | |||
| 01e1c92813 | |||
| 22c0206451 | |||
| 5173c258b7 | |||
| ff8b892ebe | |||
| 7b0988cc19 | |||
| a4c79f09f8 | |||
| 7ec3d92215 | |||
| ac9fef784a | |||
| 4822bad4fb | |||
| d7dd90f073 | |||
| bbc19d1800 | |||
| 9ee9e61312 | |||
| f765137f3f | |||
| e160822b0f | |||
| c0e35b0126 | |||
| ac41ed629e | |||
| 8b5dfff2a1 | |||
| e77154bf7a | |||
| 5f5187e05c | |||
| 5db1728a3f | |||
| c7984ceed1 | |||
| 5d3571b7a3 | |||
| c1082b4474 | |||
| 14f16349c0 | |||
| aa7e01a085 | |||
| 484629734e | |||
| 444fca2250 | |||
| 7f17102c86 | |||
| e480998a4c | |||
| 5c642997fe | |||
| 5be5cd5ba5 | |||
| 1d55ed0599 | |||
| 4380aa9803 | |||
| 66e7f240da | |||
| f3e5816547 | |||
| 3d5931c259 | |||
| d510c74456 | |||
| 7154220d0b | |||
| d5155273df | |||
| 60dbe9d0a7 | |||
| f7d3f6b3f0 | |||
| 40fdd2aa74 | |||
| f39ed93ca0 | |||
| 541b2fabb4 | |||
| 067ad72f34 | |||
| 6c137e39c9 | |||
| f8c6cdb207 | |||
| f5de6a809d | |||
| e36b96fca6 | |||
| cd1738bdf6 | |||
| ebcd30fadc | |||
| 3c10a6bf94 | |||
| dc80fd9b15 | |||
| 5d21df9ac7 | |||
| 019e912d7f | |||
| 3479dca0d0 | |||
| 32e5cc4a5a | |||
| 268a9f18fa | |||
| 16a6186570 | |||
| 4b2fb6dd11 | |||
| 67d21bcd64 | |||
| 9b87126f0f | |||
| 1043b4de70 | |||
| 4bc5e7b8ff | |||
| 423b5205bf | |||
| fde288d9e8 | |||
| f2a2d85008 | |||
| 3a91b076e1 | |||
| 27bd608b53 | |||
| 966ba29084 | |||
| 3ea5b0193c | |||
| 97dd1b3b00 | |||
| fe0088d1ae | |||
| 342e1e22f8 | |||
| c9203047fc | |||
| a3a946ccd6 | |||
| 22564f34a9 | |||
| f939c24aa4 | |||
| be93fa747b | |||
| d7f4eeea2c | |||
| 6191f60025 | |||
| 82ccb0cedb | |||
| eb92e4413a | |||
| b0ba205532 | |||
| 4fa2cdf8d9 | |||
| ae30b23d34 | |||
| 1d3905bb71 | |||
| aa1e845f9a | |||
| fbcc69ec67 | |||
| 68b2de6dd7 | |||
| 20389babbc | |||
| f9899033aa | |||
| eb37b17486 | |||
| c428cad286 | |||
| 26486da27b | |||
| cabd0ed85e | |||
| f53e1a60d5 | |||
| ec694e4a99 | |||
| 81e076c924 | |||
| 04070ffc23 | |||
| 6941d6b863 | |||
| 3c88f68f16 | |||
| 82461da704 | |||
| 8e5d17c907 | |||
| 43d2143506 | |||
| 28b729acda | |||
| 584641236b | |||
| ca74897569 | |||
| 61987c85d2 | |||
| cfb75abeed | |||
| fd32706f0b | |||
| d1f90b7d44 | |||
| f09bc4a81a | |||
| 31b3aea282 | |||
| 2e1d236e8e | |||
| 065d06a98f | |||
| 63107566ec | |||
| 4f1dcea806 | |||
| 5da1a2c611 | |||
| 180a214e1f | |||
| bb417c6975 | |||
| 75c02475be | |||
| 2fd07211d9 | |||
| 128f3be596 | |||
| 810333dbb7 | |||
| e465358ec0 | |||
| 2954ed84a0 | |||
| b36cd8a68e | |||
| 8435daa598 | |||
| 38c943d564 | |||
| 8e89ec504f | |||
| a692ec1124 | |||
| 4e5f2c9587 | |||
| 1cc263acfb | |||
| 49c6534da6 | |||
| 02d3a3d7ec | |||
| 1dbe49243c | |||
| 2c12fb7ae8 | |||
| 829c6debbd | |||
| f2d3ed322e | |||
| d90e7db497 | |||
| 26f372a36a | |||
| b037777f83 | |||
| 35ce35b1e0 | |||
| e1517c2907 | |||
| ed5f88daa0 | |||
| 4afda646f0 | |||
| e782538777 | |||
| 4e86be86d9 | |||
| 6c8cfcd7c2 | |||
| 9fc7929665 | |||
| d590bf7d64 | |||
| c0f653340e | |||
| ac2bef083b | |||
| 42c7d0ca44 | |||
| 8a8afcfb24 | |||
| 5d259bb5aa | |||
| d2a24ed4bc | |||
| efd2f49484 | |||
| 9d4d6ccca5 | |||
| 218c894b5a | |||
| 0dec522542 | |||
| 7fa6708483 | |||
| 33af47c282 | |||
| 6b971e9e1b | |||
| 50107504a6 | |||
| 2cb0c9fea6 | |||
| dd7c2cc7f6 | |||
| 857ca14499 | |||
| f022b3fcde | |||
| 9470ff2dcc | |||
| d817a4fdb6 | |||
| 19635b06cf | |||
| 872776660b | |||
| 9644d4b00e | |||
| 04579d7ae6 | |||
| e9a9eb1779 | |||
| 9a1dddaccf | |||
| 4110ab5a82 | |||
| 5d1844e491 | |||
| 6a126d46ee | |||
| f834a0c84f | |||
| 9dfeb237e7 | |||
| b769ba2974 | |||
| fc1feb280f | |||
| bface83af7 | |||
| 9a89a16388 | |||
| 7649abf86a | |||
| b6ad97745d | |||
| 92028e191d | |||
| 7d4427a5d3 | |||
| 2bea800a37 | |||
| 4c1ff7deb7 | |||
| 347260f17b | |||
| 1086fba7da | |||
| 5a7cb129bb | |||
| b29d22e99b | |||
| 12cf102543 | |||
| 3d95730880 | |||
| c5d807dd58 | |||
| d40df79dce | |||
| 3cfa297b49 | |||
| e435769345 | |||
| 9a73877b3e | |||
| e2cd8d93f4 | |||
| afc6ec468f | |||
| 391838cfc3 | |||
| 36a11ded4f | |||
| f540ef2e06 | |||
| b061e0f859 | |||
| 4972fbbc7b | |||
| 1f318de812 | |||
| 0ceeadd75b | |||
| b9dad32707 | |||
| d1cf698b45 | |||
| 9dba3f9c58 | |||
| 8fbbe40300 | |||
| f73c925ad9 | |||
| b7fb4c5950 | |||
| fed49bb98b | |||
| 6aa4e382b2 | |||
| 8051d4f9b0 | |||
| 31a49601b1 | |||
| 4a50635fe1 | |||
| 9b92e9d325 | |||
| 833953d658 | |||
| 198dc8a8e2 | |||
| 78cd65240f | |||
| 02073f827b | |||
| 4cd3fdcdba | |||
| 7c803288e0 | |||
| dc91e0f733 | |||
| adc3abe82a | |||
| 00b6f5c3fb | |||
| b5a2a8df67 | |||
| 0cc4c9f2c2 | |||
| 7317a9ba2d | |||
| d6a4009989 | |||
| 8ee52e7d05 | |||
| b9a970a19a | |||
| bee93eade1 | |||
| 5d157eea54 | |||
| 28b494c913 | |||
| 817f189154 | |||
| 0bfa049778 | |||
| 8745314ad8 | |||
| 846d6d62c7 | |||
| c625440161 | |||
| aa544f03fb | |||
| 8d42c06fb0 | |||
| 4480ff0520 | |||
| eed9b2695a | |||
| 337a9b180e | |||
| 66a6ee97f0 | |||
| 26d5abe7a5 | |||
| bf8246c705 | |||
| 73cd25b05f | |||
| c5cc6905de | |||
| 7b0a714e1f | |||
| b47d83a7f2 | |||
| 5f4d312b8e | |||
| be4c52202c | |||
| 4e9111976e | |||
| 5163f11ecb | |||
| 5a1d5fa4f0 | |||
| d389390523 | |||
| 5a661fdacc | |||
| bd6dfcd51c | |||
| 8014486fd8 | |||
| 654b5b176b | |||
| af09f99c8a | |||
| 108876d9a1 | |||
| 1eb65caff4 | |||
| 7924e8c9a9 | |||
| 101f43947f | |||
| 68a0ead0c5 | |||
| 3d119c0d5d | |||
| f3e8cbf41d | |||
| f0fa42a50e | |||
| a20fd4fdcf | |||
| 32fb1cdb23 | |||
| ac24213d53 | |||
| fa20343253 | |||
| f4d70d3748 | |||
| b311730c7c | |||
| 3cba98fee6 | |||
| 7c799323a5 | |||
| 6926746624 | |||
| af7a52970f | |||
| 5ce3886651 | |||
| 0bc883ee29 | |||
| cc96786ac0 | |||
| 5b84ecf372 | |||
| 620926c379 | |||
| 7a4e57a49d | |||
| cdca60ff1b | |||
| 604f88939e | |||
| 95a7d33848 | |||
| 39e06e48bd | |||
| 9246c1443f | |||
| d3e358817e | |||
| 3682bc8558 | |||
| 8c1f82d894 | |||
| 6887c89d5c | |||
| 5071072c6b | |||
| 1cb7bc96c7 | |||
| 755c303008 | |||
| 381a963971 | |||
| 903ea7c49a | |||
| 41c4801aed | |||
| 3a8d65bd3e | |||
| 095a392359 | |||
| ce770c2e79 | |||
| be9529faee | |||
| 1f948e30d8 | |||
| 50de79171a | |||
| e8b3854682 | |||
| 985fade9f6 | |||
| 39b1177ba0 | |||
| 5fb440171e | |||
| 38673e5f43 | |||
| b8ce2b251d | |||
| 7829e17c27 | |||
| fced891975 | |||
| 35da594bfc | |||
| e8df272729 | |||
| a337b9ba15 | |||
| 685cc358b3 | |||
| 9ce4f0220e | |||
| 2128559186 | |||
| 20e4ca6a56 | |||
| 6f15fafc4a | |||
| cd4704aed7 | |||
| 82fd4d8b26 | |||
| 08a58b7520 | |||
| c7d8026ac5 | |||
| 9efcf8bfb1 | |||
| 4cad535baa | |||
| 5fc3c298c1 | |||
| e5fe89a4fd | |||
| ccaea78901 | |||
| 1111dbb9a2 |
@@ -0,0 +1,32 @@
|
||||
# https://help.github.com/articles/dealing-with-line-endings
|
||||
#
|
||||
# For Mac & Linux
|
||||
# git config --global core.autocrlf input
|
||||
#
|
||||
# For windows
|
||||
# git config --global core.autocrlf true
|
||||
#
|
||||
# Set default behaviour, in case users don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# Explicitly declare text files we want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.txt text
|
||||
*.md text
|
||||
*.rb text
|
||||
*.js text
|
||||
*.html text
|
||||
*.yml text
|
||||
*.mustache text
|
||||
*.css text
|
||||
Rakefile text
|
||||
Gemfile text
|
||||
LICENSE text
|
||||
COPYRIGHT text
|
||||
gollum text
|
||||
.gitattributes text
|
||||
.gitignore text
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
@@ -3,3 +3,5 @@ pkg
|
||||
.DS_Store
|
||||
.bundle
|
||||
Gemfile.lock
|
||||
*.gem
|
||||
*.swp
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- 1.9.2
|
||||
- rbx-2.0
|
||||
- 1.9.3
|
||||
notifications:
|
||||
disabled: true
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -y --force-yes asciidoc
|
||||
- ASCIIDOC=1; export ASCIIDOC
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
source "http://rubygems.org"
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
gem "rake", "~> 0.9.2"
|
||||
gem 'rake', '~> 10.0.2'
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
# 1.4.0 / 2012-04-10
|
||||
|
||||
* Minor
|
||||
* Add a way to configure the `#id_prefix` property of Sanitization
|
||||
objects.
|
||||
* Add web sequence diagrams support
|
||||
* Support for updating wysiwyg components when markup language changes
|
||||
* Support RedCarpet 2.0
|
||||
* Allow ftp and irc links in wiki markup
|
||||
* Minor ui fixups
|
||||
|
||||
* Bug Fixes
|
||||
* Include the language of the code snippet when making a uniquely
|
||||
identifiable sha of a code snippet while rendering a page.
|
||||
* Pygments lexer forces utf8 encoding
|
||||
* Remove MathJax, this created problems in production for us.
|
||||
We'll look at bringing it back in future releases
|
||||
|
||||
# 1.3.1 / 2011-07-21
|
||||
|
||||
* Major Enhancements
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
gollum -- A wiki built on top of Git
|
||||
====================================
|
||||
|
||||
[](http://travis-ci.org/github/gollum)
|
||||
[](https://gemnasium.com/github/gollum)
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Gollum is a simple wiki system built on top of Git that powers GitHub Wikis.
|
||||
@@ -16,6 +19,11 @@ number of ways depending on your needs. You can edit your wiki locally:
|
||||
Gollum follows the rules of [Semantic Versioning](http://semver.org/) and uses
|
||||
[TomDoc](http://tomdoc.org/) for inline documentation.
|
||||
|
||||
## SYSTEM REQUIREMENTS
|
||||
- Python 2.5+ (2.7.3 recommended)
|
||||
- Ruby 1.8.7+ (1.9.3 recommended)
|
||||
- Unix like operating system (OS X, Ubuntu, Debian, and more)
|
||||
- Will not work on Windows (because of [grit](https://github.com/github/grit))
|
||||
|
||||
## INSTALLATION
|
||||
|
||||
@@ -26,15 +34,16 @@ The best way to install Gollum is with RubyGems:
|
||||
If you're installing from source, you can use [Bundler][bundler] to pick up all the
|
||||
gems:
|
||||
|
||||
$ bundle install # ([more info](http://gembundler.com/bundle_install.html))
|
||||
$ bundle install
|
||||
|
||||
In order to use the various formats that Gollum supports, you will need to
|
||||
separately install the necessary dependencies for each format. You only need
|
||||
to install the dependencies for the formats that you plan to use.
|
||||
|
||||
* [ASCIIDoc](http://www.methods.co.nz/asciidoc/) -- `brew install asciidoc`
|
||||
* [ASCIIDoc](http://www.methods.co.nz/asciidoc/) -- `brew install asciidoc` on mac or `apt-get install -y asciidoc` on Ubuntu
|
||||
* [Creole](http://wikicreole.org/) -- `gem install creole`
|
||||
* [Markdown](http://daringfireball.net/projects/markdown/) -- `gem install rdiscount`
|
||||
* [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.
|
||||
* [RDoc](http://rdoc.sourceforge.net/)
|
||||
@@ -58,6 +67,7 @@ utility, you can run it like so:
|
||||
|
||||
$ gollum --help
|
||||
|
||||
Note that the gollum server will not run on Windows because of [an issue](https://github.com/rtomayko/posix-spawn/issues/9) with posix-spawn (which is used by Grit).
|
||||
|
||||
## REPO STRUCTURE
|
||||
|
||||
@@ -105,6 +115,13 @@ are named `_Sidebar.ext` where the extension is one of the supported formats.
|
||||
Sidebars affect all pages in their directory and any subdirectories that do not
|
||||
have a sidebar file of their own.
|
||||
|
||||
## HEADER FILES
|
||||
|
||||
Header files allow you to add a simple header to your wiki. Header files must
|
||||
be named `_Header.ext` where the extension is one of the supported formats.
|
||||
Like sidebars, headers affect all pages in their directory and any
|
||||
subdirectories that do not have a header file of their own.
|
||||
|
||||
## FOOTER FILES
|
||||
|
||||
Footer files allow you to add a simple footer to your wiki. Footer files must
|
||||
@@ -112,7 +129,6 @@ be named `_Footer.ext` where the extension is one of the supported formats.
|
||||
Like sidebars, footers affect all pages in their directory and any
|
||||
subdirectories that do not have a footer file of their own.
|
||||
|
||||
|
||||
## HTML SANITIZATION
|
||||
|
||||
For security and compatibility reasons Gollum wikis may not contain custom CSS
|
||||
@@ -120,7 +136,13 @@ 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.
|
||||
|
||||
## 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:
|
||||
@@ -281,6 +303,22 @@ wiki page, simply preface the link with a single quote (like in LISP):
|
||||
|
||||
This is useful for writing about the link syntax in your wiki pages.
|
||||
|
||||
## TABLE OF CONTENTS
|
||||
|
||||
Gollum has a special tag to insert a table of contents (new in v2.1)
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
This tag is case sensitive, use all upper case. The TOC tag can be inserted
|
||||
into the `_Header`, `_Footer` or `_Sidebar` files too.
|
||||
|
||||
There is also a wiki option `:universal_toc` which will display a
|
||||
table of contents at the top of all your wiki pages if it is enabled.
|
||||
The `:universal_toc` is not enabled by default. To set the option,
|
||||
add the option to the `:wiki_options` hash before starting the
|
||||
frontend app:
|
||||
|
||||
Precious::App.set(:wiki_options, {:universal_toc => true})
|
||||
|
||||
## SYNTAX HIGHLIGHTING
|
||||
|
||||
@@ -294,35 +332,67 @@ separately) by using the following syntax:
|
||||
end
|
||||
```
|
||||
|
||||
The block must start with three backticks (as the first characters on the
|
||||
line). After that comes the name of the language that is contained by the
|
||||
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.
|
||||
|
||||
If the block contents are indented two spaces or one tab, then that whitespace
|
||||
will be ignored (this makes the blocks easier to read in plaintext).
|
||||
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 as the first characters on a
|
||||
line.
|
||||
The block must end with three backticks indented at the same level than the opening
|
||||
backticks.
|
||||
|
||||
### GITHUB SYNTAX HIGHLIGHTING
|
||||
|
||||
As an extra feature, you can syntax highlight a file from your repository, allowing
|
||||
you keep some of your sample code in the main repository. The code-snippet is
|
||||
updated when the wiki is rebuilt. You include github code like this:
|
||||
|
||||
```html:github/gollum/master/test/file_view/1_file.txt```
|
||||
|
||||
This will make the builder look at the **github user**, in the **gollum project**,
|
||||
in the **master branch**, at path **test/file_view/1_file.txt**. It will be
|
||||
rewritten to:
|
||||
|
||||
```html
|
||||
<ol class="tree">
|
||||
<li class="file"><a href="0">0</a></li>
|
||||
</ol>
|
||||
```
|
||||
|
||||
Which will be parsed as HTML code during the Pygments run, and thereby coloured
|
||||
appropriately.
|
||||
|
||||
## MATHEMATICAL EQUATIONS
|
||||
|
||||
Page files may contain mathematic equations in TeX syntax that will be nicely
|
||||
typeset into the expected output. A block-style equation is delimited by `\[`
|
||||
and `\]`. For example:
|
||||
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.
|
||||
|
||||
\[ P(E) = {n \choose k} p^k (1-p)^{ n-k} \]
|
||||
Inline math:
|
||||
|
||||
Inline equations are delimited by `\(` and `\)`. These equations will appear
|
||||
inline with regular text. For example:
|
||||
- $2^2$
|
||||
- `\\(2^2\\)`
|
||||
|
||||
The Pythagorean theorem is \( a^2 + b^2 = c^2 \).
|
||||
Display math:
|
||||
|
||||
Gollum uses [MathJax](http://www.mathjax.org/) to convert the TeX syntax into
|
||||
output suitable for display in web browsers.
|
||||
- $$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
|
||||
|
||||
@@ -347,6 +417,17 @@ By default, internal wiki links are all absolute from the root. To specify a dif
|
||||
|
||||
wiki = Gollum::Wiki.new("my-gollum-repo.git", :base_path => "/wiki")
|
||||
|
||||
Note that base_path just modifies the links. To map gollum to a non-root location:
|
||||
|
||||
- Use the gollum binary: `gollum path/to/wiki --base-path mywiki`
|
||||
- Define config.ru with `map`. See [#532](https://github.com/github/gollum/issues/532) for an example.
|
||||
|
||||
> :base_path - String base path for all Wiki links.
|
||||
>
|
||||
> The String base path to prefix to internal links. For example, when set
|
||||
> to "/wiki", the page "Hobbit" will be linked as "/wiki/Hobbit". Defaults
|
||||
> to "/".
|
||||
|
||||
Get the latest version of the given human or canonical page name:
|
||||
|
||||
page = wiki.page('page-name')
|
||||
@@ -371,6 +452,11 @@ Get the footer (if any) for a given page:
|
||||
|
||||
page.footer
|
||||
# => <Gollum::Page>
|
||||
|
||||
Get the header (if any) for a given page:
|
||||
|
||||
page.header
|
||||
# => <Gollum::Page>
|
||||
|
||||
Get a list of versions for a given page:
|
||||
|
||||
@@ -431,6 +517,38 @@ 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
|
||||
|
||||
@@ -450,3 +568,22 @@ your changes merged back into core is as follows:
|
||||
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
|
||||
|
||||
@@ -17,6 +17,27 @@ def version
|
||||
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
||||
end
|
||||
|
||||
# assumes x.y.z all digit version
|
||||
def next_version
|
||||
# x.y.z
|
||||
v = version.split '.'
|
||||
# bump z
|
||||
v[-1] = v[-1].to_i + 1
|
||||
v.join '.'
|
||||
end
|
||||
|
||||
def bump_version
|
||||
old_file = File.read("lib/#{name}.rb")
|
||||
old_version_line = old_file[/^\s*VERSION\s*=\s*.*/]
|
||||
new_version = next_version
|
||||
# replace first match of old vesion with new version
|
||||
old_file.sub!(old_version_line, " VERSION = '#{new_version}'")
|
||||
|
||||
File.write("lib/#{name}.rb", old_file)
|
||||
|
||||
new_version
|
||||
end
|
||||
|
||||
def date
|
||||
Date.today.to_s
|
||||
end
|
||||
@@ -60,14 +81,6 @@ task :coverage do
|
||||
sh "open coverage/index.html"
|
||||
end
|
||||
|
||||
require 'rake/rdoctask'
|
||||
Rake::RDocTask.new do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = "#{name} #{version}"
|
||||
rdoc.rdoc_files.include('README*')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
desc "Open an irb session preloaded with this library"
|
||||
task :console do
|
||||
sh "irb -rubygems -r ./lib/#{name}.rb"
|
||||
@@ -79,7 +92,14 @@ end
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
|
||||
desc "Update version number and gemspec"
|
||||
task :bump do
|
||||
puts "Updated version to #{bump_version}"
|
||||
# Execute does not invoke dependencies.
|
||||
# Manually invoke gemspec then validate.
|
||||
Rake::Task[:gemspec].execute
|
||||
Rake::Task[:validate].execute
|
||||
end
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
@@ -87,24 +107,28 @@ end
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
desc 'Create a release build'
|
||||
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 tag v#{version}"
|
||||
sh "git push origin master"
|
||||
sh "git push origin v#{version}"
|
||||
sh "gem push pkg/#{name}-#{version}.gem"
|
||||
end
|
||||
|
||||
desc 'Build gem'
|
||||
task :build => :gemspec do
|
||||
sh "mkdir -p pkg"
|
||||
sh "gem build #{gemspec_file}"
|
||||
sh "mv #{gem_file} pkg"
|
||||
end
|
||||
|
||||
desc 'Update gemspec'
|
||||
task :gemspec => :validate do
|
||||
# read spec file and split out manifest section
|
||||
spec = File.read(gemspec_file)
|
||||
@@ -122,7 +146,7 @@ task :gemspec => :validate do
|
||||
split("\n").
|
||||
sort.
|
||||
reject { |file| file =~ /^\./ }.
|
||||
reject { |file| file =~ /^(rdoc|pkg)/ }.
|
||||
reject { |file| file =~ /^(rdoc|pkg|test|Home\.md|\.gitattributes)/ }.
|
||||
map { |file| " #{file}" }.
|
||||
join("\n")
|
||||
|
||||
@@ -133,6 +157,7 @@ task :gemspec => :validate do
|
||||
puts "Updated #{gemspec_file}"
|
||||
end
|
||||
|
||||
desc 'Validate lib files and version file'
|
||||
task :validate do
|
||||
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
|
||||
unless libfiles.empty?
|
||||
|
||||
@@ -45,13 +45,48 @@ opts = OptionParser.new do |opts|
|
||||
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
|
||||
end
|
||||
|
||||
# Read command line options into `options` hash
|
||||
@@ -63,7 +98,10 @@ rescue OptionParser::InvalidOption
|
||||
exit
|
||||
end
|
||||
|
||||
gollum_path = ARGV[0] || Dir.pwd
|
||||
# --gollum-path wins over ARGV[0]
|
||||
gollum_path = wiki_options[:gollum_path] ?
|
||||
wiki_options[:gollum_path] :
|
||||
ARGV[0] || Dir.pwd
|
||||
|
||||
if options['irb']
|
||||
require 'irb'
|
||||
@@ -122,5 +160,31 @@ else
|
||||
require cfg
|
||||
end
|
||||
|
||||
Precious::App.run!(options)
|
||||
base_path = wiki_options[:base_path]
|
||||
|
||||
if wiki_options[:base_path].nil?
|
||||
Precious::App.run!(options)
|
||||
else
|
||||
require 'rack'
|
||||
|
||||
class MapGollum
|
||||
def initialize base_path
|
||||
@mg = Rack::Builder.new do
|
||||
map '/' do
|
||||
run Proc.new { [ 302, {'Location'=> "/#{base_path}" }, [] ] }
|
||||
end
|
||||
|
||||
map "/#{base_path}" do
|
||||
run Precious::App
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@mg.call(env)
|
||||
end
|
||||
end
|
||||
# Rack::Handler does not work with Ctrl + C. Use Rack::Server instead.
|
||||
Rack::Server.new(:app => MapGollum.new(base_path), :Port => options['port'], :Host => options['bind']).start
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# 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" }
|
||||
=end
|
||||
@@ -1,5 +1,7 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
# stdlib
|
||||
require 'digest/md5'
|
||||
require 'digest/sha1'
|
||||
require 'ostruct'
|
||||
|
||||
# external
|
||||
@@ -15,12 +17,23 @@ 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/albino', __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
|
||||
# Do not remove because of warning.
|
||||
# This is required for Ruby 1.8.7 which gollum still supports.
|
||||
$KCODE = 'U'
|
||||
|
||||
module Gollum
|
||||
VERSION = '1.3.1'
|
||||
VERSION = '2.4.3'
|
||||
|
||||
def self.assets_path
|
||||
::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__))
|
||||
end
|
||||
|
||||
class Error < StandardError; end
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
require 'albino/multi'
|
||||
|
||||
class Gollum::Albino < Albino::Multi
|
||||
self.bin = ::Albino::Multi.bin
|
||||
end
|
||||
@@ -1,3 +1,4 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
module Gollum
|
||||
class BlobEntry
|
||||
# Gets the String SHA for this blob.
|
||||
@@ -48,6 +49,18 @@ module Gollum
|
||||
page
|
||||
end
|
||||
|
||||
# Gets a File instance for this blob.
|
||||
#
|
||||
# wiki - Gollum::Wiki instance for the Gollum::File
|
||||
#
|
||||
# Returns a Gollum::File instance.
|
||||
def file(wiki, commit)
|
||||
blob = self.blob(wiki.repo)
|
||||
file = wiki.file_class.new(wiki).populate(blob, self.dir)
|
||||
file.version = commit
|
||||
file
|
||||
end
|
||||
|
||||
def inspect
|
||||
%(#<Gollum::BlobEntry #{@sha} #{@path}>)
|
||||
end
|
||||
@@ -75,4 +88,4 @@ module Gollum
|
||||
dir
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
module Gollum
|
||||
# Responsible for handling the commit process for a Wiki. It sets up the
|
||||
# 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
|
||||
# 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.
|
||||
@@ -21,7 +22,7 @@ module Gollum
|
||||
# :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
|
||||
# assume that this operation is part of batch of
|
||||
# updates and the commit happens later.
|
||||
#
|
||||
# Returns the Committer instance.
|
||||
@@ -73,7 +74,7 @@ module Gollum
|
||||
#
|
||||
# dir - The String subdirectory of the Gollum::Page without any
|
||||
# prefix or suffix slashes (e.g. "foo/bar").
|
||||
# name - The String Gollum::Page name.
|
||||
# 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
|
||||
@@ -91,19 +92,29 @@ module Gollum
|
||||
fullpath = ::File.join(*[@wiki.page_file_dir, dir, path].compact)
|
||||
fullpath = fullpath[1..-1] if fullpath =~ /^\//
|
||||
|
||||
if index.current_tree && tree = index.current_tree / dir
|
||||
if index.current_tree && tree = index.current_tree / (@wiki.page_file_dir || '/')
|
||||
tree = tree / dir unless tree.nil?
|
||||
end
|
||||
|
||||
if tree
|
||||
downpath = path.downcase.sub(/\.\w+$/, '')
|
||||
|
||||
tree.blobs.each do |blob|
|
||||
next if page_path_scheduled_for_deletion?(index.tree, fullpath)
|
||||
file = blob.name.downcase.sub(/\.\w+$/, '')
|
||||
file_ext = ::File.extname(blob.name).sub(/^\./, '')
|
||||
if downpath == file && !(allow_same_ext && file_ext == ext)
|
||||
|
||||
existing_file = blob.name.downcase.sub(/\.\w+$/, '')
|
||||
existing_file_ext = ::File.extname(blob.name).sub(/^\./, '')
|
||||
|
||||
new_file_ext = ::File.extname(path).sub(/^\./, '')
|
||||
|
||||
if downpath == existing_file && !(allow_same_ext && new_file_ext == existing_file_ext)
|
||||
raise DuplicatePageError.new(dir, blob.name, path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fullpath = fullpath.force_encoding('ascii-8bit') if fullpath.respond_to?(:force_encoding)
|
||||
|
||||
index.add(fullpath, @wiki.normalize(data))
|
||||
end
|
||||
|
||||
@@ -111,7 +122,8 @@ module Gollum
|
||||
# is a working directory present.
|
||||
#
|
||||
# dir - The String directory in which the file lives.
|
||||
# name - The String name of the page (may be in human format).
|
||||
# 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.
|
||||
@@ -128,6 +140,8 @@ module Gollum
|
||||
::File.join(dir, @wiki.page_file_name(name, format))
|
||||
end
|
||||
|
||||
path = path.force_encoding('ascii-8bit') if path.respond_to?(:force_encoding)
|
||||
|
||||
Dir.chdir(::File.join(@wiki.repo.path, '..')) do
|
||||
if file_path_scheduled_for_deletion?(index.tree, path)
|
||||
@wiki.repo.git.rm({'f' => true}, '--', path)
|
||||
@@ -151,7 +165,7 @@ module Gollum
|
||||
|
||||
# Adds a callback to be fired after a commit.
|
||||
#
|
||||
# block - A block that expects this Committer instance and the created
|
||||
# block - A block that expects this Committer instance and the created
|
||||
# commit's SHA1 as the arguments.
|
||||
#
|
||||
# Returns nothing.
|
||||
@@ -211,6 +225,7 @@ module Gollum
|
||||
|
||||
# Proxies methods t
|
||||
def method_missing(name, *args)
|
||||
args.map! { |item| item.respond_to?(:force_encoding) ? item.force_encoding('ascii-8bit') : item }
|
||||
index.send(name, *args)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# ~*~ encoding: utf-8 ~*~
|
||||
module Gollum
|
||||
class File
|
||||
Wiki.file_class = self
|
||||
@@ -13,12 +14,29 @@ module Gollum
|
||||
@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.
|
||||
#
|
||||
@@ -28,7 +46,7 @@ module Gollum
|
||||
end
|
||||
|
||||
# Public: The Grit::Commit version of the file.
|
||||
attr_reader :version
|
||||
attr_accessor :version
|
||||
|
||||
# Public: The String path of the file.
|
||||
attr_reader :path
|
||||
@@ -38,6 +56,18 @@ module Gollum
|
||||
@blob.mime_type
|
||||
end
|
||||
|
||||
# Populate the File with information from the Blob.
|
||||
#
|
||||
# blob - The Grit::Blob that contains the info.
|
||||
# path - The String directory path of the file.
|
||||
#
|
||||
# Returns the populated Gollum::File.
|
||||
def populate(blob, path=nil)
|
||||
@blob = blob
|
||||
@path = "#{path}/#{blob.name}"[1..-1]
|
||||
self
|
||||
end
|
||||
|
||||
#########################################################################
|
||||
#
|
||||
# Internal Methods
|
||||
@@ -61,4 +91,4 @@ module Gollum
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
# ~*~ 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,21 +1,63 @@
|
||||
# ~*~ 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__))
|
||||
|
||||
# We want to serve public assets for now
|
||||
# Detect unsupported browsers.
|
||||
Browser = Struct.new(:browser, :version)
|
||||
|
||||
set :public, "#{dir}/public"
|
||||
set :static, true
|
||||
@@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
|
||||
@@ -38,47 +80,127 @@ module Precious
|
||||
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
|
||||
show_page_or_file('Home')
|
||||
redirect ::File.join(@base_url, 'Home')
|
||||
end
|
||||
|
||||
# path is set to name if path is nil.
|
||||
# if path is 'a/b' and a and b are dirs, then
|
||||
# path must have a trailing slash 'a/b/' or
|
||||
# extract_path will trim path to 'a'
|
||||
# name, path, version
|
||||
def wiki_page(name, path = nil, version = nil, exact = true)
|
||||
path = name if path.nil?
|
||||
name = extract_name(name)
|
||||
path = extract_path(path)
|
||||
path = '/' if exact && path.nil?
|
||||
|
||||
wiki = wiki_new
|
||||
|
||||
OpenStruct.new(:wiki => wiki, :page => wiki.paged(name, path, exact, version),
|
||||
:name => name, :path => path)
|
||||
end
|
||||
|
||||
def wiki_new
|
||||
Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
end
|
||||
|
||||
get '/data/*' do
|
||||
if page = wiki_page(params[:splat].first).page
|
||||
page.raw_data
|
||||
end
|
||||
end
|
||||
|
||||
get '/edit/*' do
|
||||
@name = params[:splat].first
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
if page = wiki.page(@name)
|
||||
@page = page
|
||||
@content = page.raw_data
|
||||
mustache :edit
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
@name = wikip.name
|
||||
@path = wikip.path
|
||||
wiki = wikip.wiki
|
||||
if page = wikip.page
|
||||
if wiki.live_preview && page.format.to_s.include?('markdown') && supported_useragent?(request.user_agent)
|
||||
live_preview_url = '/livepreview/index.html?page=' + encodeURIComponent(@name)
|
||||
if @path
|
||||
live_preview_url << '&path=' + encodeURIComponent(@path)
|
||||
end
|
||||
redirect to(live_preview_url)
|
||||
else
|
||||
@page = page
|
||||
@page.version = wiki.repo.log(wiki.ref, @page.path).first
|
||||
raw_data = page.raw_data
|
||||
@content = raw_data.respond_to?(:force_encoding) ? raw_data.force_encoding('UTF-8') : raw_data
|
||||
mustache :edit
|
||||
end
|
||||
else
|
||||
redirect to("/create/#{encodeURIComponent(@name)}")
|
||||
end
|
||||
end
|
||||
|
||||
post '/edit/*' do
|
||||
path = '/' + clean_url(sanitize_empty_params(params[:path])).to_s
|
||||
page_name = CGI.unescape(params[:page])
|
||||
wiki = wiki_new
|
||||
page = wiki.paged(page_name, path, exact = true)
|
||||
return if page.nil?
|
||||
rename = params[:rename].to_url if params[:rename]
|
||||
name = rename || page.name
|
||||
committer = Gollum::Committer.new(wiki, commit_message)
|
||||
commit = {:committer => committer}
|
||||
|
||||
update_wiki_page(wiki, page, params[:content], commit, name, params[:format])
|
||||
update_wiki_page(wiki, page.header, params[:header], commit) if params[:header]
|
||||
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
|
||||
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
|
||||
committer.commit
|
||||
|
||||
page = wiki.page(rename) if rename
|
||||
|
||||
redirect to("/#{page.escaped_url_path}") unless page.nil?
|
||||
end
|
||||
|
||||
get '/delete/*' do
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
name = wikip.name
|
||||
wiki = wikip.wiki
|
||||
page = wikip.page
|
||||
wiki.delete_page(page, { :message => "Destroyed #{name} (#{page.format})" })
|
||||
|
||||
redirect to('/')
|
||||
end
|
||||
|
||||
get '/create/*' do
|
||||
wikip = wiki_page(params[:splat].first.gsub('+', '-'))
|
||||
@name = wikip.name.to_url
|
||||
@path = wikip.path
|
||||
|
||||
page = wikip.page
|
||||
if page
|
||||
redirect to("/#{page.escaped_url_path}")
|
||||
else
|
||||
mustache :create
|
||||
end
|
||||
end
|
||||
|
||||
post '/edit/*' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
page = wiki.page(params[:splat].first)
|
||||
name = params[:rename] || page.name
|
||||
committer = Gollum::Committer.new(wiki, commit_message)
|
||||
commit = {:committer => committer}
|
||||
|
||||
update_wiki_page(wiki, page, params[:content], commit, name,
|
||||
params[:format])
|
||||
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
|
||||
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
|
||||
committer.commit
|
||||
|
||||
redirect "/#{CGI.escape(Gollum::Page.cname(name))}"
|
||||
end
|
||||
|
||||
post '/create' do
|
||||
name = params[:page]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
name = params[:page].to_url
|
||||
path = sanitize_empty_params(params[:path]) || ''
|
||||
format = params[:format].intern
|
||||
|
||||
format = params[:format].intern
|
||||
# ensure pages are created in page_file_dir
|
||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
path = clean_url(::File.join(page_dir, path)) unless path.start_with?(page_dir)
|
||||
|
||||
wiki = wiki_new
|
||||
|
||||
begin
|
||||
wiki.write_page(name, format, params[:content], commit_message)
|
||||
redirect "/#{CGI.escape(name)}"
|
||||
wiki.write_page(name, format, params[:content], commit_message, path)
|
||||
redirect to("/#{clean_url(::File.join(path,name))}")
|
||||
rescue Gollum::DuplicatePageError => e
|
||||
@message = "Duplicate page: #{e.message}"
|
||||
mustache :error
|
||||
@@ -86,73 +208,86 @@ module Precious
|
||||
end
|
||||
|
||||
post '/revert/:page/*' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@name = params[:page]
|
||||
@page = wiki.page(@name)
|
||||
shas = params[:splat].first.split("/")
|
||||
sha1 = shas.shift
|
||||
sha2 = shas.shift
|
||||
wikip = wiki_page(params[:page])
|
||||
@path = wikip.path
|
||||
@name = wikip.name
|
||||
wiki = wikip.wiki
|
||||
@page = wiki.paged(@name,@path)
|
||||
shas = params[:splat].first.split("/")
|
||||
sha1 = shas.shift
|
||||
sha2 = shas.shift
|
||||
|
||||
if wiki.revert_page(@page, sha1, sha2, commit_message)
|
||||
redirect "/#{CGI.escape(@name)}"
|
||||
redirect to("/#{@page.escaped_url_path}")
|
||||
else
|
||||
sha2, sha1 = sha1, "#{sha1}^" if !sha2
|
||||
@versions = [sha1, sha2]
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
@message = "The patch does not apply."
|
||||
@versions = [sha1, sha2]
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
@message = "The patch does not apply."
|
||||
mustache :compare
|
||||
end
|
||||
end
|
||||
|
||||
post '/preview' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@name = "Preview"
|
||||
@page = wiki.preview_page(@name, params[:content], params[:format])
|
||||
@content = @page.formatted_data
|
||||
wiki = wiki_new
|
||||
@name = params[:page] || "Preview"
|
||||
@page = wiki.preview_page(@name, params[:content], params[:format])
|
||||
@content = @page.formatted_data
|
||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||
@mathjax = wiki.mathjax
|
||||
@h1_title = wiki.h1_title
|
||||
@editable = false
|
||||
mustache :page
|
||||
end
|
||||
|
||||
get '/history/:name' do
|
||||
@name = params[:name]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@page = wiki.page(@name)
|
||||
@page_num = [params[:page].to_i, 1].max
|
||||
@versions = @page.versions :page => @page_num
|
||||
get '/history/*' do
|
||||
@page = wiki_page(params[:splat].first).page
|
||||
@page_num = [params[:page].to_i, 1].max
|
||||
@versions = @page.versions :page => @page_num
|
||||
mustache :history
|
||||
end
|
||||
|
||||
post '/compare/:name' do
|
||||
post '/compare/*' do
|
||||
@file = params[:splat].first
|
||||
@versions = params[:versions] || []
|
||||
if @versions.size < 2
|
||||
redirect "/history/#{CGI.escape(params[:name])}"
|
||||
redirect to("/history/#{@file}")
|
||||
else
|
||||
redirect "/compare/%s/%s...%s" % [
|
||||
CGI.escape(params[:name]),
|
||||
redirect to("/compare/%s/%s...%s" % [
|
||||
@file,
|
||||
@versions.last,
|
||||
@versions.first]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
get '/compare/:name/:version_list' do
|
||||
@name = params[:name]
|
||||
@versions = params[:version_list].split(/\.{2,3}/)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@page = wiki.page(@name)
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
get %r{
|
||||
/compare/ # match any URL beginning with /compare/
|
||||
(.+) # extract the full path (including any directories)
|
||||
/ # match the final slash
|
||||
([^.]+) # match the first SHA1
|
||||
\.{2,3} # match .. or ...
|
||||
(.+) # match the second SHA1
|
||||
}x do |path, start_version, end_version|
|
||||
wikip = wiki_page(path)
|
||||
@path = wikip.path
|
||||
@name = wikip.name
|
||||
@versions = [start_version, end_version]
|
||||
wiki = wikip.wiki
|
||||
@page = wikip.page
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
mustache :compare
|
||||
end
|
||||
|
||||
get %r{^/(javascript|css|images)} do
|
||||
halt 404
|
||||
end
|
||||
|
||||
get %r{/(.+?)/([0-9a-f]{40})} do
|
||||
name = params[:captures][0]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
if page = wiki.page(name, params[:captures][1])
|
||||
file_path = params[:captures][0]
|
||||
version = params[:captures][1]
|
||||
wikip = wiki_page(file_path, file_path, version)
|
||||
name = wikip.name
|
||||
path = wikip.path
|
||||
if page = wikip.page
|
||||
@page = page
|
||||
@name = name
|
||||
@content = page.formatted_data
|
||||
@@ -165,51 +300,94 @@ module Precious
|
||||
|
||||
get '/search' do
|
||||
@query = params[:q]
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@results = wiki.search @query
|
||||
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 '/pages' do
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
@results = wiki.pages
|
||||
@ref = wiki.ref
|
||||
get %r{
|
||||
/pages # match any URL beginning with /pages
|
||||
(?: # begin an optional non-capturing group
|
||||
/(.+) # capture any path after the "/pages" excluding the leading slash
|
||||
)? # end the optional non-capturing group
|
||||
}x do |path|
|
||||
@path = extract_path(path) if path
|
||||
wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
|
||||
@results = wiki.pages
|
||||
@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(name)
|
||||
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
|
||||
if page = wiki.page(name)
|
||||
def show_page_or_file(fullpath)
|
||||
name = extract_name(fullpath)
|
||||
path = extract_path(fullpath) || '/'
|
||||
wiki = wiki_new
|
||||
|
||||
page_dir = settings.wiki_options[:page_file_dir].to_s
|
||||
path = ::File.join(page_dir, path) unless path.start_with?(page_dir)
|
||||
|
||||
if page = wiki.paged(name, path, exact = true)
|
||||
@page = page
|
||||
@name = name
|
||||
@content = page.formatted_data
|
||||
@editable = true
|
||||
@content = page.formatted_data
|
||||
@toc_content = wiki.universal_toc ? @page.toc_data : nil
|
||||
@mathjax = wiki.mathjax
|
||||
@h1_title = wiki.h1_title
|
||||
mustache :page
|
||||
elsif file = wiki.file(name)
|
||||
elsif file = wiki.file(fullpath)
|
||||
content_type file.mime_type
|
||||
file.raw_data
|
||||
else
|
||||
@name = name
|
||||
mustache :create
|
||||
page_path = [path, name].compact.join('/')
|
||||
redirect to("/create/#{clean_url(encodeURIComponent(page_path))}")
|
||||
end
|
||||
end
|
||||
|
||||
def update_wiki_page(wiki, page, content, commit_message, name = nil, format = nil)
|
||||
return if !page ||
|
||||
def update_wiki_page(wiki, page, content, commit, name = nil, format = nil)
|
||||
return if !page ||
|
||||
((!content || page.raw_data == content) && page.format == format)
|
||||
name ||= page.name
|
||||
format = (format || page.format).to_sym
|
||||
content ||= page.raw_data
|
||||
wiki.update_page(page, name, format, content.to_s, commit_message)
|
||||
wiki.update_page(page, name, format, content.to_s, commit)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Options parameter to Gollum::Committer#initialize
|
||||
# :message - The String commit message.
|
||||
# :name - The String author full name.
|
||||
# :email - The String email address.
|
||||
# message is sourced from the incoming request parameters
|
||||
# author details are sourced from the session, to be populated by rack middleware ahead of us
|
||||
def commit_message
|
||||
{ :message => params[:message] }
|
||||
commit_message = { :message => params[:message] }
|
||||
author_parameters = session['gollum.author']
|
||||
commit_message.merge! author_parameters unless author_parameters.nil?
|
||||
commit_message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# ~*~ 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,664 +0,0 @@
|
||||
/*
|
||||
gollum.css
|
||||
A basic stylesheet for Gollum
|
||||
*/
|
||||
|
||||
/* @section core */
|
||||
body, html {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 10px; /* -> 1em */
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#wiki-wrapper {
|
||||
margin: 0 auto;
|
||||
overflow: visible;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #4183c4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover, a:visited {
|
||||
color: #4183c4;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/* @section head */
|
||||
#head {
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin: 4.5em 0 0.5em;
|
||||
padding: 0.5em 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#head h1 {
|
||||
font-size: 3.3em;
|
||||
float: left;
|
||||
line-height: normal;
|
||||
margin: 0;
|
||||
padding: 0.08em 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;
|
||||
margin-right: 3%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.has-rightbar #wiki-body {
|
||||
width: 68%;
|
||||
}
|
||||
|
||||
/* @section rightbar */
|
||||
#wiki-rightbar {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 13px;
|
||||
float: right;
|
||||
padding: 7px;
|
||||
width: 25%;
|
||||
|
||||
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: 0;
|
||||
}
|
||||
|
||||
#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: "← ";
|
||||
}
|
||||
|
||||
#wiki-rightbar h3 {
|
||||
font-size: 1.2em;
|
||||
color: #333;
|
||||
margin: 1.2em 0 0;
|
||||
padding: 0;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
#wiki-rightbar ul {
|
||||
margin: 0.5em 0 1em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#wiki-rightbar ul li {
|
||||
color: #bbb;
|
||||
margin: 0 0 0 1em;
|
||||
padding: 0;
|
||||
line-height: 1.75em;
|
||||
list-style-position: inside;
|
||||
list-style-type: round;
|
||||
}
|
||||
|
||||
#wiki-rightbar #nav ul li a {
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
/* @section footer */
|
||||
#wiki-footer {
|
||||
clear: both;
|
||||
margin: 2em 0 5em;
|
||||
}
|
||||
|
||||
.has-rightbar #wiki-footer {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#wiki-footer #footer-content {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.5em;
|
||||
margin-top: 1.5em;
|
||||
padding: 1em;
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
|
||||
#wiki-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 {
|
||||
border-top: 1px solid #ccc;
|
||||
margin: 1em 0 7em;
|
||||
}
|
||||
|
||||
#footer p#last-edit {
|
||||
font-size: 1.2em;
|
||||
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: 3em;
|
||||
}
|
||||
|
||||
#wiki-history fieldset {
|
||||
border: 0;
|
||||
margin: 2em 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: 1.2em;
|
||||
line-height: 1.6em;
|
||||
margin: 0;
|
||||
padding: 0.3em 0.7em;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.checkbox {
|
||||
min-width: 2em;
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
#wiki-history table tr td.checkbox input {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
padding-right: 0;
|
||||
padding-top: 0.4em;
|
||||
margin-right: -0.2em;
|
||||
}
|
||||
|
||||
#wiki-history table tr: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 #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-top: 1em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.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.8em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* @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: 1.2em;
|
||||
margin-left: 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;
|
||||
margin: 1em 0 0 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext {
|
||||
background: #fff;
|
||||
border: 1px solid #d4d4d4;
|
||||
overflow: hidden;
|
||||
|
||||
border-radius: 0.3em;
|
||||
-moz-border-radius: 0.3em;
|
||||
-webkit-border-radius: 0.3em;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext input#search-query {
|
||||
border: none;
|
||||
color: #000;
|
||||
float: left;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 1.2em;
|
||||
height: 1.8em;
|
||||
|
||||
-webkit-focus-ring: none;
|
||||
}
|
||||
|
||||
.ff #head #searchbar #searchbar-fauxtext input#search-query {
|
||||
padding: 0.2em 0 0.2em 0.5em;
|
||||
}
|
||||
|
||||
.ie #head #searchbar #searchbar-fauxtext input#search-query {
|
||||
padding: 0.4em 0 0 0.5em;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext input#search-query.ph {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit {
|
||||
border: 0;
|
||||
border-left: 1px solid #d4d4d4;
|
||||
cursor: pointer;
|
||||
margin: 0 !important;
|
||||
padding: 0;
|
||||
float: right;
|
||||
font-size: 1.2em;
|
||||
|
||||
border-radius: 0 3px 3px 0;
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
-webkit-border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
#head #searchbar #searchbar-fauxtext #search-submit span {
|
||||
background-image: url(/images/icon-sprite.png);
|
||||
background-position: -431px -1px;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
height: 2em;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#MathJax_Message {
|
||||
display: none;
|
||||
}
|
||||
@@ -1,316 +0,0 @@
|
||||
/*
|
||||
Gollum v3 Template
|
||||
*/
|
||||
|
||||
#template {
|
||||
font-size: 13px;
|
||||
line-height: 23px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
/* Link Colors */
|
||||
a.absent {
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
/* Primary Body Copy */
|
||||
#template p {
|
||||
margin: 16px 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* ReST first graf in nested list */
|
||||
#template * li p.first {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
#template h1, #template h2, #template h3,
|
||||
#template h4, #template h5, #template h6 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#template h1 {
|
||||
border-top: 4px solid #ccc;
|
||||
font-size: 32px;
|
||||
line-height: normal;
|
||||
padding: 10px 0 0;
|
||||
margin: 30px 0 0;
|
||||
}
|
||||
|
||||
#template h2 {
|
||||
border-top: 4px solid #ccc;
|
||||
font-size: 22px;
|
||||
line-height: normal;
|
||||
margin: 22px 0 0;
|
||||
padding: 7px 0 0;
|
||||
}
|
||||
|
||||
#template h3 {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
padding: 26px 0 0;
|
||||
}
|
||||
|
||||
#template h4 {
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
padding: 18px 0 4px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#template h5 {
|
||||
font-size: 13px;
|
||||
line-height: 26px;
|
||||
margin-bottom: -19px;
|
||||
padding: 14px 0 0;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#template h6 {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
margin-bottom: -19px;
|
||||
padding: 18px 0 0;
|
||||
font-weight: normal;
|
||||
font-variant: italic;
|
||||
}
|
||||
|
||||
#template hr {
|
||||
background-color: #ccc;
|
||||
color: #ccc;
|
||||
border: 2px solid #ccc;
|
||||
margin: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Border Reset for headers with horizontal rules */
|
||||
#template > h2:first-child,
|
||||
#template > h1:first-child {
|
||||
border: 0;
|
||||
margin: 12px 0 0;
|
||||
padding: 10px 0 0;
|
||||
}
|
||||
|
||||
|
||||
/* Lists, Blockquotes & Such */
|
||||
#template ul,
|
||||
#template ol {
|
||||
margin: 0;
|
||||
padding: 20px 0 0;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
/* Nested Lists */
|
||||
#template ul li ul,
|
||||
#template ol li ol,
|
||||
#template ul li ol,
|
||||
#template ol li ul,
|
||||
#template ul ul,
|
||||
#template ol ol {
|
||||
padding: 0 0 0 14px;
|
||||
}
|
||||
|
||||
#template dl {
|
||||
margin: 0;
|
||||
padding: 20px 0 0;
|
||||
}
|
||||
|
||||
#template dl dt {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: normal;
|
||||
margin: 0;
|
||||
padding: 20px 0 0;
|
||||
}
|
||||
|
||||
#template dl dt:first-child {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#template dl dd {
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
padding: 3px 0 0;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
#template table {
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#template table * tr {
|
||||
border-top: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#template table * tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
#template table * tr th,
|
||||
#template table * tr td {
|
||||
border: 1px solid #ccc;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px;
|
||||
}
|
||||
|
||||
/* Images & Stuff */
|
||||
#template img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Gollum Image Tags */
|
||||
|
||||
/* Framed */
|
||||
#template span.frame {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#template span.frame > span {
|
||||
border: 1px solid #ddd;
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
padding: 7px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#template span.frame span img {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#template span.frame span span {
|
||||
clear: both;
|
||||
color: #333;
|
||||
display: block;
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
|
||||
#template span.align-center {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#template span.align-center > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#template span.align-center span img {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#template span.align-right {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#template span.align-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#template span.align-right span img {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#template span.float-left {
|
||||
display: block;
|
||||
margin-right: 13px;
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#template span.float-left span {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
|
||||
#template span.float-right {
|
||||
display: block;
|
||||
margin-left: 13px;
|
||||
overflow: hidden;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#template span.float-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
/* Code */
|
||||
#template code, #template tt {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #dedede;
|
||||
font-size: 13px;
|
||||
padding: 1px 5px;
|
||||
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#template .highlight pre, #template pre {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px;
|
||||
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#template pre code, #template pre tt {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#template .highlight { background: #ffffff; }
|
||||
#template .highlight .c { color: #999988; font-style: italic }
|
||||
#template .highlight .err { color: #a61717; background-color: #e3d2d2 }
|
||||
#template .highlight .k { font-weight: bold }
|
||||
#template .highlight .o { font-weight: bold }
|
||||
#template .highlight .cm { color: #999988; font-style: italic }
|
||||
#template .highlight .cp { color: #999999; font-weight: bold }
|
||||
#template .highlight .c1 { color: #999988; font-style: italic }
|
||||
#template .highlight .cs { color: #999999; font-weight: bold; font-style: italic }
|
||||
#template .highlight .gd { color: #000000; background-color: #ffdddd }
|
||||
#template .highlight .gd .x { color: #000000; background-color: #ffaaaa }
|
||||
#template .highlight .ge { font-style: italic }
|
||||
#template .highlight .gr { color: #aa0000 }
|
||||
#template .highlight .gh { color: #999999 }
|
||||
#template .highlight .gi { color: #000000; background-color: #ddffdd }
|
||||
#template .highlight .gi .x { color: #000000; background-color: #aaffaa }
|
||||
#template .highlight .gc { color: #999; background-color: #EAF2F5 }
|
||||
#template .highlight .go { color: #888888 }
|
||||
#template .highlight .gp { color: #555555 }
|
||||
#template .highlight .gs { font-weight: bold }
|
||||
#template .highlight .gu { color: #aaaaaa }
|
||||
#template .highlight .gt { color: #aa0000 }
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
*, 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 */ }
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
width: 450px;
|
||||
|
||||
border: 7px solid #999;
|
||||
border: 7px solid rgba(0, 0, 0, 0.3);
|
||||
border: 7px solid rgba(0, 0, 0, 0.3);
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
@@ -28,7 +28,7 @@
|
||||
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);
|
||||
}
|
||||
@@ -71,7 +71,7 @@
|
||||
padding: 0;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
|
||||
#gollum-dialog-dialog-body fieldset .field input[type="text"] {
|
||||
border: 1px solid #ddd;
|
||||
display: block;
|
||||
@@ -82,11 +82,11 @@
|
||||
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;
|
||||
}
|
||||
@@ -30,8 +30,9 @@ a {
|
||||
-webkit-border-radius: 1em;
|
||||
}
|
||||
|
||||
.ff #gollum-editor,
|
||||
.ie #gollum-editor {
|
||||
padding-bottom: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
#gollum-editor form fieldset {
|
||||
@@ -51,9 +52,9 @@ a {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
color: #000;
|
||||
font-size: 1.3em;
|
||||
font-size: 1.1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.8em;
|
||||
line-height: 1.5em;
|
||||
margin: 1em 0 0.4em;
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
@@ -63,6 +64,12 @@ a {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#gollum-editor .path_note {
|
||||
text-align: right;
|
||||
font-size: small;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#gollum-editor-title-field input#gollum-editor-page-title {
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
@@ -119,11 +126,11 @@ a {
|
||||
/* 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);
|
||||
@@ -133,7 +140,7 @@ a {
|
||||
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);
|
||||
@@ -162,7 +169,7 @@ 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-help span { background-position: -405px 0; }
|
||||
|
||||
a#function-bold:hover span { background-position: 0 -28px; }
|
||||
a#function-italic:hover span { background-position: -27px -28px; }
|
||||
@@ -177,7 +184,7 @@ a#function-h2:hover span { background-position: -244px -28px; }
|
||||
a#function-h3:hover span { background-position: -271px -28px; }
|
||||
a#function-link:hover span { background-position: -298px -28px; }
|
||||
a#function-image:hover span { background-position: -324px -28px; }
|
||||
a#function-help:hover span { background-position: -405px -28px; }
|
||||
a#function-help:hover span { background-position: -405px -28px; }
|
||||
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar a.disabled {
|
||||
@@ -192,62 +199,54 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar #gollum-editor-format-selector {
|
||||
overflow: hidden;
|
||||
padding: 0 0 1.1em 0;
|
||||
padding: .2em 0 .5em 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector select {
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector select {
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid transparent;
|
||||
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
|
||||
float: right;
|
||||
font-size: 1.1em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
padding: 0.5em 0.7em;
|
||||
margin-bottom: 0;
|
||||
|
||||
|
||||
padding: 0.3em 0.4em;
|
||||
|
||||
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
-webkit-border-radius: 0.5em;
|
||||
-moz-outline: none;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector select:hover {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
-moz-outline: none;
|
||||
-webkit-border-radius: 0.5em;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector label {
|
||||
color: #999;
|
||||
float: right;
|
||||
font-size: 1.1em;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
line-height: 1.6em;
|
||||
padding: 0.6em 0.5em 0 0;
|
||||
padding: .3em 0.5em 0 0;
|
||||
}
|
||||
|
||||
|
||||
#gollum-editor #gollum-editor-function-bar
|
||||
#gollum-editor-format-selector label:after {
|
||||
#gollum-editor-format-selector label:after {
|
||||
content: ':';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* @section form-fields */
|
||||
|
||||
#gollum-editor textarea#gollum-editor-body {
|
||||
#gollum-editor textarea {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 1.3em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.8em;
|
||||
line-height: 1.4em;
|
||||
margin: 1em 0 0.4em;
|
||||
padding: 0.5em; /* I don't really like mixing pct & em here… */
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
height: 20em;
|
||||
}
|
||||
@@ -259,7 +258,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 1.2em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
@@ -301,7 +300,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
border-bottom: 1px solid #ddd;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding: 1em 0 0.5em;
|
||||
padding: 0.5em 0 0;
|
||||
}
|
||||
|
||||
#gollum-editor #gollum-editor-body + .collapsed,
|
||||
@@ -322,11 +321,11 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
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);
|
||||
@@ -337,16 +336,19 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
font-size: 1.6em;
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding: 0.4em 0 0 0.3em;
|
||||
padding: 0.15em 0 0 0.3em;
|
||||
text-shadow: 0 -1px 0 #fff;
|
||||
}
|
||||
#gollum-editor .collapsed h4 {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#gollum-editor .collapsed a.button:hover,
|
||||
#gollum-editor .expanded h4 a.button:hover {
|
||||
#gollum-editor .expanded a.button:hover {
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
|
||||
text-decoration: none;
|
||||
|
||||
|
||||
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);
|
||||
@@ -385,10 +387,10 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
border: 1px solid #ddd;
|
||||
clear: both;
|
||||
display: block;
|
||||
font-size: 1.3em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
height: 7em;
|
||||
line-height: 1.8em;
|
||||
line-height: 1.4em;
|
||||
margin: 0.7em 0;
|
||||
padding: 0.5em;
|
||||
width: 98%;
|
||||
@@ -403,7 +405,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
font-size: 1em;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
line-height: 1.2em;
|
||||
@@ -461,16 +463,16 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
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;
|
||||
@@ -478,7 +480,7 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
#gollum-editor-help-parent li a,
|
||||
#gollum-editor-help-list li a {
|
||||
border: 1px solid transparent;
|
||||
@@ -490,16 +492,16 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
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;
|
||||
@@ -507,29 +509,29 @@ a#function-help:hover span { background-position: -405px -28px; }
|
||||
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;
|
||||
@@ -0,0 +1,716 @@
|
||||
#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: 80%;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
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: 50px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.markdown-body h2 {
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
color: #000;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.markdown-body h3 {
|
||||
font-size: 18px;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.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 li,
|
||||
.markdown-body table,
|
||||
.markdown-body pre {
|
||||
margin: 15px 0;
|
||||
}
|
||||
.markdown-body hr {
|
||||
background: transparent url(../images/dirty-shade.png) repeat-x 0 0;
|
||||
border: 0 none;
|
||||
color: #ccc;
|
||||
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{
|
||||
margin-top: 30px;
|
||||
}
|
||||
.markdown-body h2+h3{
|
||||
margin-top: 10px;
|
||||
}
|
||||
.markdown-body a:first-child h1,
|
||||
.markdown-body a:first-child h2,
|
||||
.markdown-body a:first-child h3,
|
||||
.markdown-body a:first-child h4,
|
||||
.markdown-body a:first-child h5,
|
||||
.markdown-body a:first-child h6 {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.markdown-body h1+p,
|
||||
.markdown-body h2+p,
|
||||
.markdown-body h3+p,
|
||||
.markdown-body h4+p,
|
||||
.markdown-body h5+p,
|
||||
.markdown-body h6+p {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body li p.first {
|
||||
display: inline-block;
|
||||
}
|
||||
.markdown-body ul,
|
||||
.markdown-body ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
.markdown-body ul li>:first-child,
|
||||
.markdown-body ol li>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body ul li>:last-child,
|
||||
.markdown-body ol li>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body dl {
|
||||
padding: 0;
|
||||
}
|
||||
.markdown-body dl dt {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
padding: 0;
|
||||
margin: 15px 0 5px;
|
||||
}
|
||||
.markdown-body dl dt:first-child {
|
||||
padding: 0;
|
||||
}
|
||||
.markdown-body dl dt>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body dl dt>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body dl dd {
|
||||
margin: 0 0 15px;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.markdown-body dl dd>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body dl dd>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body blockquote {
|
||||
border-left: 4px solid #DDD;
|
||||
padding: 0 15px;
|
||||
color: #777;
|
||||
}
|
||||
.markdown-body blockquote>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.markdown-body blockquote>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body table {
|
||||
padding: 0;
|
||||
border-collapse: collapse;
|
||||
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;
|
||||
}
|
||||
|
After Width: | Height: | Size: 939 B |
|
After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 271 B |
|
After Width: | Height: | Size: 433 B |
|
After Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 376 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
@@ -24,7 +24,6 @@
|
||||
* You don't need to do anything. Just run this on DOM ready.
|
||||
*/
|
||||
$.GollumEditor = function( IncomingOptions ) {
|
||||
|
||||
ActiveOptions = $.extend( DefaultOptions, IncomingOptions );
|
||||
|
||||
debug('GollumEditor loading');
|
||||
@@ -62,8 +61,10 @@
|
||||
// get form fields
|
||||
var oldAction = $('#gollum-editor form').attr('action');
|
||||
var $form = $($('#gollum-editor form').get(0));
|
||||
$form.attr('action', '/preview');
|
||||
$form.attr('action', this.href || '/preview');
|
||||
$form.attr('target', '_blank');
|
||||
var paths = window.location.pathname.split('/');
|
||||
$form.attr('page', paths[ paths.length - 1 ] || '')
|
||||
$form.submit();
|
||||
|
||||
|
||||
@@ -94,11 +95,8 @@
|
||||
$('#gollum-editor-help').hide();
|
||||
$('#gollum-editor-help').removeClass('jaws');
|
||||
}
|
||||
|
||||
}
|
||||
// EditorHas.functionBar
|
||||
}
|
||||
// EditorHas.baseEditorMarkup
|
||||
} // EditorHas.functionBar
|
||||
} // EditorHas.baseEditorMarkup
|
||||
};
|
||||
|
||||
|
||||
@@ -154,7 +152,13 @@
|
||||
define: function( name, definitionObject ) {
|
||||
LanguageDefinition._ACTIVE_LANG = name;
|
||||
LanguageDefinition._LOADED_LANGS.push( name );
|
||||
LanguageDefinition._LANG[name] = definitionObject;
|
||||
if ( typeof $.GollumEditor.WikiLanguage == 'object' ) {
|
||||
var definition = {};
|
||||
$.extend(definition, $.GollumEditor.WikiLanguage, definitionObject);
|
||||
LanguageDefinition._LANG[name] = definition;
|
||||
} else {
|
||||
LanguageDefinition._LANG[name] = definitionObject;
|
||||
}
|
||||
},
|
||||
|
||||
getActiveLanguage: function() {
|
||||
@@ -162,6 +166,14 @@
|
||||
},
|
||||
|
||||
setActiveLanguage: function( name ) {
|
||||
// On first load _ACTIVE_LANG.length is 0 and evtChangeFormat isn't called.
|
||||
if ( LanguageDefinition._ACTIVE_LANG != null && LanguageDefinition._ACTIVE_LANG.length <= 0 ) {
|
||||
FormatSelector.updateCommitMessage( name );
|
||||
}
|
||||
|
||||
if(LanguageDefinition.getHookFunctionFor("deactivate")) {
|
||||
LanguageDefinition.getHookFunctionFor("deactivate")();
|
||||
}
|
||||
if ( !LanguageDefinition.isLoadedFor(name) ) {
|
||||
LanguageDefinition._ACTIVE_LANG = null;
|
||||
LanguageDefinition.loadFor( name, function(x, t) {
|
||||
@@ -180,13 +192,56 @@
|
||||
FormatSelector.updateSelected();
|
||||
}
|
||||
|
||||
if(LanguageDefinition.getHookFunctionFor("activate")) {
|
||||
LanguageDefinition.getHookFunctionFor("activate")();
|
||||
}
|
||||
|
||||
function hotkey( e, cmd ) {
|
||||
e.preventDefault();
|
||||
|
||||
var def = LanguageDefinition.getDefinitionFor( cmd );
|
||||
if ( typeof def == 'object' ) {
|
||||
FunctionBar.executeAction( def );
|
||||
}
|
||||
// Prevent bubbling of hotkey.
|
||||
return false;
|
||||
}
|
||||
|
||||
Mousetrap.bind(['command+1', 'ctrl+1'], function( e ){ hotkey( e, 'function-h1' ); });
|
||||
Mousetrap.bind(['command+2', 'ctrl+2'], function( e ){ hotkey( e, 'function-h2' ); });
|
||||
Mousetrap.bind(['command+3', 'ctrl+3'], function( e ){ hotkey( e, 'function-h3' ); });
|
||||
Mousetrap.bind(['command+b', 'ctrl+b'], function( e ){ hotkey( e, 'function-bold' ); });
|
||||
Mousetrap.bind(['command+i', 'ctrl+i'], function( e ){ hotkey( e, 'function-italic' ); });
|
||||
Mousetrap.bind(['command+s', 'ctrl+s'], function( e ){
|
||||
e.preventDefault();
|
||||
$("#gollum-editor-submit").trigger("click");
|
||||
return false;
|
||||
});
|
||||
|
||||
} );
|
||||
} else {
|
||||
LanguageDefinition._ACTIVE_LANG = name;
|
||||
FunctionBar.refresh();
|
||||
|
||||
if(LanguageDefinition.getHookFunctionFor("activate")) {
|
||||
LanguageDefinition.getHookFunctionFor("activate")();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getHookFunctionFor: function(attr, specified_lang) {
|
||||
if ( !specified_lang ) {
|
||||
specified_lang = LanguageDefinition._ACTIVE_LANG;
|
||||
}
|
||||
|
||||
if ( LanguageDefinition.isLoadedFor(specified_lang) &&
|
||||
LanguageDefinition._LANG[specified_lang][attr] &&
|
||||
typeof LanguageDefinition._LANG[specified_lang][attr] == 'function' ) {
|
||||
return LanguageDefinition._LANG[specified_lang][attr];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* gets a definition object for a specified attribute
|
||||
@@ -233,7 +288,7 @@
|
||||
}
|
||||
|
||||
// attempt to load the definition for this language
|
||||
var script_uri = '/javascript/editor/langs/' + markup_name + '.js';
|
||||
var script_uri = baseUrl + '/javascript/editor/langs/' + markup_name + '.js';
|
||||
$.ajax({
|
||||
url: script_uri,
|
||||
dataType: 'script',
|
||||
@@ -368,17 +423,6 @@
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* EditorHas.mathJax
|
||||
* True if the editor has MathJax enabled and running, false otherwise.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
mathJax: function() {
|
||||
return (typeof window.MathJax == 'object');
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* EditorHas.previewButton
|
||||
* True if the editor has a preview button, false otherwise.
|
||||
@@ -729,9 +773,18 @@
|
||||
*/
|
||||
evtChangeFormat: function( e ) {
|
||||
var newMarkup = $(this).val();
|
||||
FormatSelector.updateCommitMessage( newMarkup );
|
||||
LanguageDefinition.setActiveLanguage( newMarkup );
|
||||
},
|
||||
|
||||
updateCommitMessage: function( newMarkup ) {
|
||||
var msg = document.getElementById( "gollum-editor-message-field" );
|
||||
var val = msg.value;
|
||||
// Must start with created or updated.
|
||||
if (/^(?:created|updated)/i.test(val)) {
|
||||
msg.value = val.replace( /\([^\)]*\)$/, "(" + newMarkup + ")" );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* FormatSelector.init
|
||||
@@ -776,226 +829,216 @@
|
||||
var Help = {
|
||||
|
||||
_ACTIVE_HELP: '',
|
||||
_LOADED_HELP_LANGS: [],
|
||||
_HELP: {},
|
||||
_LOADED_HELP_LANGS: [],
|
||||
_HELP: {},
|
||||
|
||||
/**
|
||||
* Help.define
|
||||
*
|
||||
* Defines a new help context and enables the help function if it
|
||||
* exists in the Gollum Function Bar.
|
||||
*
|
||||
* @param string name The name you're giving to this help context.
|
||||
* Generally, this should match the language name.
|
||||
* @param object definitionObject The definition object being loaded from a
|
||||
* language / help definition file.
|
||||
* @return void
|
||||
*/
|
||||
define: function( name, definitionObject ) {
|
||||
if ( Help.isValidHelpFormat( definitionObject ) ) {
|
||||
debug('help is a valid format');
|
||||
|
||||
Help._ACTIVE_HELP_LANG = name;
|
||||
Help._LOADED_HELP_LANGS.push( name );
|
||||
Help._HELP[name] = definitionObject;
|
||||
|
||||
if ( $("#function-help").length ) {
|
||||
if ( $('#function-help').hasClass('disabled') ) {
|
||||
$('#function-help').removeClass('disabled');
|
||||
}
|
||||
$('#function-help').unbind('click');
|
||||
$('#function-help').click( Help.evtHelpButtonClick );
|
||||
|
||||
// generate help menus
|
||||
Help.generateHelpMenuFor( name );
|
||||
|
||||
if ( $('#gollum-editor-help').length &&
|
||||
typeof $('#gollum-editor-help').attr('data-autodisplay') !== 'undefined' &&
|
||||
$('#gollum-editor-help').attr('data-autodisplay') === 'true' ) {
|
||||
Help.show();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( $('#function-help').length ) {
|
||||
$('#function-help').addClass('disabled');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Help.generateHelpMenuFor
|
||||
* Generates the markup for the main help menu given a context name.
|
||||
*
|
||||
* @param string name The context name.
|
||||
* @return void
|
||||
*/
|
||||
generateHelpMenuFor: function( name ) {
|
||||
if ( !Help._HELP[name] ) {
|
||||
debug('Help is not defined for ' + name.toString());
|
||||
return false;
|
||||
}
|
||||
var helpData = Help._HELP[name];
|
||||
|
||||
// clear this shiz out
|
||||
$('#gollum-editor-help-parent').html('');
|
||||
$('#gollum-editor-help-list').html('');
|
||||
$('#gollum-editor-help-content').html('');
|
||||
|
||||
// go go inefficient algorithm
|
||||
for ( var i=0; i < helpData.length; i++ ) {
|
||||
if ( typeof helpData[i] != 'object' ) {
|
||||
break;
|
||||
}
|
||||
|
||||
var $newLi = $('<li><a href="#" rel="' + i + '">' +
|
||||
helpData[i].menuName + '</a></li>');
|
||||
$('#gollum-editor-help-parent').append( $newLi );
|
||||
if ( i === 0 ) {
|
||||
// select on first run
|
||||
$newLi.children('a').addClass('selected');
|
||||
}
|
||||
$newLi.children('a').click( Help.evtParentMenuClick );
|
||||
}
|
||||
|
||||
// generate parent submenu on first run
|
||||
Help.generateSubMenu( helpData[0], 0 );
|
||||
$($('#gollum-editor-help-list li a').get(0)).click();
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Help.generateSubMenu
|
||||
* Generates the markup for the inline help sub-menu given the data
|
||||
* object for the submenu and the array index to start at.
|
||||
*
|
||||
* @param object subData The data for the sub-menu.
|
||||
* @param integer index The index clicked on (parent menu index).
|
||||
* @return void
|
||||
*/
|
||||
generateSubMenu: function( subData, index ) {
|
||||
$('#gollum-editor-help-list').html('');
|
||||
$('#gollum-editor-help-content').html('');
|
||||
for ( var i=0; i < subData.content.length; i++ ) {
|
||||
if ( typeof subData.content[i] != 'object' ) {
|
||||
break;
|
||||
}
|
||||
|
||||
var $subLi = $('<li><a href="#" rel="' + index + ':' + i + '">' +
|
||||
subData.content[i].menuName + '</a></li>');
|
||||
|
||||
|
||||
/**
|
||||
* Help.define
|
||||
*
|
||||
* Defines a new help context and enables the help function if it
|
||||
* exists in the Gollum Function Bar.
|
||||
*
|
||||
* @param string name The name you're giving to this help context.
|
||||
* Generally, this should match the language name.
|
||||
* @param object definitionObject The definition object being loaded from a
|
||||
* language / help definition file.
|
||||
* @return void
|
||||
*/
|
||||
define: function( name, definitionObject ) {
|
||||
if ( Help.isValidHelpFormat( definitionObject ) ) {
|
||||
debug('help is a valid format');
|
||||
$('#gollum-editor-help-list').append( $subLi );
|
||||
$subLi.children('a').click( Help.evtSubMenuClick );
|
||||
}
|
||||
},
|
||||
|
||||
Help._ACTIVE_HELP_LANG = name;
|
||||
Help._LOADED_HELP_LANGS.push( name );
|
||||
Help._HELP[name] = definitionObject;
|
||||
hide: function() {
|
||||
if ( $.browser.msie ) {
|
||||
$('#gollum-editor-help').css('display', 'none');
|
||||
} else {
|
||||
$('#gollum-editor-help').animate({
|
||||
opacity: 0
|
||||
}, 200, function() {
|
||||
$('#gollum-editor-help')
|
||||
.animate({ height: 'hide' }, 200);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
if ( $("#function-help").length ) {
|
||||
if ( $('#function-help').hasClass('disabled') ) {
|
||||
$('#function-help').removeClass('disabled');
|
||||
}
|
||||
$('#function-help').unbind('click');
|
||||
$('#function-help').click( Help.evtHelpButtonClick );
|
||||
show: function() {
|
||||
if ( $.browser.msie ) {
|
||||
// bypass effects for internet explorer, since it does weird crap
|
||||
// to text antialiasing with opacity animations
|
||||
$('#gollum-editor-help').css('display', 'block');
|
||||
} else {
|
||||
$('#gollum-editor-help').animate({
|
||||
height: 'show'
|
||||
}, 200, function() {
|
||||
$('#gollum-editor-help')
|
||||
.animate({ opacity: 1 }, 300);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// generate help menus
|
||||
Help.generateHelpMenuFor( name );
|
||||
}
|
||||
} else {
|
||||
if ( $('#function-help').length ) {
|
||||
$('#function-help').addClass('disabled');
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Help.showHelpFor
|
||||
* Displays the actual help content given the two menu indexes, which are
|
||||
* rendered in the rel="" attributes of the help menus
|
||||
*
|
||||
* @param integer index1 parent index
|
||||
* @param integer index2 submenu index
|
||||
* @return void
|
||||
*/
|
||||
showHelpFor: function( index1, index2 ) {
|
||||
var html =
|
||||
Help._HELP[Help._ACTIVE_HELP_LANG][index1].content[index2].data;
|
||||
$('#gollum-editor-help-content').html(html);
|
||||
},
|
||||
|
||||
/**
|
||||
* Help.isLoadedFor
|
||||
* Returns true if help is loaded for a specific markup language,
|
||||
* false otherwise.
|
||||
*
|
||||
* @param string name The name of the markup language.
|
||||
* @return boolean
|
||||
*/
|
||||
isLoadedFor: function( name ) {
|
||||
for ( var i=0; i < Help._LOADED_HELP_LANGS.length; i++ ) {
|
||||
if ( name == Help._LOADED_HELP_LANGS[i] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Help.generateHelpMenuFor
|
||||
* Generates the markup for the main help menu given a context name.
|
||||
*
|
||||
* @param string name The context name.
|
||||
* @return void
|
||||
*/
|
||||
generateHelpMenuFor: function( name ) {
|
||||
if ( !Help._HELP[name] ) {
|
||||
debug('Help is not defined for ' + name.toString());
|
||||
return false;
|
||||
}
|
||||
var helpData = Help._HELP[name];
|
||||
isShown: function() {
|
||||
return ($('#gollum-editor-help').is(':visible'));
|
||||
},
|
||||
|
||||
if ( EditorHas.mathJax() && Help.isLoadedFor('mathjax') ) {
|
||||
debug('Adding MathJax support to help');
|
||||
// TODO
|
||||
}
|
||||
/**
|
||||
* Help.isValidHelpFormat
|
||||
* Does a quick check to make sure that the help definition isn't in a
|
||||
* completely messed-up format.
|
||||
*
|
||||
* @param object (Array) helpArr The help definition array.
|
||||
* @return boolean
|
||||
*/
|
||||
isValidHelpFormat: function( helpArr ) {
|
||||
return ( typeof helpArr == 'object' &&
|
||||
helpArr.length &&
|
||||
typeof helpArr[0].menuName == 'string' &&
|
||||
typeof helpArr[0].content == 'object' &&
|
||||
helpArr[0].content.length );
|
||||
},
|
||||
|
||||
// clear this shiz out
|
||||
$('#gollum-editor-help-parent').html('');
|
||||
$('#gollum-editor-help-list').html('');
|
||||
$('#gollum-editor-help-content').html('');
|
||||
|
||||
// go go inefficient algorithm
|
||||
for ( var i=0; i < helpData.length; i++ ) {
|
||||
if ( typeof helpData[i] != 'object' ) {
|
||||
break;
|
||||
}
|
||||
|
||||
var $newLi = $('<li><a href="#" rel="' + i + '">' +
|
||||
helpData[i].menuName + '</a></li>');
|
||||
$('#gollum-editor-help-parent').append( $newLi );
|
||||
if ( i === 0 ) {
|
||||
// select on first run
|
||||
$newLi.children('a').addClass('selected');
|
||||
}
|
||||
$newLi.children('a').click( Help.evtParentMenuClick );
|
||||
}
|
||||
|
||||
// generate parent submenu on first run
|
||||
Help.generateSubMenu( helpData[0], 0 );
|
||||
$($('#gollum-editor-help-list li a').get(0)).click();
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Help.generateSubMenu
|
||||
* Generates the markup for the inline help sub-menu given the data
|
||||
* object for the submenu and the array index to start at.
|
||||
*
|
||||
* @param object subData The data for the sub-menu.
|
||||
* @param integer index The index clicked on (parent menu index).
|
||||
* @return void
|
||||
*/
|
||||
generateSubMenu: function( subData, index ) {
|
||||
$('#gollum-editor-help-list').html('');
|
||||
$('#gollum-editor-help-content').html('');
|
||||
for ( var i=0; i < subData.content.length; i++ ) {
|
||||
if ( typeof subData.content[i] != 'object' ) {
|
||||
break;
|
||||
}
|
||||
|
||||
var $subLi = $('<li><a href="#" rel="' + index + ':' + i + '">' +
|
||||
subData.content[i].menuName + '</a></li>');
|
||||
|
||||
|
||||
$('#gollum-editor-help-list').append( $subLi );
|
||||
$subLi.children('a').click( Help.evtSubMenuClick );
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
hide: function() {
|
||||
if ( $.browser.msie ) {
|
||||
$('#gollum-editor-help').css('display', 'none');
|
||||
} else {
|
||||
$('#gollum-editor-help').animate({
|
||||
opacity: 0
|
||||
}, 200,
|
||||
function() {
|
||||
$('#gollum-editor-help')
|
||||
.animate({ height: 'hide' }, 200);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if ( $.browser.msie ) {
|
||||
// bypass effects for internet explorer, since it does weird crap
|
||||
// to text antialiasing with opacity animations
|
||||
$('#gollum-editor-help').css('display', 'block');
|
||||
} else {
|
||||
$('#gollum-editor-help').animate({
|
||||
height: 'show'
|
||||
}, 200,
|
||||
function() {
|
||||
$('#gollum-editor-help')
|
||||
.animate({ opacity: 1 }, 300);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Help.showHelpFor
|
||||
* Displays the actual help content given the two menu indexes, which are
|
||||
* rendered in the rel="" attributes of the help menus
|
||||
*
|
||||
* @param integer index1 parent index
|
||||
* @param integer index2 submenu index
|
||||
* @return void
|
||||
*/
|
||||
showHelpFor: function( index1, index2 ) {
|
||||
var html =
|
||||
Help._HELP[Help._ACTIVE_HELP_LANG][index1].content[index2].data;
|
||||
$('#gollum-editor-help-content').html(html);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Help.isLoadedFor
|
||||
* Returns true if help is loaded for a specific markup language,
|
||||
* false otherwise.
|
||||
*
|
||||
* @param string name The name of the markup language.
|
||||
* @return boolean
|
||||
*/
|
||||
isLoadedFor: function( name ) {
|
||||
for ( var i=0; i < Help._LOADED_HELP_LANGS.length; i++ ) {
|
||||
if ( name == Help._LOADED_HELP_LANGS[i] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
isShown: function() {
|
||||
return ( $('#gollum-editor-help').is(':visible') );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Help.isValidHelpFormat
|
||||
* Does a quick check to make sure that the help definition isn't in a
|
||||
* completely messed-up format.
|
||||
*
|
||||
* @param object (Array) helpArr The help definition array.
|
||||
* @return boolean
|
||||
*/
|
||||
isValidHelpFormat: function( helpArr ) {
|
||||
return ( typeof helpArr == 'object' &&
|
||||
helpArr.length &&
|
||||
typeof helpArr[0].menuName == 'string' &&
|
||||
typeof helpArr[0].content == 'object' &&
|
||||
helpArr[0].content.length );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Help.setActiveHelp
|
||||
* Sets the active help definition to the one defined in the argument,
|
||||
* re-rendering the help menu to match the new definition.
|
||||
*
|
||||
* @param string name The name of the help definition.
|
||||
* @return void
|
||||
*/
|
||||
setActiveHelp: function( name ) {
|
||||
if ( !Help.isLoadedFor( name ) ) {
|
||||
if ( $('#function-help').length ) {
|
||||
$('#function-help').addClass('disabled');
|
||||
}
|
||||
if ( Help.isShown() ) {
|
||||
Help.hide();
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Help.setActiveHelp
|
||||
* Sets the active help definition to the one defined in the argument,
|
||||
* re-rendering the help menu to match the new definition.
|
||||
*
|
||||
* @param string name The name of the help definition.
|
||||
* @return void
|
||||
*/
|
||||
setActiveHelp: function( name ) {
|
||||
if ( !Help.isLoadedFor( name ) ) {
|
||||
if ( $('#function-help').length ) {
|
||||
$('#function-help').addClass('disabled');
|
||||
}
|
||||
if ( Help.isShown() ) {
|
||||
Help.hide();
|
||||
}
|
||||
} else {
|
||||
Help._ACTIVE_HELP_LANG = name;
|
||||
if ( $("#function-help").length ) {
|
||||
if ( $('#function-help').hasClass('disabled') ) {
|
||||
@@ -1005,80 +1048,84 @@
|
||||
$('#function-help').click( Help.evtHelpButtonClick );
|
||||
Help.generateHelpMenuFor( name );
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Help.evtHelpButtonClick
|
||||
* Event handler for clicking the help button in the function bar.
|
||||
*
|
||||
* @param jQuery.Event e The jQuery event object.
|
||||
* @return void
|
||||
*/
|
||||
evtHelpButtonClick: function( e ) {
|
||||
e.preventDefault();
|
||||
if ( Help.isShown() ) {
|
||||
// turn off autodisplay if it's on
|
||||
if ( $('#gollum-editor-help').length &&
|
||||
$('#gollum-editor-help').attr('data-autodisplay') !== 'undefined' &&
|
||||
$('#gollum-editor-help').attr('data-autodisplay') === 'true' ) {
|
||||
$.post('/wiki/help?_method=delete');
|
||||
$('#gollum-editor-help').attr('data-autodisplay', '');
|
||||
}
|
||||
Help.hide(); }
|
||||
else { Help.show(); }
|
||||
},
|
||||
|
||||
/**
|
||||
* Help.evtHelpButtonClick
|
||||
* Event handler for clicking the help button in the function bar.
|
||||
*
|
||||
* @param jQuery.Event e The jQuery event object.
|
||||
* @return void
|
||||
*/
|
||||
evtHelpButtonClick: function( e ) {
|
||||
e.preventDefault();
|
||||
if ( Help.isShown() ) { Help.hide(); }
|
||||
else { Help.show(); }
|
||||
},
|
||||
/**
|
||||
* Help.evtParentMenuClick
|
||||
* Event handler for clicking on an item in the parent menu. Automatically
|
||||
* renders the submenu for the parent menu as well as the first result for
|
||||
* the actual plain text.
|
||||
*
|
||||
* @param jQuery.Event e The jQuery event object.
|
||||
* @return void
|
||||
*/
|
||||
evtParentMenuClick: function( e ) {
|
||||
e.preventDefault();
|
||||
// short circuit if we've selected this already
|
||||
if ( $(this).hasClass('selected') ) { return; }
|
||||
|
||||
// populate from help data for this
|
||||
var helpIndex = $(this).attr('rel');
|
||||
var subData = Help._HELP[Help._ACTIVE_HELP_LANG][helpIndex];
|
||||
|
||||
/**
|
||||
* Help.evtParentMenuClick
|
||||
* Event handler for clicking on an item in the parent menu. Automatically
|
||||
* renders the submenu for the parent menu as well as the first result for
|
||||
* the actual plain text.
|
||||
*
|
||||
* @param jQuery.Event e The jQuery event object.
|
||||
* @return void
|
||||
*/
|
||||
evtParentMenuClick: function( e ) {
|
||||
e.preventDefault();
|
||||
// short circuit if we've selected this already
|
||||
if ( $(this).hasClass('selected') ) { return; }
|
||||
$('#gollum-editor-help-parent li a').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
Help.generateSubMenu( subData, helpIndex );
|
||||
$($('#gollum-editor-help-list li a').get(0)).click();
|
||||
},
|
||||
|
||||
// populate from help data for this
|
||||
var helpIndex = $(this).attr('rel');
|
||||
var subData = Help._HELP[Help._ACTIVE_HELP_LANG][helpIndex];
|
||||
/**
|
||||
* Help.evtSubMenuClick
|
||||
* Event handler for clicking an item in a help submenu. Renders the
|
||||
* appropriate text for the submenu link.
|
||||
*
|
||||
* @param jQuery.Event e The jQuery event object.
|
||||
* @return void
|
||||
*/
|
||||
evtSubMenuClick: function( e ) {
|
||||
e.preventDefault();
|
||||
if ( $(this).hasClass('selected') ) { return; }
|
||||
|
||||
$('#gollum-editor-help-parent li a').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
Help.generateSubMenu( subData, helpIndex );
|
||||
$($('#gollum-editor-help-list li a').get(0)).click();
|
||||
},
|
||||
// split index rel data
|
||||
var rawIndex = $(this).attr('rel').split(':');
|
||||
$('#gollum-editor-help-list li a').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
Help.showHelpFor( rawIndex[0], rawIndex[1] );
|
||||
}
|
||||
};
|
||||
|
||||
// Publicly-accessible function to Help.define
|
||||
$.GollumEditor.defineHelp = Help.define;
|
||||
|
||||
/**
|
||||
* Help.evtSubMenuClick
|
||||
* Event handler for clicking an item in a help submenu. Renders the
|
||||
* appropriate text for the submenu link.
|
||||
*
|
||||
* @param jQuery.Event e The jQuery event object.
|
||||
* @return void
|
||||
*/
|
||||
evtSubMenuClick: function( e ) {
|
||||
e.preventDefault();
|
||||
if ( $(this).hasClass('selected') ) { return; }
|
||||
// Dialog exists as its own thing now
|
||||
$.GollumEditor.Dialog = $.GollumDialog;
|
||||
$.GollumEditor.replaceSelection = function( repText ) {
|
||||
FunctionBar.replaceFieldSelection( $('#gollum-editor-body'), repText );
|
||||
};
|
||||
|
||||
// split index rel data
|
||||
var rawIndex = $(this).attr('rel').split(':');
|
||||
$('#gollum-editor-help-list li a').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
Help.showHelpFor( rawIndex[0], rawIndex[1] );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Publicly-accessible function to Help.define
|
||||
$.GollumEditor.defineHelp = Help.define;
|
||||
|
||||
// Dialog exists as its own thing now
|
||||
$.GollumEditor.Dialog = $.GollumDialog;
|
||||
$.GollumEditor.replaceSelection = function( repText ) {
|
||||
FunctionBar.replaceFieldSelection( $('#gollum-editor-body'), repText );
|
||||
};
|
||||
|
||||
// Placeholder exists as its own thing now
|
||||
$.GollumEditor.Placeholder = $.GollumPlaceholder;
|
||||
// Placeholder exists as its own thing now
|
||||
$.GollumEditor.Placeholder = $.GollumPlaceholder;
|
||||
|
||||
})(jQuery);
|
||||
@@ -3,40 +3,40 @@
|
||||
*
|
||||
*/
|
||||
|
||||
(function() {
|
||||
(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' : {
|
||||
|
||||
'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;
|
||||
@@ -47,7 +47,8 @@ var ASCIIDoc = {
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
help: 'The text to display to the user.'
|
||||
help: 'The text to display to the user.',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
@@ -59,17 +60,17 @@ var ASCIIDoc = {
|
||||
OK: function( res ) {
|
||||
var h = '';
|
||||
if ( res['text'] && res['href'] ) {
|
||||
h = res['href'] + '[' +
|
||||
h = res['href'] + '[' +
|
||||
res['text'] + ']';
|
||||
}
|
||||
$.GollumEditor.replaceSelection( h );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'function-image' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
@@ -98,10 +99,10 @@ var ASCIIDoc = {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
jQuery.GollumEditor.defineLanguage('asciidoc', ASCIIDoc);
|
||||
$.GollumEditor.defineLanguage('asciidoc', ASCIIDoc);
|
||||
|
||||
|
||||
var ASCIIDocHelp = [
|
||||
@@ -158,11 +159,10 @@ var ASCIIDocHelp = [
|
||||
menuName: 'Images',
|
||||
data: '<p>Images in ASCIIDoc work much like hyperlinks, but image URLs are prefixed with <code>image:</code>. For example, to link to an image at <code>images/icons/home.png</code>, write <code>image:images/icons/home.png</code>. Alt text can be added by appending the text to the URI in <code>[</code> (brackets).</p>'
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
jQuery.GollumEditor.defineHelp('asciidoc', ASCIIDocHelp);
|
||||
|
||||
})();
|
||||
$.GollumEditor.defineHelp('asciidoc', ASCIIDocHelp);
|
||||
|
||||
})(jQuery);
|
||||
@@ -2,40 +2,40 @@
|
||||
* Creole Language Definition
|
||||
*
|
||||
*/
|
||||
(function() {
|
||||
(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";
|
||||
append: "\n\n----\n\n"
|
||||
},
|
||||
|
||||
'function-ul' : {
|
||||
|
||||
'function-ul' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
/* This looks silly but is completely valid Markdown */
|
||||
|
||||
/* 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;
|
||||
@@ -46,7 +46,8 @@ var Creole = {
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
help: 'The text to display to the user.'
|
||||
help: 'The text to display to the user.',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
@@ -56,16 +57,16 @@ var Creole = {
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var h = '[[' + res['href'] + '|' +
|
||||
var h = '[[' + res['href'] + '|' +
|
||||
res['text'] + ']]';
|
||||
$.GollumEditor.replaceSelection( h );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'function-image' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
@@ -84,8 +85,9 @@ var Creole = {
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var h = '';
|
||||
if ( res['url'] && res['alt'] ) {
|
||||
var h = '{{' + res['url'];
|
||||
h = '{{' + res['url'];
|
||||
if ( res['alt'] != '' ) {
|
||||
h += '|' + res['alt'] + '}}';
|
||||
}
|
||||
@@ -95,9 +97,9 @@ var Creole = {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
jQuery.GollumEditor.defineLanguage('creole', Creole);
|
||||
$.GollumEditor.defineLanguage('creole', Creole);
|
||||
|
||||
})();
|
||||
})(jQuery);
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Markdown Language Definition
|
||||
*
|
||||
* A language definition for string manipulation operations, in this case
|
||||
*
|
||||
* 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
|
||||
* 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:
|
||||
@@ -14,63 +14,74 @@
|
||||
* search: /somesearchregex/gi,
|
||||
* replace: 'replace text for RegExp.replace',
|
||||
* append: "just add this where the cursor is"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
**/
|
||||
(function() {
|
||||
(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,
|
||||
search: /([^\n]+)([\n\s]*)/g,
|
||||
replace: "`$1`$2"
|
||||
},
|
||||
|
||||
|
||||
'function-hr' : {
|
||||
append: "\n***\n"
|
||||
},
|
||||
|
||||
'function-ul' : {
|
||||
|
||||
'function-ul' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
/* This looks silly but is completely valid Markdown */
|
||||
/* based on rdoc.js */
|
||||
'function-ol' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "1. $1$2"
|
||||
exec: function( txt, selText, $field ) {
|
||||
var count = 1;
|
||||
// split into lines
|
||||
var repText = '';
|
||||
var lines = selText.split("\n");
|
||||
var hasContent = /[\w]+/;
|
||||
for ( var i = 0; i < lines.length; i++ ) {
|
||||
if ( hasContent.test(lines[i]) ) {
|
||||
repText += (i + 1).toString() + '. ' +
|
||||
lines[i] + "\n";
|
||||
}
|
||||
}
|
||||
$.GollumEditor.replaceSelection( repText );
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'function-blockquote' : {
|
||||
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;
|
||||
@@ -80,7 +91,8 @@ var MarkDown = {
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
@@ -91,15 +103,15 @@ var MarkDown = {
|
||||
OK: function( res ) {
|
||||
var rep = '';
|
||||
if ( res['text'] && res['href'] ) {
|
||||
rep = '[' + res['text'] + ']('
|
||||
+ res['href'] + ')';
|
||||
rep = '[' + res['text'] + '](' +
|
||||
res['href'] + ')';
|
||||
}
|
||||
$.GollumEditor.replaceSelection( rep );
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'function-image' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
@@ -128,7 +140,7 @@ var MarkDown = {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
var MarkDownHelp = [
|
||||
@@ -162,7 +174,7 @@ var MarkDownHelp = [
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
menuName: 'Span Elements',
|
||||
content: [
|
||||
@@ -170,24 +182,24 @@ var MarkDownHelp = [
|
||||
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: [
|
||||
@@ -195,7 +207,7 @@ var MarkDownHelp = [
|
||||
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.'
|
||||
@@ -205,7 +217,7 @@ var MarkDownHelp = [
|
||||
];
|
||||
|
||||
|
||||
jQuery.GollumEditor.defineLanguage('markdown', MarkDown);
|
||||
jQuery.GollumEditor.defineHelp('markdown', MarkDownHelp);
|
||||
$.GollumEditor.defineLanguage('markdown', MarkDown);
|
||||
$.GollumEditor.defineHelp('markdown', MarkDownHelp);
|
||||
|
||||
})();
|
||||
})(jQuery);
|
||||
@@ -1,36 +1,36 @@
|
||||
/**
|
||||
* Org-mode Language Definition
|
||||
**/
|
||||
(function() {
|
||||
(function($) {
|
||||
|
||||
var OrgMode = {
|
||||
|
||||
|
||||
'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' : {
|
||||
|
||||
'function-ul' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
/* This works, just like it works for Markdown */
|
||||
|
||||
/* This works, just like it works for Markdown */
|
||||
'function-ol' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "1. $1$2"
|
||||
},
|
||||
|
||||
|
||||
'function-blockquote' : {
|
||||
search: /(.+)([\n]?)/g,
|
||||
replace: "#+BEGIN_QUOTE\n$1$2\n#+END_QUOTE\n"
|
||||
@@ -40,17 +40,17 @@ var OrgMode = {
|
||||
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;
|
||||
@@ -60,7 +60,8 @@ var OrgMode = {
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
@@ -71,18 +72,18 @@ var OrgMode = {
|
||||
OK: function( res ) {
|
||||
var rep = '';
|
||||
if ( res['text'] && res['href'] ) {
|
||||
rep = '[[' + res['href'] + ']['
|
||||
+ res['text'] + ']]';
|
||||
rep = '[[' + res['href'] + '][' +
|
||||
res['text'] + ']]';
|
||||
}
|
||||
else if ( res['href'] ) {
|
||||
rep = '[[' + res['href'] + ']]';
|
||||
}
|
||||
$.GollumEditor.replaceSelection( rep );
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'function-image' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
@@ -93,7 +94,7 @@ var OrgMode = {
|
||||
id: 'url',
|
||||
name: 'Image URL',
|
||||
type: 'text'
|
||||
},
|
||||
}
|
||||
],
|
||||
OK: function( res ) {
|
||||
var rep = '';
|
||||
@@ -105,7 +106,7 @@ var OrgMode = {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
var OrgModeHelp = [
|
||||
@@ -136,10 +137,10 @@ var OrgModeHelp = [
|
||||
{
|
||||
menuName: 'Tables',
|
||||
data: '<p>Org-mode supports simple tables (tables with equal number of cells in each row). To create a simple table, just separate the contents of each cell with a <code>|</code> character. For example, <br><br><code>|one|two|three|<br>|four|five|six|</code><br><br> will appear as a table with two rows and three columns. Additionally, <br><br><code>|one|two|three|<br>|---+---+-----|<br>|four|five|six|</code><br><br> will also appear as a table, but the first row will be interpreted as a header row and the <code><th></code> tag will be used to render it. </p>'
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
menuName: 'Span Elements',
|
||||
content: [
|
||||
@@ -147,27 +148,27 @@ var OrgModeHelp = [
|
||||
menuName: 'Links',
|
||||
data: '<p>To create links to external pages, you need to enclose the URI in double square brackets. (i.e., <code>[[http://github.com/]]</code> will automatically be parsed to <a href="javascript:void(0);">http://github.com/</a>)If you want to add text, to be displayed to the user, you write the URI and the text next to each other, both enclosed in square brackets and both of them together enclosed in another pair of square brackets. For example, if you want your link to display the text “GitHub”, you write <code>[[http://github.com][GitHub]]</code>.</p>'
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
menuName: 'Emphasis',
|
||||
data: '<p>Forward slashes (<code>/</code>) are treated as emphasis and are wrapped with an <code><i></code> tag. Asterisks (<code>*</code>) are treated as bold using the <code><b></code> tag.</p>'
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
menuName: 'Code',
|
||||
data: '<p>To create inline spans of code, simply wrap the code in equal signs (<code>=</code>). Orgmode will turn <code>=myFunction=</code> into <code>myFunction</code>.</p>'
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
menuName: 'Images',
|
||||
data: "<p>Org-mode image syntax is exactly same as the syntax that you would use for a URI to link to itself. The image URI is enclosed in double square brackets. Alt text on images is not currently supported by Gollum's Org-mode parser.</p>"
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
jQuery.GollumEditor.defineLanguage('org', OrgMode);
|
||||
jQuery.GollumEditor.defineHelp('org', OrgModeHelp);
|
||||
$.GollumEditor.defineLanguage('org', OrgMode);
|
||||
$.GollumEditor.defineHelp('org', OrgModeHelp);
|
||||
|
||||
})();
|
||||
})(jQuery);
|
||||
@@ -1,40 +1,40 @@
|
||||
/**
|
||||
* Pod Language Definition
|
||||
**/
|
||||
(function() {
|
||||
(function($) {
|
||||
|
||||
var Pod = {
|
||||
|
||||
|
||||
'function-bold' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "B<$1>$2"
|
||||
},
|
||||
|
||||
|
||||
'function-italic' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "I<$1>$2"
|
||||
},
|
||||
|
||||
|
||||
'function-code' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "C<$1>$2"
|
||||
},
|
||||
|
||||
|
||||
'function-h1' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "=head1 $1$2"
|
||||
},
|
||||
|
||||
|
||||
'function-h2' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "=head2 $1$2"
|
||||
},
|
||||
|
||||
|
||||
'function-h3' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "=head3 $1$2"
|
||||
},
|
||||
|
||||
|
||||
'function-link' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
@@ -44,7 +44,8 @@ var Pod = {
|
||||
{
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
@@ -55,18 +56,18 @@ var Pod = {
|
||||
OK: function( res ) {
|
||||
var rep = '';
|
||||
if ( res['text'] && res['href'] ) {
|
||||
rep = 'L<' + res['text'] + '|'
|
||||
+ res['href'] + '>';
|
||||
rep = 'L<' + res['text'] + '|' +
|
||||
res['href'] + '>';
|
||||
}
|
||||
$.GollumEditor.replaceSelection( rep );
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
jQuery.GollumEditor.defineLanguage('pod', Pod);
|
||||
$.GollumEditor.defineLanguage('pod', Pod);
|
||||
|
||||
|
||||
var PodHelp = [
|
||||
@@ -106,6 +107,6 @@ var PodHelp = [
|
||||
}
|
||||
];
|
||||
|
||||
jQuery.GollumEditor.defineHelp('pod', PodHelp);
|
||||
$.GollumEditor.defineHelp('pod', PodHelp);
|
||||
|
||||
})();
|
||||
})(jQuery);
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Markdown Language Definition
|
||||
*
|
||||
* A language definition for string manipulation operations, in this case
|
||||
*
|
||||
* 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
|
||||
* 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:
|
||||
@@ -14,27 +14,27 @@
|
||||
* search: /somesearchregex/gi,
|
||||
* replace: 'replace text for RegExp.replace',
|
||||
* append: "just add this where the cursor is"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
**/
|
||||
(function() {
|
||||
(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' : {
|
||||
|
||||
'function-ul' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
|
||||
'function-ol' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var count = 1;
|
||||
@@ -51,24 +51,24 @@ var RDoc = {
|
||||
$.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"
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
jQuery.GollumEditor.defineLanguage('rdoc', RDoc);
|
||||
$.GollumEditor.defineLanguage('rdoc', RDoc);
|
||||
|
||||
})();
|
||||
})(jQuery);
|
||||
@@ -1,44 +1,44 @@
|
||||
/**
|
||||
* Textile Language Definition
|
||||
*/
|
||||
(function() {
|
||||
(function($) {
|
||||
|
||||
var Textile = {
|
||||
|
||||
|
||||
'function-bold' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "*$1*$2"
|
||||
},
|
||||
|
||||
|
||||
'function-italic' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "_$1_$2"
|
||||
},
|
||||
|
||||
|
||||
'function-hr' : {
|
||||
append: "\n***\n"
|
||||
},
|
||||
|
||||
|
||||
'function-code' : {
|
||||
search: /(^[\n]+)([\n\s]*)/g,
|
||||
replace: "<pre><code>$1</code></pre>$2"
|
||||
},
|
||||
|
||||
'function-ul' : {
|
||||
|
||||
'function-ul' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "* $1$2"
|
||||
},
|
||||
|
||||
|
||||
'function-ol' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "# $1$2"
|
||||
},
|
||||
|
||||
|
||||
'function-blockquote' : {
|
||||
search: /(.+)([\n]?)/gi,
|
||||
replace: "bq. $1$2"
|
||||
},
|
||||
|
||||
|
||||
'function-link' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
@@ -49,7 +49,8 @@ var Textile = {
|
||||
id: 'text',
|
||||
name: 'Link Text',
|
||||
type: 'text',
|
||||
help: 'The text to display to the user.'
|
||||
help: 'The text to display to the user.',
|
||||
defaultValue: selText
|
||||
},
|
||||
{
|
||||
id: 'href',
|
||||
@@ -67,11 +68,11 @@ var Textile = {
|
||||
$.GollumEditor.replaceSelection( h );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'function-image' : {
|
||||
exec: function( txt, selText, $field ) {
|
||||
var results = null;
|
||||
@@ -102,10 +103,10 @@ var Textile = {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
jQuery.GollumEditor.defineLanguage('textile', Textile);
|
||||
$.GollumEditor.defineLanguage('textile', Textile);
|
||||
|
||||
|
||||
var TextileHelp = [
|
||||
@@ -170,6 +171,6 @@ var TextileHelp = [
|
||||
}
|
||||
];
|
||||
|
||||
jQuery.GollumEditor.defineHelp('textile', TextileHelp);
|
||||
$.GollumEditor.defineHelp('textile', TextileHelp);
|
||||
|
||||
})();
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* gollum.dialog.js
|
||||
*
|
||||
* Used for dialogs. Duh.
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
var Dialog = {
|
||||
|
||||
debugOn: false,
|
||||
markupCreated: false,
|
||||
markup: '',
|
||||
|
||||
attachEvents: function( evtOK ) {
|
||||
$('#gollum-dialog-action-ok').click(function( e ) {
|
||||
Dialog.eventOK( e, evtOK );
|
||||
});
|
||||
$('#gollum-dialog-action-cancel').click( Dialog.eventCancel );
|
||||
$('#gollum-dialog-dialog input[type="text"]').keydown(function( e ) {
|
||||
if ( e.keyCode == 13 ) {
|
||||
Dialog.eventOK( e, evtOK );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
detachEvents: function() {
|
||||
$('#gollum-dialog-action-ok').unbind('click');
|
||||
$('#gollum-dialog-action-cancel').unbind('click');
|
||||
},
|
||||
|
||||
createFieldMarkup: function( fieldArray ) {
|
||||
var fieldMarkup = '<fieldset>';
|
||||
for ( var i=0; i < fieldArray.length; i++ ) {
|
||||
if ( typeof fieldArray[i] == 'object' ) {
|
||||
fieldMarkup += '<div class="field">';
|
||||
switch ( fieldArray[i].type ) {
|
||||
|
||||
// only text is supported for now
|
||||
case 'text':
|
||||
fieldMarkup += Dialog.createFieldText( fieldArray[i] );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
fieldMarkup += '</div>';
|
||||
}
|
||||
|
||||
}
|
||||
fieldMarkup += '</fieldset>';
|
||||
return fieldMarkup;
|
||||
},
|
||||
|
||||
createFieldText: function( fieldAttributes ) {
|
||||
var html = '';
|
||||
|
||||
if ( fieldAttributes.name ) {
|
||||
html += '<label';
|
||||
if ( fieldAttributes.id ) {
|
||||
html += ' for="' + fieldAttributes.name + '"';
|
||||
}
|
||||
html += '>' + fieldAttributes.name + '</label>';
|
||||
}
|
||||
|
||||
html += '<input type="text"';
|
||||
|
||||
if ( fieldAttributes.id ) {
|
||||
html += ' name="' + fieldAttributes.id + '"'
|
||||
if ( fieldAttributes.type == 'code' ) {
|
||||
html+= ' class="code"';
|
||||
}
|
||||
if ( fieldAttributes.defaultValue ) {
|
||||
html+= ' value="' + fieldAttributes.defaultValue.split('"').join('"') + '"';
|
||||
}
|
||||
html += ' id="gollum-dialog-dialog-generated-field-' +
|
||||
fieldAttributes.id + '">';
|
||||
}
|
||||
|
||||
return html;
|
||||
},
|
||||
|
||||
createMarkup: function( title, body ) {
|
||||
Dialog.markupCreated = true;
|
||||
if ($.facebox) {
|
||||
return '<div id="gollum-dialog-dialog">' +
|
||||
'<div id="gollum-dialog-dialog-title"><h4>' +
|
||||
title +'</h4></div>' +
|
||||
'<div id="gollum-dialog-dialog-body">' + body + '</div>' +
|
||||
'<div id="gollum-dialog-dialog-buttons">' +
|
||||
'<a href="#" title="Cancel" id="gollum-dialog-action-cancel" ' +
|
||||
'class="gollum-minibutton">Cancel</a>' +
|
||||
'<a href="#" title="OK" id="gollum-dialog-action-ok" '+
|
||||
'class="gollum-minibutton">OK</a>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
} else {
|
||||
return '<div id="gollum-dialog-dialog">' +
|
||||
'<div id="gollum-dialog-dialog-inner">' +
|
||||
'<div id="gollum-dialog-dialog-bg">' +
|
||||
'<div id="gollum-dialog-dialog-title"><h4>' +
|
||||
title +'</h4></div>' +
|
||||
'<div id="gollum-dialog-dialog-body">' + body + '</div>' +
|
||||
'<div id="gollum-dialog-dialog-buttons">' +
|
||||
'<a href="#" title="Cancel" id="gollum-dialog-action-cancel" ' +
|
||||
'class="minibutton">Cancel</a>' +
|
||||
'<a href="#" title="OK" id="gollum-dialog-action-ok" '+
|
||||
'class="minibutton">OK</a>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
},
|
||||
|
||||
eventCancel: function( e ) {
|
||||
e.preventDefault();
|
||||
debug('Cancelled dialog.');
|
||||
Dialog.hide();
|
||||
},
|
||||
|
||||
eventOK: function( e, evtOK ) {
|
||||
e.preventDefault();
|
||||
|
||||
var results = [];
|
||||
// get the results from each field and build them into the object
|
||||
$('#gollum-dialog-dialog-body input').each(function() {
|
||||
results[$(this).attr('name')] = $(this).val();
|
||||
});
|
||||
|
||||
// pass them to evtOK if it exists (which it should)
|
||||
if ( evtOK &&
|
||||
typeof evtOK == 'function' ) {
|
||||
evtOK( results );
|
||||
}
|
||||
Dialog.hide();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if ( $.facebox ) {
|
||||
Dialog.markupCreated = false;
|
||||
$(document).trigger('close.facebox');
|
||||
Dialog.detachEvents();
|
||||
} else {
|
||||
if ( $.browser.msie ) {
|
||||
$('#gollum-dialog-dialog').hide().removeClass('active');
|
||||
$('select').css('visibility', 'visible');
|
||||
} else {
|
||||
$('#gollum-dialog-dialog').animate({ opacity: 0 }, {
|
||||
duration: 200,
|
||||
complete: function() {
|
||||
$('#gollum-dialog-dialog').removeClass('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
init: function( argObject ) {
|
||||
var title = '';
|
||||
var body = '';
|
||||
|
||||
// bail out if necessary
|
||||
if ( !argObject ||
|
||||
typeof argObject != 'object' ) {
|
||||
debug('Editor Dialog: Cannot init; invalid init object');
|
||||
return;
|
||||
}
|
||||
|
||||
if ( argObject.body && typeof argObject.body == 'string' ) {
|
||||
body = '<p>' + argObject.body + '</p>';
|
||||
}
|
||||
|
||||
// alright, build out fields
|
||||
if ( argObject.fields && typeof argObject.fields == 'object' ) {
|
||||
body += Dialog.createFieldMarkup( argObject.fields );
|
||||
}
|
||||
|
||||
if ( argObject.title && typeof argObject.title == 'string' ) {
|
||||
title = argObject.title;
|
||||
}
|
||||
|
||||
if ( Dialog.markupCreated ) {
|
||||
if ($.facebox) {
|
||||
$(document).trigger('close.facebox');
|
||||
} else {
|
||||
$('#gollum-dialog-dialog').remove();
|
||||
}
|
||||
}
|
||||
|
||||
Dialog.markup = Dialog.createMarkup( title, body );
|
||||
|
||||
if ($.facebox) {
|
||||
$(document).bind('reveal.facebox', function() {
|
||||
if ( argObject.OK &&
|
||||
typeof argObject.OK == 'function' ) {
|
||||
Dialog.attachEvents( argObject.OK );
|
||||
$($('#facebox input[type="text"]').get(0)).focus();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$('body').append( Dialog.markup );
|
||||
if ( argObject.OK &&
|
||||
typeof argObject.OK == 'function' ) {
|
||||
Dialog.attachEvents( argObject.OK );
|
||||
}
|
||||
}
|
||||
|
||||
Dialog.show();
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if ( !Dialog.markupCreated ) {
|
||||
debug('Dialog: No markup to show. Please use init first.');
|
||||
} else {
|
||||
debug('Showing dialog');
|
||||
if ($.facebox) {
|
||||
$.facebox( Dialog.markup );
|
||||
} else {
|
||||
if ( $.browser.msie ) {
|
||||
$('#gollum-dialog.dialog').addClass('active');
|
||||
Dialog.position();
|
||||
$('select').css('visibility', 'hidden');
|
||||
} else {
|
||||
$('#gollum-dialog.dialog').css('display', 'none');
|
||||
$('#gollum-dialog-dialog').animate({ opacity: 0 }, {
|
||||
duration: 0,
|
||||
complete: function() {
|
||||
$('#gollum-dialog-dialog').css('display', 'block');
|
||||
Dialog.position(); // position this thing
|
||||
$('#gollum-dialog-dialog').animate({ opacity: 1 }, {
|
||||
duration: 500
|
||||
});
|
||||
$($('#gollum-dialog-dialog input[type="text"]').get(0)).focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
position: function() {
|
||||
var dialogHeight = $('#gollum-dialog-dialog-inner').height();
|
||||
$('#gollum-dialog-dialog-inner')
|
||||
.css('height', dialogHeight + 'px')
|
||||
.css('margin-top', -1 * parseInt( dialogHeight / 2 ));
|
||||
}
|
||||
};
|
||||
|
||||
if ($.facebox) {
|
||||
$(document).bind('reveal.facebox', function() {
|
||||
$('#facebox img.close_image').remove();
|
||||
});
|
||||
}
|
||||
|
||||
var debug = function(m) {
|
||||
if ( Dialog.debugOn
|
||||
&& typeof console != 'undefined' ) {
|
||||
console.log( m );
|
||||
}
|
||||
};
|
||||
|
||||
$.GollumDialog = Dialog;
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,248 @@
|
||||
// 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,24 +1,24 @@
|
||||
(function($) {
|
||||
|
||||
var Placeholder = {
|
||||
|
||||
|
||||
_PLACEHOLDERS : [],
|
||||
|
||||
|
||||
_p : function( $field ) {
|
||||
|
||||
this.fieldObject = $field;
|
||||
|
||||
this.fieldObject = $field;
|
||||
this.placeholderText = $field.val();
|
||||
var placeholderText = $field.val();
|
||||
|
||||
|
||||
$field.addClass('ph');
|
||||
|
||||
|
||||
$field.blur(function() {
|
||||
if ( $(this).val() == '' ) {
|
||||
$(this).val( placeholderText );
|
||||
$(this).addClass('ph');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$field.focus(function() {
|
||||
$(this).removeClass('ph');
|
||||
if ( $(this).val() == placeholderText ) {
|
||||
@@ -27,28 +27,28 @@
|
||||
$(this)[0].select();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
add : function( $field ) {
|
||||
Placeholder._PLACEHOLDERS.push( new Placeholder._p( $field ) );
|
||||
},
|
||||
|
||||
|
||||
clearAll: function() {
|
||||
for ( var i=0; i < Placeholder._PLACEHOLDERS.length; i++ ) {
|
||||
if ( Placeholder._PLACEHOLDERS[i].fieldObject.val() ==
|
||||
if ( Placeholder._PLACEHOLDERS[i].fieldObject.val() ==
|
||||
Placeholder._PLACEHOLDERS[i].placeholderText ) {
|
||||
Placeholder._PLACEHOLDERS[i].fieldObject.val('');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
exists : function() {
|
||||
return ( _PLACEHOLDERS.length );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
$.GollumPlaceholder = Placeholder;
|
||||
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@
|
||||
// Otherwise, we're most likely dealing with a named color
|
||||
return colors[jQuery.trim(color).toLowerCase()];
|
||||
}
|
||||
|
||||
|
||||
function getColor(elem, attr) {
|
||||
var color;
|
||||
|
||||
@@ -62,14 +62,14 @@
|
||||
|
||||
// Keep going until we find an element that has color, or we hit the body
|
||||
if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
|
||||
break;
|
||||
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/
|
||||
@@ -119,5 +119,5 @@
|
||||
white:[255,255,255],
|
||||
yellow:[255,255,0]
|
||||
};
|
||||
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,8 @@
|
||||
/* mousetrap v1.1.2 craig.is/killing/mice */
|
||||
window.Mousetrap=function(){function o(a,c,b){if(a.addEventListener)return a.addEventListener(c,b,!1);a.attachEvent("on"+c,b)}function u(a){return"keypress"==a.type?String.fromCharCode(a.which):h[a.which]?h[a.which]:v[a.which]?v[a.which]:String.fromCharCode(a.which).toLowerCase()}function p(a){var a=a||{},c=!1,b;for(b in l)a[b]?c=!0:l[b]=0;c||(n=!1)}function w(a,c,b,d,C){var g,e,f=[];if(!j[a])return[];"keyup"==b&&q(a)&&(c=[a]);for(g=0;g<j[a].length;++g)if(e=j[a][g],!(e.seq&&l[e.seq]!=e.level)&&b==
|
||||
e.action&&("keypress"==b||c.sort().join(",")===e.modifiers.sort().join(",")))d&&e.combo==C&&j[a].splice(g,1),f.push(e);return f}function r(a,c){!1===a(c)&&(c.preventDefault&&c.preventDefault(),c.stopPropagation&&c.stopPropagation(),c.returnValue=!1,c.cancelBubble=!0)}function s(a){a.which="number"==typeof a.which?a.which:a.keyCode;var c=u(a);if(c)if("keyup"==a.type&&t==c)t=!1;else{var b=a.target||a.srcElement,d=b.tagName;if(!(-1<(" "+b.className+" ").indexOf(" mousetrap ")?0:"INPUT"==d||"SELECT"==
|
||||
d||"TEXTAREA"==d||b.contentEditable&&"true"==b.contentEditable)){b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");for(var b=w(c,b,a.type),f={},g=!1,d=0;d<b.length;++d)b[d].seq?(g=!0,f[b[d].seq]=1,r(b[d].callback,a)):!g&&!n&&r(b[d].callback,a);a.type==n&&!q(c)&&p(f)}}}function q(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function x(a,c,b){if(!b){if(!k){k={};for(var d in h)95<d&&112>d||h.hasOwnProperty(d)&&(k[h[d]]=d)}b=k[a]?"keydown":
|
||||
"keypress"}"keypress"==b&&c.length&&(b="keydown");return b}function y(a,c,b,d,f){var a=a.replace(/\s+/g," "),g=a.split(" "),e,h,i=[];if(1<g.length){var k=a,m=b;l[k]=0;m||(m=x(g[0],[]));a=function(){n=m;++l[k];clearTimeout(z);z=setTimeout(p,1E3)};b=function(a){r(c,a);"keyup"!==m&&(t=u(a));setTimeout(p,10)};for(d=0;d<g.length;++d)y(g[d],d<g.length-1?a:b,m,k,d)}else{h="+"===a?["+"]:a.split("+");for(g=0;g<h.length;++g)e=h[g],A[e]&&(e=A[e]),b&&("keypress"!=b&&B[e])&&(e=B[e],i.push("shift")),q(e)&&i.push(e);
|
||||
b=x(e,i,b);j[e]||(j[e]=[]);w(e,i,b,!d,a);j[e][d?"unshift":"push"]({callback:c,modifiers:i,action:b,seq:d,level:f,combo:a})}}for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},v={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},B=
|
||||
{"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},A={option:"alt",command:"meta","return":"enter",escape:"esc"},k,j={},i={},l={},z,t=!1,n=!1,f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;o(document,"keypress",s);o(document,"keydown",s);o(document,"keyup",s);return{bind:function(a,c,b){for(var d=a instanceof Array?a:[a],f=0;f<d.length;++f)y(d[f],c,b);i[a+":"+b]=c},unbind:function(a,c){i[a+
|
||||
":"+c]&&(delete i[a+":"+c],this.bind(a,function(){},c))},trigger:function(a,c){i[a+":"+c]()},reset:function(){j={};i={}}}}();
|
||||
@@ -0,0 +1,132 @@
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#editor .ace_sb {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
#darkness {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
background-color: black;
|
||||
opacity: 0.8;
|
||||
z-index: 1001; /* must be > 1000 to overlay ace gutter */
|
||||
}
|
||||
|
||||
#commenttoolpanel {
|
||||
visibility: hidden;
|
||||
z-index: 1002; /* > 1001 to not be hidden by darkness */
|
||||
}
|
||||
|
||||
#comment, #editor {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
/* Set font size of both ace editors. */
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/*
|
||||
Must set ace-line to preserve whitespace in empty lines.
|
||||
Ace editor sets the height inline. The static highlight ext does not.
|
||||
<div class="ace_line" style="height:15px"></div>
|
||||
*/
|
||||
#previewframe #contentframe .ace-github .ace_editor.ace_scroller.ace_text-layer .ace_line {
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
/* Set comment to have a higher z-index
|
||||
so editor doesn't display in the background. */
|
||||
|
||||
#comment {
|
||||
visibility: hidden;
|
||||
z-index: 1003; /* > 1002 to not be hidden by toolpanel */
|
||||
}
|
||||
|
||||
#contentframe {
|
||||
margin: 0 auto;
|
||||
overflow: visible;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#previewframe {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 10px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.editor_bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: black;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
.toolpanel_bg {
|
||||
position: fixed;
|
||||
background: #666;
|
||||
top: 0;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
margin: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* -- Start from notepag.es -- */
|
||||
.toolpanel {
|
||||
position: fixed;
|
||||
background: #666;
|
||||
top: 0;
|
||||
height: 30px;
|
||||
width: 50%;
|
||||
vertical-align: middle;
|
||||
padding: 5px 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.toolpanel.edit a.edit {
|
||||
opacity: 0.4;
|
||||
/* Make it appear as a link even though save
|
||||
doesn't have a href attribute. */
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.toolpanel a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin: 0 5px;
|
||||
display: none;
|
||||
padding: 4px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.toolpanel a img {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
/* -- End from notepag.es -- */
|
||||
|
After Width: | Height: | Size: 525 B |
|
After Width: | Height: | Size: 630 B |
|
After Width: | Height: | Size: 919 B |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 278 B |
@@ -0,0 +1,44 @@
|
||||
<!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>
|
||||
@@ -0,0 +1,103 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kevin Dangoor (kdangoor@mozilla.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* class Ace
|
||||
*
|
||||
* The main class required to set up an Ace instance in the browser.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
require("./lib/fixoldbrowsers");
|
||||
|
||||
var Dom = require("./lib/dom");
|
||||
var Event = require("./lib/event");
|
||||
|
||||
var Editor = require("./editor").Editor;
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var UndoManager = require("./undomanager").UndoManager;
|
||||
var Renderer = require("./virtual_renderer").VirtualRenderer;
|
||||
var MultiSelect = require("./multi_select").MultiSelect;
|
||||
|
||||
// The following require()s are for inclusion in the built ace file
|
||||
require("./worker/worker_client");
|
||||
require("./keyboard/hash_handler");
|
||||
require("./keyboard/state_handler");
|
||||
require("./placeholder");
|
||||
exports.config = require("./config");
|
||||
/**
|
||||
* Ace.edit(el) -> Editor
|
||||
* - el (String | DOMElement): Either the id of an element, or the element itself
|
||||
*
|
||||
* This method embeds the Ace editor into the DOM, at the element provided by `el`.
|
||||
*
|
||||
**/
|
||||
exports.edit = function(el) {
|
||||
if (typeof(el) == "string") {
|
||||
el = document.getElementById(el);
|
||||
}
|
||||
|
||||
if (el.env && el.env.editor instanceof Editor)
|
||||
return el.env.editor;
|
||||
|
||||
var doc = new EditSession(Dom.getInnerText(el));
|
||||
doc.setUndoManager(new UndoManager());
|
||||
el.innerHTML = '';
|
||||
|
||||
var editor = new Editor(new Renderer(el, require("./theme/textmate")));
|
||||
new MultiSelect(editor);
|
||||
editor.setSession(doc);
|
||||
|
||||
var env = {};
|
||||
env.document = doc;
|
||||
env.editor = editor;
|
||||
editor.resize();
|
||||
Event.addListener(window, "resize", function() {
|
||||
editor.resize();
|
||||
});
|
||||
el.env = env;
|
||||
// Store env on editor such that it can be accessed later on from
|
||||
// the returned object.
|
||||
editor.env = env;
|
||||
return editor;
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,254 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
|
||||
/**
|
||||
* class Anchor
|
||||
*
|
||||
* Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new Anchor(doc, row, column)
|
||||
* - doc (Document): The document to associate with the anchor
|
||||
* - row (Number): The starting row position
|
||||
* - column (Number): The starting column position
|
||||
*
|
||||
* Creates a new `Anchor` and associates it with a document.
|
||||
*
|
||||
**/
|
||||
|
||||
var Anchor = exports.Anchor = function(doc, row, column) {
|
||||
this.document = doc;
|
||||
|
||||
if (typeof column == "undefined")
|
||||
this.setPosition(row.row, row.column);
|
||||
else
|
||||
this.setPosition(row, column);
|
||||
|
||||
this.$onChange = this.onChange.bind(this);
|
||||
doc.on("change", this.$onChange);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
/**
|
||||
* Anchor.getPosition() -> Object
|
||||
*
|
||||
* Returns an object identifying the `row` and `column` position of the current anchor.
|
||||
*
|
||||
**/
|
||||
|
||||
this.getPosition = function() {
|
||||
return this.$clipPositionToDocument(this.row, this.column);
|
||||
};
|
||||
|
||||
/**
|
||||
* Anchor.getDocument() -> Document
|
||||
*
|
||||
* Returns the current document.
|
||||
*
|
||||
**/
|
||||
|
||||
this.getDocument = function() {
|
||||
return this.document;
|
||||
};
|
||||
|
||||
/**
|
||||
* Anchor@onChange(e)
|
||||
* - e (Event): Contains data about the event
|
||||
*
|
||||
* Fires whenever the anchor position changes. Events that can trigger this function include `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
*
|
||||
**/
|
||||
|
||||
this.onChange = function(e) {
|
||||
var delta = e.data;
|
||||
var range = delta.range;
|
||||
|
||||
if (range.start.row == range.end.row && range.start.row != this.row)
|
||||
return;
|
||||
|
||||
if (range.start.row > this.row)
|
||||
return;
|
||||
|
||||
if (range.start.row == this.row && range.start.column > this.column)
|
||||
return;
|
||||
|
||||
var row = this.row;
|
||||
var column = this.column;
|
||||
|
||||
if (delta.action === "insertText") {
|
||||
if (range.start.row === row && range.start.column <= column) {
|
||||
if (range.start.row === range.end.row) {
|
||||
column += range.end.column - range.start.column;
|
||||
}
|
||||
else {
|
||||
column -= range.start.column;
|
||||
row += range.end.row - range.start.row;
|
||||
}
|
||||
}
|
||||
else if (range.start.row !== range.end.row && range.start.row < row) {
|
||||
row += range.end.row - range.start.row;
|
||||
}
|
||||
} else if (delta.action === "insertLines") {
|
||||
if (range.start.row <= row) {
|
||||
row += range.end.row - range.start.row;
|
||||
}
|
||||
}
|
||||
else if (delta.action == "removeText") {
|
||||
if (range.start.row == row && range.start.column < column) {
|
||||
if (range.end.column >= column)
|
||||
column = range.start.column;
|
||||
else
|
||||
column = Math.max(0, column - (range.end.column - range.start.column));
|
||||
|
||||
} else if (range.start.row !== range.end.row && range.start.row < row) {
|
||||
if (range.end.row == row) {
|
||||
column = Math.max(0, column - range.end.column) + range.start.column;
|
||||
}
|
||||
row -= (range.end.row - range.start.row);
|
||||
}
|
||||
else if (range.end.row == row) {
|
||||
row -= range.end.row - range.start.row;
|
||||
column = Math.max(0, column - range.end.column) + range.start.column;
|
||||
}
|
||||
} else if (delta.action == "removeLines") {
|
||||
if (range.start.row <= row) {
|
||||
if (range.end.row <= row)
|
||||
row -= range.end.row - range.start.row;
|
||||
else {
|
||||
row = range.start.row;
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setPosition(row, column, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Anchor.setPosition(row, column, noClip)
|
||||
* - row (Number): The row index to move the anchor to
|
||||
* - column (Number): The column index to move the anchor to
|
||||
* - noClip (Boolean): Identifies if you want the position to be clipped
|
||||
*
|
||||
* Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped.
|
||||
*
|
||||
**/
|
||||
|
||||
this.setPosition = function(row, column, noClip) {
|
||||
var pos;
|
||||
if (noClip) {
|
||||
pos = {
|
||||
row: row,
|
||||
column: column
|
||||
};
|
||||
}
|
||||
else {
|
||||
pos = this.$clipPositionToDocument(row, column);
|
||||
}
|
||||
|
||||
if (this.row == pos.row && this.column == pos.column)
|
||||
return;
|
||||
|
||||
var old = {
|
||||
row: this.row,
|
||||
column: this.column
|
||||
};
|
||||
|
||||
this.row = pos.row;
|
||||
this.column = pos.column;
|
||||
this._emit("change", {
|
||||
old: old,
|
||||
value: pos
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Anchor.detach()
|
||||
*
|
||||
* When called, the `'change'` event listener is removed.
|
||||
*
|
||||
**/
|
||||
|
||||
this.detach = function() {
|
||||
this.document.removeEventListener("change", this.$onChange);
|
||||
};
|
||||
|
||||
/** internal, hide
|
||||
* Anchor.clipPositionToDocument(row, column)
|
||||
* - row (Number): The row index to clip the anchor to
|
||||
* - column (Number): The column index to clip the anchor to
|
||||
*
|
||||
* Clips the anchor position to the specified row and column.
|
||||
*
|
||||
**/
|
||||
|
||||
this.$clipPositionToDocument = function(row, column) {
|
||||
var pos = {};
|
||||
|
||||
if (row >= this.document.getLength()) {
|
||||
pos.row = Math.max(0, this.document.getLength() - 1);
|
||||
pos.column = this.document.getLine(pos.row).length;
|
||||
}
|
||||
else if (row < 0) {
|
||||
pos.row = 0;
|
||||
pos.column = 0;
|
||||
}
|
||||
else {
|
||||
pos.row = row;
|
||||
pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
|
||||
}
|
||||
|
||||
if (column < 0)
|
||||
pos.column = 0;
|
||||
|
||||
return pos;
|
||||
};
|
||||
|
||||
}).call(Anchor.prototype);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,184 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Document = require("./document").Document;
|
||||
var Anchor = require("./anchor").Anchor;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test create anchor" : function() {
|
||||
var doc = new Document("juhu");
|
||||
var anchor = new Anchor(doc, 0, 0);
|
||||
|
||||
assert.position(anchor.getPosition(), 0, 0);
|
||||
assert.equal(anchor.getDocument(), doc);
|
||||
},
|
||||
|
||||
"test insert text in same row before cursor should move anchor column": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.insert({row: 1, column: 1}, "123");
|
||||
assert.position(anchor.getPosition(), 1, 7);
|
||||
},
|
||||
|
||||
"test insert lines before cursor should move anchor row": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.insertLines(1, ["123", "456"]);
|
||||
assert.position(anchor.getPosition(), 3, 4);
|
||||
},
|
||||
|
||||
"test insert new line before cursor should move anchor column": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.insertNewLine({row: 0, column: 0});
|
||||
assert.position(anchor.getPosition(), 2, 4);
|
||||
},
|
||||
|
||||
"test insert new line in anchor line before anchor should move anchor column and row": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.insertNewLine({row: 1, column: 2});
|
||||
assert.position(anchor.getPosition(), 2, 2);
|
||||
},
|
||||
|
||||
"test delete text in anchor line before anchor should move anchor column": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.remove(new Range(1, 1, 1, 3));
|
||||
assert.position(anchor.getPosition(), 1, 2);
|
||||
},
|
||||
|
||||
"test remove range which contains the anchor should move the anchor to the start of the range": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 0, 3);
|
||||
|
||||
doc.remove(new Range(0, 1, 1, 3));
|
||||
assert.position(anchor.getPosition(), 0, 1);
|
||||
},
|
||||
|
||||
"test delete character before the anchor should have no effect": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.remove(new Range(1, 4, 1, 5));
|
||||
assert.position(anchor.getPosition(), 1, 4);
|
||||
},
|
||||
|
||||
"test delete lines in anchor line before anchor should move anchor row": function() {
|
||||
var doc = new Document("juhu\n1\n2\nkinners");
|
||||
var anchor = new Anchor(doc, 3, 4);
|
||||
|
||||
doc.removeLines(1, 2);
|
||||
assert.position(anchor.getPosition(), 1, 4);
|
||||
},
|
||||
|
||||
"test remove new line before the cursor": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.removeNewLine(0);
|
||||
assert.position(anchor.getPosition(), 0, 8);
|
||||
},
|
||||
|
||||
"test delete range which contains the anchor should move anchor to the end of the range": function() {
|
||||
var doc = new Document("juhu\nkinners");
|
||||
var anchor = new Anchor(doc, 1, 4);
|
||||
|
||||
doc.remove(new Range(0, 2, 1, 2));
|
||||
assert.position(anchor.getPosition(), 0, 4);
|
||||
},
|
||||
|
||||
"test delete line which contains the anchor should move anchor to the end of the range": function() {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 1, 5);
|
||||
|
||||
doc.removeLines(1, 1);
|
||||
assert.position(anchor.getPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test remove after the anchor should have no effect": function() {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 1, 2);
|
||||
|
||||
doc.remove(new Range(1, 4, 2, 2));
|
||||
assert.position(anchor.getPosition(), 1, 2);
|
||||
},
|
||||
|
||||
"test anchor changes triggered by document changes should emit change event": function(next) {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 1, 5);
|
||||
|
||||
anchor.on("change", function(e) {
|
||||
assert.position(anchor.getPosition(), 0, 0);
|
||||
next();
|
||||
});
|
||||
|
||||
doc.remove(new Range(0, 0, 2, 1));
|
||||
},
|
||||
|
||||
"test only fire change event if position changes": function() {
|
||||
var doc = new Document("juhu\nkinners\n123");
|
||||
var anchor = new Anchor(doc, 1, 5);
|
||||
|
||||
anchor.on("change", function(e) {
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
doc.remove(new Range(2, 0, 2, 1));
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
|
||||
// tokenizing lines longer than this makes editor very slow
|
||||
var MAX_LINE_LENGTH = 5000;
|
||||
|
||||
/**
|
||||
* class BackgroundTokenizer
|
||||
*
|
||||
* Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use. If a certain row is changed, everything below that row is re-tokenized.
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new BackgroundTokenizer(tokenizer, editor)
|
||||
* - tokenizer (Tokenizer): The tokenizer to use
|
||||
* - editor (Editor): The editor to associate with
|
||||
*
|
||||
* Creates a new `BackgroundTokenizer` object.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
var BackgroundTokenizer = function(tokenizer, editor) {
|
||||
this.running = false;
|
||||
this.lines = [];
|
||||
this.states = [];
|
||||
this.currentLine = 0;
|
||||
this.tokenizer = tokenizer;
|
||||
|
||||
var self = this;
|
||||
|
||||
this.$worker = function() {
|
||||
if (!self.running) { return; }
|
||||
|
||||
var workerStart = new Date();
|
||||
var startLine = self.currentLine;
|
||||
var doc = self.doc;
|
||||
|
||||
var processedLines = 0;
|
||||
|
||||
var len = doc.getLength();
|
||||
while (self.currentLine < len) {
|
||||
self.$tokenizeRow(self.currentLine);
|
||||
while (self.lines[self.currentLine])
|
||||
self.currentLine++;
|
||||
|
||||
// only check every 5 lines
|
||||
processedLines ++;
|
||||
if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) {
|
||||
self.fireUpdateEvent(startLine, self.currentLine-1);
|
||||
self.running = setTimeout(self.$worker, 20);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.running = false;
|
||||
|
||||
self.fireUpdateEvent(startLine, len - 1);
|
||||
};
|
||||
};
|
||||
|
||||
(function(){
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.setTokenizer(tokenizer)
|
||||
* - tokenizer (Tokenizer): The new tokenizer to use
|
||||
*
|
||||
* Sets a new tokenizer for this object.
|
||||
*
|
||||
**/
|
||||
this.setTokenizer = function(tokenizer) {
|
||||
this.tokenizer = tokenizer;
|
||||
this.lines = [];
|
||||
this.states = [];
|
||||
|
||||
this.start(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.setDocument(doc)
|
||||
* - doc (Document): The new document to associate with
|
||||
*
|
||||
* Sets a new document to associate with this object.
|
||||
*
|
||||
**/
|
||||
this.setDocument = function(doc) {
|
||||
this.doc = doc;
|
||||
this.lines = [];
|
||||
this.states = [];
|
||||
|
||||
this.stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.fireUpdateEvent(firstRow, lastRow)
|
||||
* - firstRow (Number): The starting row region
|
||||
* - lastRow (Number): The final row region
|
||||
*
|
||||
* Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated.
|
||||
*
|
||||
**/
|
||||
this.fireUpdateEvent = function(firstRow, lastRow) {
|
||||
var data = {
|
||||
first: firstRow,
|
||||
last: lastRow
|
||||
};
|
||||
this._emit("update", {data: data});
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.start(startRow)
|
||||
* - startRow (Number): The row to start at
|
||||
*
|
||||
* Starts tokenizing at the row indicated.
|
||||
*
|
||||
**/
|
||||
this.start = function(startRow) {
|
||||
this.currentLine = Math.min(startRow || 0, this.currentLine, this.doc.getLength());
|
||||
|
||||
// remove all cached items below this line
|
||||
this.lines.splice(this.currentLine, this.lines.length);
|
||||
this.states.splice(this.currentLine, this.states.length);
|
||||
|
||||
this.stop();
|
||||
// pretty long delay to prevent the tokenizer from interfering with the user
|
||||
this.running = setTimeout(this.$worker, 700);
|
||||
};
|
||||
|
||||
this.$updateOnChange = function(delta) {
|
||||
var range = delta.range;
|
||||
var startRow = range.start.row;
|
||||
var len = range.end.row - startRow;
|
||||
|
||||
if (len === 0) {
|
||||
this.lines[startRow] = null;
|
||||
} else if (delta.action == "removeText" || delta.action == "removeLines") {
|
||||
this.lines.splice(startRow, len + 1, null);
|
||||
this.states.splice(startRow, len + 1, null);
|
||||
} else {
|
||||
var args = Array(len + 1);
|
||||
args.unshift(startRow, 1);
|
||||
this.lines.splice.apply(this.lines, args);
|
||||
this.states.splice.apply(this.states, args);
|
||||
}
|
||||
|
||||
this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength());
|
||||
|
||||
this.stop();
|
||||
// pretty long delay to prevent the tokenizer from interfering with the user
|
||||
this.running = setTimeout(this.$worker, 700);
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.stop()
|
||||
*
|
||||
* Stops tokenizing.
|
||||
*
|
||||
**/
|
||||
this.stop = function() {
|
||||
if (this.running)
|
||||
clearTimeout(this.running);
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
/** related to: BackgroundTokenizer.$tokenizeRows
|
||||
* BackgroundTokenizer.getTokens(firstRow, lastRow) -> [Object]
|
||||
* - firstRow (Number): The row to start at
|
||||
* - lastRow (Number): The row to finish at
|
||||
*
|
||||
* Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows.
|
||||
*
|
||||
**/
|
||||
this.getTokens = function(row) {
|
||||
return this.lines[row] || this.$tokenizeRow(row);
|
||||
};
|
||||
|
||||
/**
|
||||
* BackgroundTokenizer.getState(row) -> String
|
||||
* - row (Number): The row to start at
|
||||
*
|
||||
* [Returns the state of tokenization at the end of a row.]{: #BackgroundTokenizer.getState}
|
||||
**/
|
||||
this.getState = function(row) {
|
||||
if (this.currentLine == row)
|
||||
this.$tokenizeRow(row);
|
||||
return this.states[row] || "start";
|
||||
};
|
||||
|
||||
this.$tokenizeRow = function(row) {
|
||||
var line = this.doc.getLine(row);
|
||||
var state = this.states[row - 1];
|
||||
|
||||
if (line.length > MAX_LINE_LENGTH) {
|
||||
var overflow = {value: line.substr(MAX_LINE_LENGTH), type: "text"};
|
||||
line = line.slice(0, MAX_LINE_LENGTH);
|
||||
}
|
||||
var data = this.tokenizer.getLineTokens(line, state);
|
||||
if (overflow) {
|
||||
data.tokens.push(overflow);
|
||||
data.state = "start";
|
||||
}
|
||||
|
||||
if (this.states[row] !== data.state) {
|
||||
this.states[row] = data.state;
|
||||
this.lines[row + 1] = null;
|
||||
if (this.currentLine > row + 1)
|
||||
this.currentLine = row + 1;
|
||||
} else if (this.currentLine == row) {
|
||||
this.currentLine = row + 1;
|
||||
}
|
||||
|
||||
return this.lines[row] = data.tokens;
|
||||
};
|
||||
|
||||
}).call(BackgroundTokenizer.prototype);
|
||||
|
||||
exports.BackgroundTokenizer = BackgroundTokenizer;
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <harutyun@c9.io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
function forceTokenize(session){
|
||||
for (var i = 0, l = session.getLength(); i < l; i++)
|
||||
session.getTokens(i)
|
||||
}
|
||||
|
||||
function testStates(session, states) {
|
||||
for (var i = 0, l = session.getLength(); i < l; i++)
|
||||
assert.equal(session.bgTokenizer.states[i], states[i])
|
||||
assert.ok(l == states.length)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test background tokenizer update on session change" : function() {
|
||||
var doc = new EditSession([
|
||||
"/*",
|
||||
"*/",
|
||||
"var juhu"
|
||||
]);
|
||||
doc.setMode("./mode/javascript")
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "start", "start"])
|
||||
|
||||
doc.remove(new Range(0,2,1,2))
|
||||
testStates(doc, [null, "start"])
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "comment"])
|
||||
|
||||
doc.insert({row:0, column:2}, "\n*/")
|
||||
testStates(doc, [undefined, undefined, "comment"])
|
||||
|
||||
forceTokenize(doc)
|
||||
testStates(doc, ["comment", "start", "start"])
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
var EventEmitter = require("../lib/event_emitter").EventEmitter;
|
||||
|
||||
/**
|
||||
* class CommandManager
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new CommandManager(platform, commands)
|
||||
* - platform (String): Identifier for the platform; must be either `'mac'` or `'win'`
|
||||
* - commands (Array): A list of commands
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
var CommandManager = function(platform, commands) {
|
||||
this.platform = platform;
|
||||
this.commands = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
this.addCommands(commands);
|
||||
|
||||
this.setDefaultHandler("exec", function(e) {
|
||||
return e.command.exec(e.editor, e.args || {});
|
||||
});
|
||||
};
|
||||
|
||||
oop.inherits(CommandManager, HashHandler);
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
this.exec = function(command, editor, args) {
|
||||
if (typeof command === 'string')
|
||||
command = this.commands[command];
|
||||
|
||||
if (!command)
|
||||
return false;
|
||||
|
||||
if (editor && editor.$readOnly && !command.readOnly)
|
||||
return false;
|
||||
|
||||
var retvalue = this._emit("exec", {
|
||||
editor: editor,
|
||||
command: command,
|
||||
args: args
|
||||
});
|
||||
|
||||
return retvalue === false ? false : true;
|
||||
};
|
||||
|
||||
this.toggleRecording = function() {
|
||||
if (this.$inReplay)
|
||||
return;
|
||||
if (this.recording) {
|
||||
this.macro.pop();
|
||||
this.removeEventListener("exec", this.$addCommandToMacro);
|
||||
|
||||
if (!this.macro.length)
|
||||
this.macro = this.oldMacro;
|
||||
|
||||
return this.recording = false;
|
||||
}
|
||||
if (!this.$addCommandToMacro) {
|
||||
this.$addCommandToMacro = function(e) {
|
||||
this.macro.push([e.command, e.args]);
|
||||
}.bind(this);
|
||||
}
|
||||
|
||||
this.oldMacro = this.macro;
|
||||
this.macro = [];
|
||||
this.on("exec", this.$addCommandToMacro);
|
||||
return this.recording = true;
|
||||
};
|
||||
|
||||
this.replay = function(editor) {
|
||||
if (this.$inReplay || !this.macro)
|
||||
return;
|
||||
|
||||
if (this.recording)
|
||||
return this.toggleRecording();
|
||||
|
||||
try {
|
||||
this.$inReplay = true;
|
||||
this.macro.forEach(function(x) {
|
||||
if (typeof x == "string")
|
||||
this.exec(x, editor);
|
||||
else
|
||||
this.exec(x[0], editor, x[1]);
|
||||
}, this);
|
||||
} finally {
|
||||
this.$inReplay = false;
|
||||
}
|
||||
};
|
||||
|
||||
this.trimMacro = function(m) {
|
||||
return m.map(function(x){
|
||||
if (typeof x[0] != "string")
|
||||
x[0] = x[0].name;
|
||||
if (!x[1])
|
||||
x = x[0];
|
||||
return x;
|
||||
});
|
||||
};
|
||||
|
||||
}).call(CommandManager.prototype);
|
||||
|
||||
exports.CommandManager = CommandManager;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,193 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var CommandManager = require("./command_manager").CommandManager;
|
||||
var keys = require("../lib/keys");
|
||||
var assert = require("../test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
setUp: function() {
|
||||
this.command = {
|
||||
name: "gotoline",
|
||||
bindKey: {
|
||||
mac: "Command-L",
|
||||
win: "Ctrl-L"
|
||||
},
|
||||
called: false,
|
||||
exec: function(editor) { this.called = true; }
|
||||
};
|
||||
|
||||
this.cm = new CommandManager("mac", [this.command]);
|
||||
},
|
||||
|
||||
"test: register command": function() {
|
||||
this.cm.exec("gotoline");
|
||||
assert.ok(this.command.called);
|
||||
},
|
||||
|
||||
"test: mac hotkeys": function() {
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "L");
|
||||
assert.equal(command, this.command);
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "L");
|
||||
assert.equal(command, undefined);
|
||||
},
|
||||
|
||||
"test: win hotkeys": function() {
|
||||
var cm = new CommandManager("win", [this.command]);
|
||||
|
||||
var command = cm.findKeyCommand(keys.KEY_MODS.command, "L");
|
||||
assert.equal(command, undefined);
|
||||
|
||||
var command = cm.findKeyCommand(keys.KEY_MODS.ctrl, "L");
|
||||
assert.equal(command, this.command);
|
||||
},
|
||||
|
||||
"test: remove command by object": function() {
|
||||
this.cm.removeCommand(this.command);
|
||||
|
||||
this.cm.exec("gotoline");
|
||||
assert.ok(!this.command.called);
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "L");
|
||||
assert.equal(command, null);
|
||||
},
|
||||
|
||||
"test: remove command by name": function() {
|
||||
this.cm.removeCommand("gotoline");
|
||||
|
||||
this.cm.exec("gotoline");
|
||||
assert.ok(!this.command.called);
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "L");
|
||||
assert.equal(command, null);
|
||||
},
|
||||
|
||||
"test: adding a new command with the same name as an existing one should remove the old one first": function() {
|
||||
var command = {
|
||||
name: "gotoline",
|
||||
bindKey: {
|
||||
mac: "Command-L",
|
||||
win: "Ctrl-L"
|
||||
},
|
||||
called: false,
|
||||
exec: function(editor) { this.called = true; }
|
||||
};
|
||||
this.cm.addCommand(command);
|
||||
|
||||
this.cm.exec("gotoline");
|
||||
assert.ok(command.called);
|
||||
assert.ok(!this.command.called);
|
||||
|
||||
assert.equal(this.cm.findKeyCommand(keys.KEY_MODS.command, "L"), command);
|
||||
},
|
||||
|
||||
"test: adding commands and recording a macro": function() {
|
||||
var called = "";
|
||||
this.cm.addCommands({
|
||||
togglerecording: function(editor) {
|
||||
editor.cm.toggleRecording();
|
||||
},
|
||||
replay: function(editor) {
|
||||
editor.cm.replay();
|
||||
},
|
||||
cm1: function(editor, arg) {
|
||||
called += "1" + (arg || "");
|
||||
},
|
||||
cm2: function(editor) {
|
||||
called += "2";
|
||||
}
|
||||
});
|
||||
|
||||
this.cm.exec("togglerecording", this);
|
||||
assert.ok(this.cm.recording);
|
||||
|
||||
this.cm.exec("cm1", this, "-");
|
||||
this.cm.exec("cm2");
|
||||
this.cm.exec("replay", this);
|
||||
assert.ok(!this.cm.recording);
|
||||
assert.equal(called, "1-2");
|
||||
|
||||
called = "";
|
||||
this.cm.exec("replay", this);
|
||||
assert.equal(called, "1-2");
|
||||
},
|
||||
|
||||
"test: bindkeys": function() {
|
||||
var called = "";
|
||||
this.cm.addCommands({
|
||||
cm1: function(editor, arg) {
|
||||
called += "1" + (arg || "");
|
||||
},
|
||||
cm2: function(editor) {
|
||||
called += "2";
|
||||
}
|
||||
});
|
||||
|
||||
this.cm.bindKeys({
|
||||
"Ctrl-L|Command-C": "cm1",
|
||||
"Ctrl-R": "cm2"
|
||||
});
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "C");
|
||||
assert.equal(command, "cm1");
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "R");
|
||||
assert.equal(command, "cm2");
|
||||
|
||||
this.cm.bindKeys({
|
||||
"Ctrl-R": null
|
||||
});
|
||||
|
||||
var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "R");
|
||||
assert.equal(command, null);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var lang = require("../lib/lang");
|
||||
|
||||
function bindKey(win, mac) {
|
||||
return {
|
||||
win: win,
|
||||
mac: mac
|
||||
};
|
||||
}
|
||||
|
||||
exports.commands = [{
|
||||
name: "selectall",
|
||||
bindKey: bindKey("Ctrl-A", "Command-A"),
|
||||
exec: function(editor) { editor.selectAll(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "centerselection",
|
||||
bindKey: bindKey(null, "Ctrl-L"),
|
||||
exec: function(editor) { editor.centerSelection(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoline",
|
||||
bindKey: bindKey("Ctrl-L", "Command-L"),
|
||||
exec: function(editor) {
|
||||
var line = parseInt(prompt("Enter line number:"), 10);
|
||||
if (!isNaN(line)) {
|
||||
editor.gotoLine(line);
|
||||
}
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "fold",
|
||||
bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"),
|
||||
exec: function(editor) { editor.session.toggleFold(false); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "unfold",
|
||||
bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"),
|
||||
exec: function(editor) { editor.session.toggleFold(true); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "foldall",
|
||||
bindKey: bindKey("Alt-0", "Command-Option-0"),
|
||||
exec: function(editor) { editor.session.foldAll(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "unfoldall",
|
||||
bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"),
|
||||
exec: function(editor) { editor.session.unfold(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "findnext",
|
||||
bindKey: bindKey("Ctrl-K", "Command-G"),
|
||||
exec: function(editor) { editor.findNext(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "findprevious",
|
||||
bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"),
|
||||
exec: function(editor) { editor.findPrevious(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "find",
|
||||
bindKey: bindKey("Ctrl-F", "Command-F"),
|
||||
exec: function(editor) {
|
||||
var needle = prompt("Find:", editor.getCopyText());
|
||||
editor.find(needle);
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "overwrite",
|
||||
bindKey: "Insert",
|
||||
exec: function(editor) { editor.toggleOverwrite(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttostart",
|
||||
bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Up"),
|
||||
exec: function(editor) { editor.getSelection().selectFileStart(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotostart",
|
||||
bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"),
|
||||
exec: function(editor) { editor.navigateFileStart(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectup",
|
||||
bindKey: bindKey("Shift-Up", "Shift-Up"),
|
||||
exec: function(editor) { editor.getSelection().selectUp(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "golineup",
|
||||
bindKey: bindKey("Up", "Up|Ctrl-P"),
|
||||
exec: function(editor, args) { editor.navigateUp(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttoend",
|
||||
bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-Down"),
|
||||
exec: function(editor) { editor.getSelection().selectFileEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoend",
|
||||
bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"),
|
||||
exec: function(editor) { editor.navigateFileEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectdown",
|
||||
bindKey: bindKey("Shift-Down", "Shift-Down"),
|
||||
exec: function(editor) { editor.getSelection().selectDown(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "golinedown",
|
||||
bindKey: bindKey("Down", "Down|Ctrl-N"),
|
||||
exec: function(editor, args) { editor.navigateDown(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectwordleft",
|
||||
bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectWordLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotowordleft",
|
||||
bindKey: bindKey("Ctrl-Left", "Option-Left"),
|
||||
exec: function(editor) { editor.navigateWordLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttolinestart",
|
||||
bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotolinestart",
|
||||
bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"),
|
||||
exec: function(editor) { editor.navigateLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectleft",
|
||||
bindKey: bindKey("Shift-Left", "Shift-Left"),
|
||||
exec: function(editor) { editor.getSelection().selectLeft(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoleft",
|
||||
bindKey: bindKey("Left", "Left|Ctrl-B"),
|
||||
exec: function(editor, args) { editor.navigateLeft(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectwordright",
|
||||
bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectWordRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotowordright",
|
||||
bindKey: bindKey("Ctrl-Right", "Option-Right"),
|
||||
exec: function(editor) { editor.navigateWordRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttolineend",
|
||||
bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotolineend",
|
||||
bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"),
|
||||
exec: function(editor) { editor.navigateLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectright",
|
||||
bindKey: bindKey("Shift-Right", "Shift-Right"),
|
||||
exec: function(editor) { editor.getSelection().selectRight(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotoright",
|
||||
bindKey: bindKey("Right", "Right|Ctrl-F"),
|
||||
exec: function(editor, args) { editor.navigateRight(args.times); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectpagedown",
|
||||
bindKey: "Shift-PageDown",
|
||||
exec: function(editor) { editor.selectPageDown(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "pagedown",
|
||||
bindKey: bindKey(null, "Option-PageDown"),
|
||||
exec: function(editor) { editor.scrollPageDown(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotopagedown",
|
||||
bindKey: bindKey("PageDown", "PageDown|Ctrl-V"),
|
||||
exec: function(editor) { editor.gotoPageDown(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectpageup",
|
||||
bindKey: "Shift-PageUp",
|
||||
exec: function(editor) { editor.selectPageUp(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "pageup",
|
||||
bindKey: bindKey(null, "Option-PageUp"),
|
||||
exec: function(editor) { editor.scrollPageUp(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "gotopageup",
|
||||
bindKey: "PageUp",
|
||||
exec: function(editor) { editor.gotoPageUp(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "scrollup",
|
||||
bindKey: bindKey("Ctrl-Up", null),
|
||||
exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "scrolldown",
|
||||
bindKey: bindKey("Ctrl-Down", null),
|
||||
exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectlinestart",
|
||||
bindKey: "Shift-Home",
|
||||
exec: function(editor) { editor.getSelection().selectLineStart(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selectlineend",
|
||||
bindKey: "Shift-End",
|
||||
exec: function(editor) { editor.getSelection().selectLineEnd(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "togglerecording",
|
||||
bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"),
|
||||
exec: function(editor) { editor.commands.toggleRecording(); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "replaymacro",
|
||||
bindKey: bindKey("Ctrl-Shift-E", "Command-Shift-E"),
|
||||
exec: function(editor) { editor.commands.replay(editor); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "jumptomatching",
|
||||
bindKey: bindKey("Ctrl-P", "Ctrl-P"),
|
||||
exec: function(editor) { editor.jumpToMatching(); },
|
||||
multiSelectAction: "forEach",
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "selecttomatching",
|
||||
bindKey: bindKey("Ctrl-Shift-P", "Ctrl-Shift-P"),
|
||||
exec: function(editor) { editor.jumpToMatching(true); },
|
||||
readOnly: true
|
||||
},
|
||||
|
||||
// commands disabled in readOnly mode
|
||||
{
|
||||
name: "cut",
|
||||
exec: function(editor) {
|
||||
var range = editor.getSelectionRange();
|
||||
editor._emit("cut", range);
|
||||
|
||||
if (!editor.selection.isEmpty()) {
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
}
|
||||
},
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removeline",
|
||||
bindKey: bindKey("Ctrl-D", "Command-D"),
|
||||
exec: function(editor) { editor.removeLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "duplicateSelection",
|
||||
bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"),
|
||||
exec: function(editor) { editor.duplicateSelection(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "togglecomment",
|
||||
bindKey: bindKey("Ctrl-/", "Command-/"),
|
||||
exec: function(editor) { editor.toggleCommentLines(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "replace",
|
||||
bindKey: bindKey("Ctrl-R", "Command-Option-F"),
|
||||
exec: function(editor) {
|
||||
var needle = prompt("Find:", editor.getCopyText());
|
||||
if (!needle)
|
||||
return;
|
||||
var replacement = prompt("Replacement:");
|
||||
if (!replacement)
|
||||
return;
|
||||
editor.replace(replacement, {needle: needle});
|
||||
}
|
||||
}, {
|
||||
name: "replaceall",
|
||||
bindKey: bindKey("Ctrl-Shift-R", "Command-Shift-Option-F"),
|
||||
exec: function(editor) {
|
||||
var needle = prompt("Find:");
|
||||
if (!needle)
|
||||
return;
|
||||
var replacement = prompt("Replacement:");
|
||||
if (!replacement)
|
||||
return;
|
||||
editor.replaceAll(replacement, {needle: needle});
|
||||
}
|
||||
}, {
|
||||
name: "undo",
|
||||
bindKey: bindKey("Ctrl-Z", "Command-Z"),
|
||||
exec: function(editor) { editor.undo(); }
|
||||
}, {
|
||||
name: "redo",
|
||||
bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"),
|
||||
exec: function(editor) { editor.redo(); }
|
||||
}, {
|
||||
name: "copylinesup",
|
||||
bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"),
|
||||
exec: function(editor) { editor.copyLinesUp(); }
|
||||
}, {
|
||||
name: "movelinesup",
|
||||
bindKey: bindKey("Alt-Up", "Option-Up"),
|
||||
exec: function(editor) { editor.moveLinesUp(); }
|
||||
}, {
|
||||
name: "copylinesdown",
|
||||
bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"),
|
||||
exec: function(editor) { editor.copyLinesDown(); }
|
||||
}, {
|
||||
name: "movelinesdown",
|
||||
bindKey: bindKey("Alt-Down", "Option-Down"),
|
||||
exec: function(editor) { editor.moveLinesDown(); }
|
||||
}, {
|
||||
name: "del",
|
||||
bindKey: bindKey("Delete", "Delete|Ctrl-D"),
|
||||
exec: function(editor) { editor.remove("right"); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "backspace",
|
||||
bindKey: bindKey(
|
||||
"Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
|
||||
"Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H"
|
||||
),
|
||||
exec: function(editor) { editor.remove("left"); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removetolinestart",
|
||||
bindKey: bindKey("Alt-Backspace", "Command-Backspace"),
|
||||
exec: function(editor) { editor.removeToLineStart(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removetolineend",
|
||||
bindKey: bindKey("Alt-Delete", "Ctrl-K"),
|
||||
exec: function(editor) { editor.removeToLineEnd(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removewordleft",
|
||||
bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"),
|
||||
exec: function(editor) { editor.removeWordLeft(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "removewordright",
|
||||
bindKey: bindKey("Ctrl-Delete", "Alt-Delete"),
|
||||
exec: function(editor) { editor.removeWordRight(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "outdent",
|
||||
bindKey: bindKey("Shift-Tab", "Shift-Tab"),
|
||||
exec: function(editor) { editor.blockOutdent(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "indent",
|
||||
bindKey: bindKey("Tab", "Tab"),
|
||||
exec: function(editor) { editor.indent(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "insertstring",
|
||||
exec: function(editor, str) { editor.insert(str); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "inserttext",
|
||||
exec: function(editor, args) {
|
||||
editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
|
||||
},
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "splitline",
|
||||
bindKey: bindKey(null, "Ctrl-O"),
|
||||
exec: function(editor) { editor.splitLine(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "transposeletters",
|
||||
bindKey: bindKey("Ctrl-T", "Ctrl-T"),
|
||||
exec: function(editor) { editor.transposeLetters(); },
|
||||
multiSelectAction: function(editor) {editor.transposeSelections(1); }
|
||||
}, {
|
||||
name: "touppercase",
|
||||
bindKey: bindKey("Ctrl-U", "Ctrl-U"),
|
||||
exec: function(editor) { editor.toUpperCase(); },
|
||||
multiSelectAction: "forEach"
|
||||
}, {
|
||||
name: "tolowercase",
|
||||
bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"),
|
||||
exec: function(editor) { editor.toLowerCase(); },
|
||||
multiSelectAction: "forEach"
|
||||
}];
|
||||
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
// commands to enter multiselect mode
|
||||
exports.defaultCommands = [{
|
||||
name: "addCursorAbove",
|
||||
exec: function(editor) { editor.selectMoreLines(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelow",
|
||||
exec: function(editor) { editor.selectMoreLines(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorAboveSkipCurrent",
|
||||
exec: function(editor) { editor.selectMoreLines(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "addCursorBelowSkipCurrent",
|
||||
exec: function(editor) { editor.selectMoreLines(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreBefore",
|
||||
exec: function(editor) { editor.selectMore(-1); },
|
||||
bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectMoreAfter",
|
||||
exec: function(editor) { editor.selectMore(1); },
|
||||
bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextBefore",
|
||||
exec: function(editor) { editor.selectMore(-1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "selectNextAfter",
|
||||
exec: function(editor) { editor.selectMore(1, true); },
|
||||
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
|
||||
readonly: true
|
||||
}, {
|
||||
name: "splitIntoLines",
|
||||
exec: function(editor) { editor.multiSelect.splitIntoLines(); },
|
||||
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"},
|
||||
readonly: true
|
||||
}];
|
||||
|
||||
// commands active in multiselect mode
|
||||
exports.multiSelectCommands = [{
|
||||
name: "singleSelection",
|
||||
bindKey: "esc",
|
||||
exec: function(editor) { editor.exitMultiSelectMode(); },
|
||||
readonly: true,
|
||||
isAvailable: function(editor) {return editor && editor.inMultiSelectMode}
|
||||
}];
|
||||
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
exports.keyboardHandler = new HashHandler(exports.multiSelectCommands);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,124 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"no use strict";
|
||||
|
||||
var lang = require("./lib/lang");
|
||||
|
||||
var global = (function() {
|
||||
return this;
|
||||
})();
|
||||
|
||||
var options = {
|
||||
packaged: false,
|
||||
workerPath: "",
|
||||
modePath: "",
|
||||
themePath: "",
|
||||
suffix: ".js"
|
||||
};
|
||||
|
||||
exports.get = function(key) {
|
||||
if (!options.hasOwnProperty(key))
|
||||
throw new Error("Unknown config key: " + key);
|
||||
|
||||
return options[key];
|
||||
};
|
||||
|
||||
exports.set = function(key, value) {
|
||||
if (!options.hasOwnProperty(key))
|
||||
throw new Error("Unknown config key: " + key);
|
||||
|
||||
options[key] = value;
|
||||
};
|
||||
|
||||
exports.all = function() {
|
||||
return lang.copyObject(options);
|
||||
};
|
||||
|
||||
exports.init = function() {
|
||||
options.packaged = require.packaged || module.packaged || (global.define && define.packaged);
|
||||
|
||||
if (!global.document)
|
||||
return "";
|
||||
|
||||
var scriptOptions = {};
|
||||
var scriptUrl = "";
|
||||
|
||||
var scripts = document.getElementsByTagName("script");
|
||||
for (var i=0; i<scripts.length; i++) {
|
||||
var script = scripts[i];
|
||||
|
||||
var src = script.src || script.getAttribute("src");
|
||||
if (!src) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var attributes = script.attributes;
|
||||
for (var j=0, l=attributes.length; j < l; j++) {
|
||||
var attr = attributes[j];
|
||||
if (attr.name.indexOf("data-ace-") === 0) {
|
||||
scriptOptions[deHyphenate(attr.name.replace(/^data-ace-/, ""))] = attr.value;
|
||||
}
|
||||
}
|
||||
|
||||
var m = src.match(/^(.*)\/ace(\-\w+)?\.js(\?|$)/);
|
||||
if (m)
|
||||
scriptUrl = m[1];
|
||||
}
|
||||
|
||||
if (scriptUrl) {
|
||||
scriptOptions.base = scriptOptions.base || scriptUrl;
|
||||
scriptOptions.packaged = true;
|
||||
}
|
||||
|
||||
scriptOptions.workerPath = scriptOptions.workerPath || scriptOptions.base;
|
||||
scriptOptions.modePath = scriptOptions.modePath || scriptOptions.base;
|
||||
scriptOptions.themePath = scriptOptions.themePath || scriptOptions.base;
|
||||
delete scriptOptions.base;
|
||||
|
||||
for (var key in scriptOptions)
|
||||
if (typeof scriptOptions[key] !== "undefined")
|
||||
exports.set(key, scriptOptions[key]);
|
||||
};
|
||||
|
||||
function deHyphenate(str) {
|
||||
return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); });
|
||||
}
|
||||
|
||||
});
|
||||
|
After Width: | Height: | Size: 759 B |
@@ -0,0 +1,327 @@
|
||||
.ace_editor {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Droid Sans Mono', 'Consolas', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ace_scroller {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ace_content {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.ace_gutter {
|
||||
position: absolute;
|
||||
overflow : hidden;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.ace_scroller.horscroll {
|
||||
box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;
|
||||
}
|
||||
|
||||
.ace_gutter-cell {
|
||||
padding-left: 19px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_error {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUM2OEZDQTQ4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUM2OEZDQTU4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQzY4RkNBMjhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQzY4RkNBMzhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkgXxbAAAAJbSURBVHjapFNNaBNBFH4zs5vdZLP5sQmNpT82QY209heh1ioWisaDRcSKF0WKJ0GQnrzrxasHsR6EnlrwD0TagxJabaVEpFYxLWlLSS822tr87m66ccfd2GKyVhA6MMybgfe97/vmPUQphd0sZjto9XIn9OOsvlu2nkqRzVU+6vvlzPf8W6bk8dxQ0NPbxAALgCgg2JkaQuhzQau/El0zbmUA7U0Es8v2CiYmKQJHGO1QICCLoqilMhkmurDAyapKgqItezi/USRdJqEYY4D5jCy03ht2yMkkvL91jTTX10qzyyu2hruPRN7jgbH+EOsXcMLgYiThEgAMhABW85oqy1DXdRIdvP1AHJ2acQXvDIrVHcdQNrEKNYSVMSZGMjEzIIAwDXIo+6G/FxcGnzkC3T2oMhLjre49sBB+RRcHLqdafK6sYdE/GGBwU1VpFNj0aN8pJbe+BkZyevUrvLl6Xmm0W9IuTc0DxrDNAJd5oEvI/KRsNC3bQyNjPO9yQ1YHcfj2QvfQc/5TUhJTBc2iM0U7AWDQtc1nJHvD/cfO2s7jaGkiTEfa/Ep8coLu7zmNmh8+dc5lZDuUeFAGUNA/OY6JVaypQ0vjr7XYjUvJM37vt+j1vuTK5DgVfVUoTjVe+y3/LxMxY2GgU+CSLy4cpfsYorRXuXIOi0Vt40h67uZFTdIo6nLaZcwUJWAzwNS0tBnqqKzQDnjdG/iPyZxo46HaKUpbvYkj8qYRTZsBhge+JHhZyh0x9b95JqjVJkT084kZIPwu/mPWqPgfQ5jXh2+92Ay7HedfAgwA6KDWafb4w3cAAAAASUVORK5CYII=");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUM2OEZDQTg4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUM2OEZDQTk4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQzY4RkNBNjhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQzY4RkNBNzhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pgd7PfIAAAGmSURBVHjaYvr//z8DJZiJgUIANoCRkREb9gLiSVAaQx4OQM7AAkwd7XU2/v++/rOttdYGEB9dASEvOMydGKfH8Gv/p4XTkvRBfLxeQAP+1cUhXopyvzhP7P/IoSj7g7Mw09cNKO6J1QQ0L4gICPIv/veg/8W+JdFvQNLHVsW9/nmn9zk7B+cCkDwhL7gt6knSZnx9/LuCEOcvkIAMP+cvto9nfqyZmmUAksfnBUtbM60gX/3/kgyv3/xSFOL5DZT+L8vP+Yfh5cvfPvp/xUHyQHXGyAYwgpwBjZYFT3Y1OEl/OfCH4ffv3wzc4iwMvNIsDJ+f/mH4+vIPAxsb631WW0Yln6ZpQLXdMK/DXGDflh+sIv37EivD5x//Gb7+YWT4y86sl7BCCkSD+Z++/1dkvsFRl+HnD1Rvje4F8whjMXmGj58YGf5zsDMwcnAwfPvKcml62DsQDeaDxN+/Y0qwlpEHqrdB94IRNIDUgfgfKJChGK4OikEW3gTiXUB950ASLFAF54AC94A0G9QAfOnmF9DCDzABFqS08IHYDIScdijOjQABBgC+/9awBH96jwAAAABJRU5ErkJggg==");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_info {
|
||||
background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQAAAAAAEFBQVJSUl5eXmRkZGtra39/f4WFhYmJiZGRkaampry8vMPDw8zMzNXV1dzc3OTk5Orq6vDw8P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABQALAAAAAAQABAAAAUuICWOZGmeaBml5XGwFCQSBGyXRSAwtqQIiRuiwIM5BoYVbEFIyGCQoeJGrVptIQA7");
|
||||
background-position: 2px center;
|
||||
}
|
||||
.ace_dark .ace_gutter-cell.ace_info {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRTk5MTVGREIxNDkxMUUxOTc5Q0FFREQyMTNGMjBFQyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRTk5MTVGRUIxNDkxMUUxOTc5Q0FFREQyMTNGMjBFQyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZFOTkxNUZCQjE0OTExRTE5NzlDQUVERDIxM0YyMEVDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkZFOTkxNUZDQjE0OTExRTE5NzlDQUVERDIxM0YyMEVDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+SIDkjAAAAJ1JREFUeNpi/P//PwMlgImBQkB7A6qrq/+DMC55FkIGKCoq4pVnpFkgTp069f/+/fv/r1u37r+tre1/kg0A+ptn9uzZYLaRkRHpLvjw4cNXWVlZhufPnzOcO3eOdAO0tbVPAjHDmzdvGA4fPsxIsgGSkpJmv379Ynj37h2DjIyMCMkG3LhxQ/T27dsMampqDHZ2dq/pH41DxwCAAAMAFdc68dUsFZgAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.ace_editor .ace_sb {
|
||||
position: absolute;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ace_editor .ace_sb div {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ace_editor .ace_print_margin_layer {
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ace_editor .ace_print_margin {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ace_editor > textarea {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
width: 0.5em;
|
||||
height: 1em;
|
||||
opacity: 0;
|
||||
background: transparent;
|
||||
appearance: none;
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
resize: none;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ace_editor > textarea.ace_composition {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 1000;
|
||||
opacity: 1;
|
||||
border: solid lightgray 1px;
|
||||
margin: -1px
|
||||
}
|
||||
|
||||
.ace_layer {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
/* setting pointer-events: auto; on node under the mouse, which changes
|
||||
during scroll, will break mouse wheel scrolling in Safari */
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ace_gutter .ace_layer {
|
||||
position: relative;
|
||||
min-width: 40px;
|
||||
width: auto;
|
||||
text-align: right;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.ace_text-layer {
|
||||
color: black;
|
||||
font: inherit !important;
|
||||
}
|
||||
|
||||
.ace_cjk {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ace_cursor-layer {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.ace_cursor {
|
||||
z-index: 4;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.ace_cursor.ace_hidden {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.ace_editor.multiselect .ace_cursor {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.ace_line {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_step {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_selection {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_bracket {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_active_line {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_selected_word {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ace_line .ace_fold {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
|
||||
display: inline-block;
|
||||
height: 11px;
|
||||
margin-top: -2px;
|
||||
vertical-align: middle;
|
||||
|
||||
background-image:
|
||||
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82"),
|
||||
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%3AIDAT8%11c%FC%FF%FF%7F%18%03%1A%60%01%F2%3F%A0%891%80%04%FF%11-%F8%17%9BJ%E2%05%B1ZD%81v%26t%E7%80%F8%A3%82h%A12%1A%20%A3%01%02%0F%01%BA%25%06%00%19%C0%0D%AEF%D5%3ES%00%00%00%00IEND%AEB%60%82");
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
background-position: center center, top left;
|
||||
color: transparent;
|
||||
|
||||
border: 1px solid black;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.ace_dark .ace_fold {
|
||||
}
|
||||
|
||||
.ace_fold:hover{
|
||||
background-image:
|
||||
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82"),
|
||||
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%003IDAT8%11c%FC%FF%FF%7F%3E%03%1A%60%01%F2%3F%A3%891%80%04%FFQ%26%F8w%C0%B43%A1%DB%0C%E2%8F%0A%A2%85%CAh%80%8C%06%08%3C%04%E8%96%18%00%A3S%0D%CD%CF%D8%C1%9D%00%00%00%00IEND%AEB%60%82");
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
background-position: center center, top left;
|
||||
}
|
||||
|
||||
.ace_dragging .ace_content {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.ace_folding-enabled > .ace_gutter-cell {
|
||||
padding-right: 13px;
|
||||
}
|
||||
|
||||
.ace_fold-widget {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
|
||||
margin: 0 -12px 1px 1px;
|
||||
display: inline-block;
|
||||
height: 14px;
|
||||
width: 11px;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAe%8A%B1%0D%000%0C%C2%F2%2CK%96%BC%D0%8F9%81%88H%E9%D0%0E%96%C0%10%92%3E%02%80%5E%82%E4%A9*-%EEsw%C8%CC%11%EE%96w%D8%DC%E9*Eh%0C%151(%00%00%00%00IEND%AEB%60%82");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center 4px;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.ace_fold-widget.end {
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAm%C7%C1%09%000%08C%D1%8C%ECE%C8E(%8E%EC%02)%1EZJ%F1%C1'%04%07I%E1%E5%EE%CAL%F5%A2%99%99%22%E2%D6%1FU%B5%FE0%D9x%A7%26Wz5%0E%D5%00%00%00%00IEND%AEB%60%82");
|
||||
}
|
||||
|
||||
.ace_fold-widget.closed {
|
||||
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%03%00%00%00%06%08%06%00%00%00%06%E5%24%0C%00%00%009IDATx%DA5%CA%C1%09%000%08%03%C0%AC*(%3E%04%C1%0D%BA%B1%23%A4Uh%E0%20%81%C0%CC%F8%82%81%AA%A2%AArGfr%88%08%11%11%1C%DD%7D%E0%EE%5B%F6%F6%CB%B8%05Q%2F%E9tai%D9%00%00%00%00IEND%AEB%60%82");
|
||||
}
|
||||
|
||||
.ace_fold-widget:hover {
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
|
||||
background-position: center 4px;
|
||||
}
|
||||
|
||||
.ace_fold-widget:active {
|
||||
border: 1px solid rgba(0, 0, 0, 0.4);
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
/**
|
||||
* Dark version for fold widgets
|
||||
*/
|
||||
.ace_dark .ace_fold-widget {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");
|
||||
}
|
||||
.ace_dark .ace_fold-widget.end {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");
|
||||
}
|
||||
.ace_dark .ace_fold-widget.closed {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");
|
||||
}
|
||||
.ace_dark .ace_fold-widget:hover {
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.ace_dark .ace_fold-widget:active {
|
||||
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ace_fold-widget.invalid {
|
||||
background-color: #FFB4B4;
|
||||
border-color: #DE5555;
|
||||
}
|
||||
|
||||
.ace_fade-fold-widgets .ace_fold-widget {
|
||||
-moz-transition: opacity 0.4s ease 0.05s;
|
||||
-webkit-transition: opacity 0.4s ease 0.05s;
|
||||
-o-transition: opacity 0.4s ease 0.05s;
|
||||
-ms-transition: opacity 0.4s ease 0.05s;
|
||||
transition: opacity 0.4s ease 0.05s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.ace_fade-fold-widgets:hover .ace_fold-widget {
|
||||
-moz-transition: opacity 0.05s ease 0.05s;
|
||||
-webkit-transition: opacity 0.05s ease 0.05s;
|
||||
-o-transition: opacity 0.05s ease 0.05s;
|
||||
-ms-transition: opacity 0.05s ease 0.05s;
|
||||
transition: opacity 0.05s ease 0.05s;
|
||||
opacity:1;
|
||||
}
|
||||
|
After Width: | Height: | Size: 290 B |
@@ -0,0 +1,617 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var EventEmitter = require("./lib/event_emitter").EventEmitter;
|
||||
var Range = require("./range").Range;
|
||||
var Anchor = require("./anchor").Anchor;
|
||||
|
||||
/**
|
||||
* class Document
|
||||
*
|
||||
* Contains the text of the document. Documents are controlled by a single [[EditSession `EditSession`]]. At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new Document([text])
|
||||
* - text (String | Array): The starting text
|
||||
*
|
||||
* Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty.
|
||||
*
|
||||
**/
|
||||
var Document = function(text) {
|
||||
this.$lines = [];
|
||||
|
||||
// There has to be one line at least in the document. If you pass an empty
|
||||
// string to the insert function, nothing will happen. Workaround.
|
||||
if (text.length == 0) {
|
||||
this.$lines = [""];
|
||||
} else if (Array.isArray(text)) {
|
||||
this.insertLines(0, text);
|
||||
} else {
|
||||
this.insert({row: 0, column:0}, text);
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, EventEmitter);
|
||||
|
||||
/**
|
||||
* Document.setValue(text) -> Void
|
||||
* - text (String): The text to use
|
||||
*
|
||||
* Replaces all the lines in the current `Document` with the value of `text`.
|
||||
**/
|
||||
this.setValue = function(text) {
|
||||
var len = this.getLength();
|
||||
this.remove(new Range(0, 0, len, this.getLine(len-1).length));
|
||||
this.insert({row: 0, column:0}, text);
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getValue() -> String
|
||||
*
|
||||
* Returns all the lines in the document as a single string, split by the new line character.
|
||||
**/
|
||||
this.getValue = function() {
|
||||
return this.getAllLines().join(this.getNewLineCharacter());
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.createAnchor(row, column) -> Anchor
|
||||
* - row (Number): The row number to use
|
||||
* - column (Number): The column number to use
|
||||
*
|
||||
* Creates a new `Anchor` to define a floating point in the document.
|
||||
**/
|
||||
this.createAnchor = function(row, column) {
|
||||
return new Anchor(this, row, column);
|
||||
};
|
||||
|
||||
/** internal, hide
|
||||
* Document.$split(text) -> [String]
|
||||
* - text (String): The text to work with
|
||||
* + ([String]): A String array, with each index containing a piece of the original `text` string.
|
||||
*
|
||||
* Splits a string of text on any newline (`\n`) or carriage-return ('\r') characters.
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
// check for IE split bug
|
||||
if ("aaa".split(/a/).length == 0)
|
||||
this.$split = function(text) {
|
||||
return text.replace(/\r\n|\r/g, "\n").split("\n");
|
||||
}
|
||||
else
|
||||
this.$split = function(text) {
|
||||
return text.split(/\r\n|\r|\n/);
|
||||
};
|
||||
|
||||
|
||||
/** internal, hide
|
||||
* Document.$detectNewLine(text) -> Void
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.$detectNewLine = function(text) {
|
||||
var match = text.match(/^.*?(\r\n|\r|\n)/m);
|
||||
if (match) {
|
||||
this.$autoNewLine = match[1];
|
||||
} else {
|
||||
this.$autoNewLine = "\n";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getNewLineCharacter() -> String
|
||||
* + (String): If `newLineMode == windows`, `\r\n` is returned.<br/>
|
||||
* If `newLineMode == unix`, `\n` is returned.<br/>
|
||||
* If `newLineMode == auto`, the value of `autoNewLine` is returned.
|
||||
*
|
||||
* Returns the newline character that's being used, depending on the value of `newLineMode`.
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.getNewLineCharacter = function() {
|
||||
switch (this.$newLineMode) {
|
||||
case "windows":
|
||||
return "\r\n";
|
||||
|
||||
case "unix":
|
||||
return "\n";
|
||||
|
||||
case "auto":
|
||||
return this.$autoNewLine;
|
||||
}
|
||||
};
|
||||
|
||||
this.$autoNewLine = "\n";
|
||||
this.$newLineMode = "auto";
|
||||
/**
|
||||
* Document.setNewLineMode(newLineMode) -> Void
|
||||
* - newLineMode(String): [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param}
|
||||
*
|
||||
* [Sets the new line mode.]{: #Document.setNewLineMode.desc}
|
||||
**/
|
||||
this.setNewLineMode = function(newLineMode) {
|
||||
if (this.$newLineMode === newLineMode)
|
||||
return;
|
||||
|
||||
this.$newLineMode = newLineMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getNewLineMode() -> String
|
||||
*
|
||||
* [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode}
|
||||
*
|
||||
**/
|
||||
this.getNewLineMode = function() {
|
||||
return this.$newLineMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.isNewLine(text) -> Boolean
|
||||
* - text (String): The text to check
|
||||
*
|
||||
* Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`).
|
||||
*
|
||||
**/
|
||||
this.isNewLine = function(text) {
|
||||
return (text == "\r\n" || text == "\r" || text == "\n");
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getLine(row) -> String
|
||||
* - row (Number): The row index to retrieve
|
||||
*
|
||||
* Returns a verbatim copy of the given line as it is in the document
|
||||
*
|
||||
**/
|
||||
this.getLine = function(row) {
|
||||
return this.$lines[row] || "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getLines(firstRow, lastRow) -> [String]
|
||||
* - firstRow (Number): The first row index to retrieve
|
||||
* - lastRow (Number): The final row index to retrieve
|
||||
*
|
||||
* Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`.
|
||||
*
|
||||
**/
|
||||
this.getLines = function(firstRow, lastRow) {
|
||||
return this.$lines.slice(firstRow, lastRow + 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getAllLines() -> [String]
|
||||
*
|
||||
* Returns all lines in the document as string array. Warning: The caller should not modify this array!
|
||||
**/
|
||||
this.getAllLines = function() {
|
||||
return this.getLines(0, this.getLength());
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getLength() -> Number
|
||||
*
|
||||
* Returns the number of rows in the document.
|
||||
**/
|
||||
this.getLength = function() {
|
||||
return this.$lines.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.getTextRange(range) -> String
|
||||
* - range (Range): The range to work with
|
||||
*
|
||||
* [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc}
|
||||
**/
|
||||
this.getTextRange = function(range) {
|
||||
if (range.start.row == range.end.row) {
|
||||
return this.$lines[range.start.row].substring(range.start.column,
|
||||
range.end.column);
|
||||
}
|
||||
else {
|
||||
var lines = this.getLines(range.start.row+1, range.end.row-1);
|
||||
lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column));
|
||||
lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column));
|
||||
return lines.join(this.getNewLineCharacter());
|
||||
}
|
||||
};
|
||||
|
||||
/** internal, hide
|
||||
* Document.$clipPosition(position) -> Number
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.$clipPosition = function(position) {
|
||||
var length = this.getLength();
|
||||
if (position.row >= length) {
|
||||
position.row = Math.max(0, length - 1);
|
||||
position.column = this.getLine(length-1).length;
|
||||
}
|
||||
return position;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.insert(position, text) -> Number
|
||||
* - position (Number): The position to start inserting at
|
||||
* - text (String): A chunk of text to insert
|
||||
* + (Number): The position of the last line of `text`. If the length of `text` is 0, this function simply returns `position`.
|
||||
* Inserts a block of `text` and the indicated `position`.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.insert = function(position, text) {
|
||||
if (!text || text.length === 0)
|
||||
return position;
|
||||
|
||||
position = this.$clipPosition(position);
|
||||
|
||||
// only detect new lines if the document has no line break yet
|
||||
if (this.getLength() <= 1)
|
||||
this.$detectNewLine(text);
|
||||
|
||||
var lines = this.$split(text);
|
||||
var firstLine = lines.splice(0, 1)[0];
|
||||
var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
|
||||
|
||||
position = this.insertInLine(position, firstLine);
|
||||
if (lastLine !== null) {
|
||||
position = this.insertNewLine(position); // terminate first line
|
||||
position = this.insertLines(position.row, lines);
|
||||
position = this.insertInLine(position, lastLine || "");
|
||||
}
|
||||
return position;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.insertLines(row, lines) -> Object
|
||||
* - row (Number): The index of the row to insert at
|
||||
* - lines (Array): An array of strings
|
||||
* + (Object): Returns an object containing the final row and column, like this:<br/>
|
||||
* ```{row: endRow, column: 0}```<br/>
|
||||
* If `lines` is empty, this function returns an object containing the current row, and column, like this:<br/>
|
||||
* ```{row: row, column: 0}```
|
||||
*
|
||||
* Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.insertLines = function(row, lines) {
|
||||
if (lines.length == 0)
|
||||
return {row: row, column: 0};
|
||||
|
||||
// apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF)
|
||||
// to circumvent that we have to break huge inserts into smaller chunks here
|
||||
if (lines.length > 0xFFFF) {
|
||||
var end = this.insertLines(row, lines.slice(0xFFFF));
|
||||
lines = lines.slice(0, 0xFFFF);
|
||||
}
|
||||
|
||||
var args = [row, 0];
|
||||
args.push.apply(args, lines);
|
||||
this.$lines.splice.apply(this.$lines, args);
|
||||
|
||||
var range = new Range(row, 0, row + lines.length, 0);
|
||||
var delta = {
|
||||
action: "insertLines",
|
||||
range: range,
|
||||
lines: lines
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
return end || range.end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.insertNewLine(position) -> Object
|
||||
* - position (String): The position to insert at
|
||||
* + (Object): Returns an object containing the final row and column, like this:<br/>
|
||||
* ```{row: endRow, column: 0}```
|
||||
*
|
||||
* Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.insertNewLine = function(position) {
|
||||
position = this.$clipPosition(position);
|
||||
var line = this.$lines[position.row] || "";
|
||||
|
||||
this.$lines[position.row] = line.substring(0, position.column);
|
||||
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
|
||||
|
||||
var end = {
|
||||
row : position.row + 1,
|
||||
column : 0
|
||||
};
|
||||
|
||||
var delta = {
|
||||
action: "insertText",
|
||||
range: Range.fromPoints(position, end),
|
||||
text: this.getNewLineCharacter()
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.insertInLine(position, text) -> Object | Number
|
||||
* - position (Number): The position to insert at
|
||||
* - text (String): A chunk of text
|
||||
* + (Object): Returns an object containing the final row and column, like this:<br/>
|
||||
* ```{row: endRow, column: 0}```
|
||||
* + (Number): If `text` is empty, this function returns the value of `position`
|
||||
*
|
||||
* Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.insertInLine = function(position, text) {
|
||||
if (text.length == 0)
|
||||
return position;
|
||||
|
||||
var line = this.$lines[position.row] || "";
|
||||
|
||||
this.$lines[position.row] = line.substring(0, position.column) + text
|
||||
+ line.substring(position.column);
|
||||
|
||||
var end = {
|
||||
row : position.row,
|
||||
column : position.column + text.length
|
||||
};
|
||||
|
||||
var delta = {
|
||||
action: "insertText",
|
||||
range: Range.fromPoints(position, end),
|
||||
text: text
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.remove(range) -> Object
|
||||
* - range (Range): A specified Range to remove
|
||||
* + (Object): Returns the new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`.
|
||||
*
|
||||
* Removes the `range` from the document.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.remove = function(range) {
|
||||
// clip to document
|
||||
range.start = this.$clipPosition(range.start);
|
||||
range.end = this.$clipPosition(range.end);
|
||||
|
||||
if (range.isEmpty())
|
||||
return range.start;
|
||||
|
||||
var firstRow = range.start.row;
|
||||
var lastRow = range.end.row;
|
||||
|
||||
if (range.isMultiLine()) {
|
||||
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
|
||||
var lastFullRow = lastRow - 1;
|
||||
|
||||
if (range.end.column > 0)
|
||||
this.removeInLine(lastRow, 0, range.end.column);
|
||||
|
||||
if (lastFullRow >= firstFullRow)
|
||||
this.removeLines(firstFullRow, lastFullRow);
|
||||
|
||||
if (firstFullRow != firstRow) {
|
||||
this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
|
||||
this.removeNewLine(range.start.row);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.removeInLine(firstRow, range.start.column, range.end.column);
|
||||
}
|
||||
return range.start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.removeInLine(row, startColumn, endColumn) -> Object
|
||||
* - row (Number): The row to remove from
|
||||
* - startColumn (Number): The column to start removing at
|
||||
* - endColumn (Number): The column to stop removing at
|
||||
* + (Object): Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.<br/>If `startColumn` is equal to `endColumn`, this function returns nothing.
|
||||
*
|
||||
* Removes the specified columns from the `row`. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.removeInLine = function(row, startColumn, endColumn) {
|
||||
if (startColumn == endColumn)
|
||||
return;
|
||||
|
||||
var range = new Range(row, startColumn, row, endColumn);
|
||||
var line = this.getLine(row);
|
||||
var removed = line.substring(startColumn, endColumn);
|
||||
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
|
||||
this.$lines.splice(row, 1, newLine);
|
||||
|
||||
var delta = {
|
||||
action: "removeText",
|
||||
range: range,
|
||||
text: removed
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
return range.start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.removeLines(firstRow, lastRow) -> [String]
|
||||
* - firstRow (Number): The first row to be removed
|
||||
* - lastRow (Number): The last row to be removed
|
||||
* + ([String]): Returns all the removed lines.
|
||||
*
|
||||
* Removes a range of full lines. This method also triggers the `'change'` event.
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.removeLines = function(firstRow, lastRow) {
|
||||
var range = new Range(firstRow, 0, lastRow + 1, 0);
|
||||
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
|
||||
|
||||
var delta = {
|
||||
action: "removeLines",
|
||||
range: range,
|
||||
nl: this.getNewLineCharacter(),
|
||||
lines: removed
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
return removed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.removeNewLine(row) -> Void
|
||||
* - row (Number): The row to check
|
||||
*
|
||||
* Removes the new line between `row` and the row immediately following it. This method also triggers the `'change'` event.
|
||||
*
|
||||
**/
|
||||
this.removeNewLine = function(row) {
|
||||
var firstLine = this.getLine(row);
|
||||
var secondLine = this.getLine(row+1);
|
||||
|
||||
var range = new Range(row, firstLine.length, row+1, 0);
|
||||
var line = firstLine + secondLine;
|
||||
|
||||
this.$lines.splice(row, 2, line);
|
||||
|
||||
var delta = {
|
||||
action: "removeText",
|
||||
range: range,
|
||||
text: this.getNewLineCharacter()
|
||||
};
|
||||
this._emit("change", { data: delta });
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.replace(range, text) -> Object
|
||||
* - range (Range): A specified Range to replace
|
||||
* - text (String): The new text to use as a replacement
|
||||
* + (Object): Returns an object containing the final row and column, like this:
|
||||
* {row: endRow, column: 0}
|
||||
* If the text and range are empty, this function returns an object containing the current `range.start` value.
|
||||
* If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value.
|
||||
*
|
||||
* Replaces a range in the document with the new `text`.
|
||||
*
|
||||
**/
|
||||
this.replace = function(range, text) {
|
||||
if (text.length == 0 && range.isEmpty())
|
||||
return range.start;
|
||||
|
||||
// Shortcut: If the text we want to insert is the same as it is already
|
||||
// in the document, we don't have to replace anything.
|
||||
if (text == this.getTextRange(range))
|
||||
return range.end;
|
||||
|
||||
this.remove(range);
|
||||
if (text) {
|
||||
var end = this.insert(range.start, text);
|
||||
}
|
||||
else {
|
||||
end = range.start;
|
||||
}
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.applyDeltas(deltas) -> Void
|
||||
*
|
||||
* Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
**/
|
||||
this.applyDeltas = function(deltas) {
|
||||
for (var i=0; i<deltas.length; i++) {
|
||||
var delta = deltas[i];
|
||||
var range = Range.fromPoints(delta.range.start, delta.range.end);
|
||||
|
||||
if (delta.action == "insertLines")
|
||||
this.insertLines(range.start.row, delta.lines);
|
||||
else if (delta.action == "insertText")
|
||||
this.insert(range.start, delta.text);
|
||||
else if (delta.action == "removeLines")
|
||||
this.removeLines(range.start.row, range.end.row - 1);
|
||||
else if (delta.action == "removeText")
|
||||
this.remove(range);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Document.revertDeltas(deltas) -> Void
|
||||
*
|
||||
* Reverts any changes previously applied. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
|
||||
**/
|
||||
this.revertDeltas = function(deltas) {
|
||||
for (var i=deltas.length-1; i>=0; i--) {
|
||||
var delta = deltas[i];
|
||||
|
||||
var range = Range.fromPoints(delta.range.start, delta.range.end);
|
||||
|
||||
if (delta.action == "insertLines")
|
||||
this.removeLines(range.start.row, range.end.row - 1);
|
||||
else if (delta.action == "insertText")
|
||||
this.remove(range);
|
||||
else if (delta.action == "removeLines")
|
||||
this.insertLines(range.start.row, delta.lines);
|
||||
else if (delta.action == "removeText")
|
||||
this.insert(range.start, delta.text);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(Document.prototype);
|
||||
|
||||
exports.Document = Document;
|
||||
});
|
||||
@@ -0,0 +1,314 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Document = require("./document").Document;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test: insert text in line" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insert({row: 0, column: 1}, "juhu");
|
||||
assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert new line" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insertNewLine({row: 0, column: 1});
|
||||
assert.equal(doc.getValue(), ["1", "2", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1", "2", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert lines at the beginning" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insertLines(0, ["aa", "bb"]);
|
||||
assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert lines at the end" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insertLines(2, ["aa", "bb"]);
|
||||
assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert lines in the middle" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insertLines(1, ["aa", "bb"]);
|
||||
assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert multi line string at the start" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insert({row: 0, column: 0}, "aa\nbb\ncc");
|
||||
assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert multi line string at the end" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insert({row: 2, column: 0}, "aa\nbb\ncc");
|
||||
assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n"));
|
||||
},
|
||||
|
||||
"test: insert multi line string in the middle" : function() {
|
||||
var doc = new Document(["12", "34"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.insert({row: 0, column: 1}, "aa\nbb\ncc");
|
||||
assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n"));
|
||||
},
|
||||
|
||||
"test: delete in line" : function() {
|
||||
var doc = new Document(["1234", "5678"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.remove(new Range(0, 1, 0, 3));
|
||||
assert.equal(doc.getValue(), ["14", "5678"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1234", "5678"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["14", "5678"].join("\n"));
|
||||
},
|
||||
|
||||
"test: delete new line" : function() {
|
||||
var doc = new Document(["1234", "5678"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.remove(new Range(0, 4, 1, 0));
|
||||
assert.equal(doc.getValue(), ["12345678"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1234", "5678"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12345678"].join("\n"));
|
||||
},
|
||||
|
||||
"test: delete multi line range line" : function() {
|
||||
var doc = new Document(["1234", "5678", "abcd"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.remove(new Range(0, 2, 2, 2));
|
||||
assert.equal(doc.getValue(), ["12cd"].join("\n"));
|
||||
|
||||
var d = deltas.concat();
|
||||
doc.revertDeltas(d);
|
||||
assert.equal(doc.getValue(), ["1234", "5678", "abcd"].join("\n"));
|
||||
|
||||
doc.applyDeltas(d);
|
||||
assert.equal(doc.getValue(), ["12cd"].join("\n"));
|
||||
},
|
||||
|
||||
"test: delete full lines" : function() {
|
||||
var doc = new Document(["1234", "5678", "abcd"]);
|
||||
|
||||
var deltas = [];
|
||||
doc.on("change", function(e) { deltas.push(e.data); });
|
||||
|
||||
doc.remove(new Range(1, 0, 3, 0));
|
||||
assert.equal(doc.getValue(), ["1234", ""].join("\n"));
|
||||
},
|
||||
|
||||
"test: remove lines should return the removed lines" : function() {
|
||||
var doc = new Document(["1234", "5678", "abcd"]);
|
||||
|
||||
var removed = doc.removeLines(1, 2);
|
||||
assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n"));
|
||||
},
|
||||
|
||||
"test: should handle unix style new lines" : function() {
|
||||
var doc = new Document(["1", "2", "3"]);
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: should handle windows style new lines" : function() {
|
||||
var doc = new Document(["1", "2", "3"].join("\r\n"));
|
||||
|
||||
doc.setNewLineMode("unix");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: set new line mode to 'windows' should use '\\r\\n' as new lines": function() {
|
||||
var doc = new Document(["1", "2", "3"].join("\n"));
|
||||
doc.setNewLineMode("windows");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n"));
|
||||
},
|
||||
|
||||
"test: set new line mode to 'unix' should use '\\n' as new lines": function() {
|
||||
var doc = new Document(["1", "2", "3"].join("\r\n"));
|
||||
|
||||
doc.setNewLineMode("unix");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: set new line mode to 'auto' should detect the incoming nl type": function() {
|
||||
var doc = new Document(["1", "2", "3"].join("\n"));
|
||||
|
||||
doc.setNewLineMode("auto");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
|
||||
|
||||
var doc = new Document(["1", "2", "3"].join("\r\n"));
|
||||
|
||||
doc.setNewLineMode("auto");
|
||||
assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n"));
|
||||
|
||||
doc.replace(new Range(0, 0, 2, 1), ["4", "5", "6"].join("\n"));
|
||||
assert.equal(["4", "5", "6"].join("\n"), doc.getValue());
|
||||
},
|
||||
|
||||
"test: set value": function() {
|
||||
var doc = new Document("1");
|
||||
assert.equal("1", doc.getValue());
|
||||
|
||||
doc.setValue(doc.getValue());
|
||||
assert.equal("1", doc.getValue());
|
||||
|
||||
var doc = new Document("1\n2");
|
||||
assert.equal("1\n2", doc.getValue());
|
||||
|
||||
doc.setValue(doc.getValue());
|
||||
assert.equal("1\n2", doc.getValue());
|
||||
},
|
||||
|
||||
"test: empty document has to contain one line": function() {
|
||||
var doc = new Document("");
|
||||
assert.equal(doc.$lines.length, 1);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var TokenIterator = require("../token_iterator").TokenIterator;
|
||||
var Range = require("../range").Range;
|
||||
|
||||
/**
|
||||
* class BracketMatch
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* new BracketMatch(position)
|
||||
* - platform (String): Identifier for the platform; must be either `'mac'` or `'win'`
|
||||
* - commands (Array): A list of commands
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
*
|
||||
**/
|
||||
function BracketMatch() {
|
||||
|
||||
/**
|
||||
* new findMatchingBracket(position)
|
||||
* - position (Number): Identifier for the platform; must be either `'mac'` or `'win'`
|
||||
* - commands (Array): A list of commands
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
*
|
||||
**/
|
||||
this.findMatchingBracket = function(position) {
|
||||
if (position.column == 0) return null;
|
||||
|
||||
var charBeforeCursor = this.getLine(position.row).charAt(position.column-1);
|
||||
if (charBeforeCursor == "") return null;
|
||||
|
||||
var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/);
|
||||
if (!match)
|
||||
return null;
|
||||
|
||||
if (match[1])
|
||||
return this.$findClosingBracket(match[1], position);
|
||||
else
|
||||
return this.$findOpeningBracket(match[2], position);
|
||||
};
|
||||
|
||||
this.getBracketRange = function(pos) {
|
||||
var line = this.getLine(pos.row);
|
||||
var before = true, range;
|
||||
|
||||
var chr = line.charAt(pos.column-1);
|
||||
var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/);
|
||||
if (!match) {
|
||||
chr = line.charAt(pos.column);
|
||||
pos = {row: pos.row, column: pos.column + 1};
|
||||
match = chr && chr.match(/([\(\[\{])|([\)\]\}])/);
|
||||
before = false;
|
||||
}
|
||||
if (!match)
|
||||
return null;
|
||||
|
||||
if (match[1]) {
|
||||
var bracketPos = this.$findClosingBracket(match[1], pos);
|
||||
if (!bracketPos)
|
||||
return null;
|
||||
range = Range.fromPoints(pos, bracketPos);
|
||||
if (!before) {
|
||||
range.end.column++;
|
||||
range.start.column--;
|
||||
}
|
||||
range.cursor = range.end;
|
||||
} else {
|
||||
var bracketPos = this.$findOpeningBracket(match[2], pos);
|
||||
if (!bracketPos)
|
||||
return null;
|
||||
range = Range.fromPoints(bracketPos, pos);
|
||||
if (!before) {
|
||||
range.start.column++;
|
||||
range.end.column--;
|
||||
}
|
||||
range.cursor = range.start;
|
||||
}
|
||||
|
||||
return range;
|
||||
};
|
||||
|
||||
this.$brackets = {
|
||||
")": "(",
|
||||
"(": ")",
|
||||
"]": "[",
|
||||
"[": "]",
|
||||
"{": "}",
|
||||
"}": "{"
|
||||
};
|
||||
|
||||
this.$findOpeningBracket = function(bracket, position, typeRe) {
|
||||
var openBracket = this.$brackets[bracket];
|
||||
var depth = 1;
|
||||
|
||||
var iterator = new TokenIterator(this, position.row, position.column);
|
||||
var token = iterator.getCurrentToken();
|
||||
if (!token)
|
||||
token = iterator.stepForward();
|
||||
if (!token)
|
||||
return
|
||||
|
||||
if (!typeRe){
|
||||
typeRe = new RegExp(
|
||||
"(\\.?" +
|
||||
token.type.replace(".", "\\.").replace("rparen", ".paren")
|
||||
+ ")+"
|
||||
);
|
||||
}
|
||||
|
||||
// Start searching in token, just before the character at position.column
|
||||
var valueIndex = position.column - iterator.getCurrentTokenColumn() - 2;
|
||||
var value = token.value;
|
||||
|
||||
while (true) {
|
||||
|
||||
while (valueIndex >= 0) {
|
||||
var chr = value.charAt(valueIndex);
|
||||
if (chr == openBracket) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
return {row: iterator.getCurrentTokenRow(),
|
||||
column: valueIndex + iterator.getCurrentTokenColumn()};
|
||||
}
|
||||
}
|
||||
else if (chr == bracket) {
|
||||
depth += 1;
|
||||
}
|
||||
valueIndex -= 1;
|
||||
}
|
||||
|
||||
// Scan backward through the document, looking for the next token
|
||||
// whose type matches typeRe
|
||||
do {
|
||||
token = iterator.stepBackward();
|
||||
} while (token && !typeRe.test(token.type));
|
||||
|
||||
if (token == null)
|
||||
break;
|
||||
|
||||
value = token.value;
|
||||
valueIndex = value.length - 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
this.$findClosingBracket = function(bracket, position, typeRe) {
|
||||
var closingBracket = this.$brackets[bracket];
|
||||
var depth = 1;
|
||||
|
||||
var iterator = new TokenIterator(this, position.row, position.column);
|
||||
var token = iterator.getCurrentToken();
|
||||
if (!token)
|
||||
token = iterator.stepForward();
|
||||
if (!token)
|
||||
return
|
||||
|
||||
if (!typeRe){
|
||||
typeRe = new RegExp(
|
||||
"(\\.?" +
|
||||
token.type.replace(".", "\\.").replace("lparen", ".paren")
|
||||
+ ")+"
|
||||
);
|
||||
}
|
||||
|
||||
// Start searching in token, after the character at position.column
|
||||
var valueIndex = position.column - iterator.getCurrentTokenColumn();
|
||||
|
||||
while (true) {
|
||||
|
||||
var value = token.value;
|
||||
var valueLength = value.length;
|
||||
while (valueIndex < valueLength) {
|
||||
var chr = value.charAt(valueIndex);
|
||||
if (chr == closingBracket) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
return {row: iterator.getCurrentTokenRow(),
|
||||
column: valueIndex + iterator.getCurrentTokenColumn()};
|
||||
}
|
||||
}
|
||||
else if (chr == bracket) {
|
||||
depth += 1;
|
||||
}
|
||||
valueIndex += 1;
|
||||
}
|
||||
|
||||
// Scan forward through the document, looking for the next token
|
||||
// whose type matches typeRe
|
||||
do {
|
||||
token = iterator.stepForward();
|
||||
} while (token && !typeRe.test(token.type));
|
||||
|
||||
if (token == null)
|
||||
break;
|
||||
|
||||
valueIndex = 0;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
exports.BracketMatch = BracketMatch;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,116 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Simple fold-data struct.
|
||||
**/
|
||||
var Fold = exports.Fold = function(range, placeholder) {
|
||||
this.foldLine = null;
|
||||
this.placeholder = placeholder;
|
||||
this.range = range;
|
||||
this.start = range.start;
|
||||
this.end = range.end;
|
||||
|
||||
this.sameRow = range.start.row == range.end.row;
|
||||
this.subFolds = [];
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.toString = function() {
|
||||
return '"' + this.placeholder + '" ' + this.range.toString();
|
||||
};
|
||||
|
||||
this.setFoldLine = function(foldLine) {
|
||||
this.foldLine = foldLine;
|
||||
this.subFolds.forEach(function(fold) {
|
||||
fold.setFoldLine(foldLine);
|
||||
});
|
||||
};
|
||||
|
||||
this.clone = function() {
|
||||
var range = this.range.clone();
|
||||
var fold = new Fold(range, this.placeholder);
|
||||
this.subFolds.forEach(function(subFold) {
|
||||
fold.subFolds.push(subFold.clone());
|
||||
});
|
||||
return fold;
|
||||
};
|
||||
|
||||
this.addSubFold = function(fold) {
|
||||
if (this.range.isEqual(fold))
|
||||
return this;
|
||||
|
||||
if (!this.range.containsRange(fold))
|
||||
throw "A fold can't intersect already existing fold" + fold.range + this.range;
|
||||
|
||||
var row = fold.range.start.row, column = fold.range.start.column;
|
||||
for (var i = 0, cmp = -1; i < this.subFolds.length; i++) {
|
||||
cmp = this.subFolds[i].range.compare(row, column);
|
||||
if (cmp != 1)
|
||||
break;
|
||||
}
|
||||
var afterStart = this.subFolds[i];
|
||||
|
||||
if (cmp == 0)
|
||||
return afterStart.addSubFold(fold)
|
||||
|
||||
// cmp == -1
|
||||
var row = fold.range.end.row, column = fold.range.end.column;
|
||||
for (var j = i, cmp = -1; j < this.subFolds.length; j++) {
|
||||
cmp = this.subFolds[j].range.compare(row, column);
|
||||
if (cmp != 1)
|
||||
break;
|
||||
}
|
||||
var afterEnd = this.subFolds[j];
|
||||
|
||||
if (cmp == 0)
|
||||
throw "A fold can't intersect already existing fold" + fold.range + this.range;
|
||||
|
||||
var consumedFolds = this.subFolds.splice(i, j - i, fold)
|
||||
fold.setFoldLine(this.foldLine);
|
||||
|
||||
return fold;
|
||||
}
|
||||
|
||||
}).call(Fold.prototype);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,276 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Range = require("../range").Range;
|
||||
|
||||
/*
|
||||
* If an array is passed in, the folds are expected to be sorted already.
|
||||
*/
|
||||
function FoldLine(foldData, folds) {
|
||||
this.foldData = foldData;
|
||||
if (Array.isArray(folds)) {
|
||||
this.folds = folds;
|
||||
} else {
|
||||
folds = this.folds = [ folds ];
|
||||
}
|
||||
|
||||
var last = folds[folds.length - 1]
|
||||
this.range = new Range(folds[0].start.row, folds[0].start.column,
|
||||
last.end.row, last.end.column);
|
||||
this.start = this.range.start;
|
||||
this.end = this.range.end;
|
||||
|
||||
this.folds.forEach(function(fold) {
|
||||
fold.setFoldLine(this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
(function() {
|
||||
/*
|
||||
* Note: This doesn't update wrapData!
|
||||
*/
|
||||
this.shiftRow = function(shift) {
|
||||
this.start.row += shift;
|
||||
this.end.row += shift;
|
||||
this.folds.forEach(function(fold) {
|
||||
fold.start.row += shift;
|
||||
fold.end.row += shift;
|
||||
});
|
||||
}
|
||||
|
||||
this.addFold = function(fold) {
|
||||
if (fold.sameRow) {
|
||||
if (fold.start.row < this.startRow || fold.endRow > this.endRow) {
|
||||
throw "Can't add a fold to this FoldLine as it has no connection";
|
||||
}
|
||||
this.folds.push(fold);
|
||||
this.folds.sort(function(a, b) {
|
||||
return -a.range.compareEnd(b.start.row, b.start.column);
|
||||
});
|
||||
if (this.range.compareEnd(fold.start.row, fold.start.column) > 0) {
|
||||
this.end.row = fold.end.row;
|
||||
this.end.column = fold.end.column;
|
||||
} else if (this.range.compareStart(fold.end.row, fold.end.column) < 0) {
|
||||
this.start.row = fold.start.row;
|
||||
this.start.column = fold.start.column;
|
||||
}
|
||||
} else if (fold.start.row == this.end.row) {
|
||||
this.folds.push(fold);
|
||||
this.end.row = fold.end.row;
|
||||
this.end.column = fold.end.column;
|
||||
} else if (fold.end.row == this.start.row) {
|
||||
this.folds.unshift(fold);
|
||||
this.start.row = fold.start.row;
|
||||
this.start.column = fold.start.column;
|
||||
} else {
|
||||
throw "Trying to add fold to FoldRow that doesn't have a matching row";
|
||||
}
|
||||
fold.foldLine = this;
|
||||
}
|
||||
|
||||
this.containsRow = function(row) {
|
||||
return row >= this.start.row && row <= this.end.row;
|
||||
}
|
||||
|
||||
this.walk = function(callback, endRow, endColumn) {
|
||||
var lastEnd = 0,
|
||||
folds = this.folds,
|
||||
fold,
|
||||
comp, stop, isNewRow = true;
|
||||
|
||||
if (endRow == null) {
|
||||
endRow = this.end.row;
|
||||
endColumn = this.end.column;
|
||||
}
|
||||
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
fold = folds[i];
|
||||
|
||||
comp = fold.range.compareStart(endRow, endColumn);
|
||||
// This fold is after the endRow/Column.
|
||||
if (comp == -1) {
|
||||
callback(null, endRow, endColumn, lastEnd, isNewRow);
|
||||
return;
|
||||
}
|
||||
|
||||
stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow);
|
||||
stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd);
|
||||
|
||||
// If the user requested to stop the walk or endRow/endColumn is
|
||||
// inside of this fold (comp == 0), then end here.
|
||||
if (stop || comp == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note the new lastEnd might not be on the same line. However,
|
||||
// it's the callback's job to recognize this.
|
||||
isNewRow = !fold.sameRow;
|
||||
lastEnd = fold.end.column;
|
||||
}
|
||||
callback(null, endRow, endColumn, lastEnd, isNewRow);
|
||||
}
|
||||
|
||||
this.getNextFoldTo = function(row, column) {
|
||||
var fold, cmp;
|
||||
for (var i = 0; i < this.folds.length; i++) {
|
||||
fold = this.folds[i];
|
||||
cmp = fold.range.compareEnd(row, column);
|
||||
if (cmp == -1) {
|
||||
return {
|
||||
fold: fold,
|
||||
kind: "after"
|
||||
};
|
||||
} else if (cmp == 0) {
|
||||
return {
|
||||
fold: fold,
|
||||
kind: "inside"
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
this.addRemoveChars = function(row, column, len) {
|
||||
var ret = this.getNextFoldTo(row, column),
|
||||
fold, folds;
|
||||
if (ret) {
|
||||
fold = ret.fold;
|
||||
if (ret.kind == "inside"
|
||||
&& fold.start.column != column
|
||||
&& fold.start.row != row)
|
||||
{
|
||||
//throwing here breaks whole editor
|
||||
//@todo properly handle this
|
||||
window.console && window.console.log(row, column, fold);
|
||||
} else if (fold.start.row == row) {
|
||||
folds = this.folds;
|
||||
var i = folds.indexOf(fold);
|
||||
if (i == 0) {
|
||||
this.start.column += len;
|
||||
}
|
||||
for (i; i < folds.length; i++) {
|
||||
fold = folds[i];
|
||||
fold.start.column += len;
|
||||
if (!fold.sameRow) {
|
||||
return;
|
||||
}
|
||||
fold.end.column += len;
|
||||
}
|
||||
this.end.column += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.split = function(row, column) {
|
||||
var fold = this.getNextFoldTo(row, column).fold,
|
||||
folds = this.folds;
|
||||
var foldData = this.foldData;
|
||||
|
||||
if (!fold) {
|
||||
return null;
|
||||
}
|
||||
var i = folds.indexOf(fold);
|
||||
var foldBefore = folds[i - 1];
|
||||
this.end.row = foldBefore.end.row;
|
||||
this.end.column = foldBefore.end.column;
|
||||
|
||||
// Remove the folds after row/column and create a new FoldLine
|
||||
// containing these removed folds.
|
||||
folds = folds.splice(i, folds.length - i);
|
||||
|
||||
var newFoldLine = new FoldLine(foldData, folds);
|
||||
foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine);
|
||||
return newFoldLine;
|
||||
}
|
||||
|
||||
this.merge = function(foldLineNext) {
|
||||
var folds = foldLineNext.folds;
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
this.addFold(folds[i]);
|
||||
}
|
||||
// Remove the foldLineNext - no longer needed, as
|
||||
// it's merged now with foldLineNext.
|
||||
var foldData = this.foldData;
|
||||
foldData.splice(foldData.indexOf(foldLineNext), 1);
|
||||
}
|
||||
|
||||
this.toString = function() {
|
||||
var ret = [this.range.toString() + ": [" ];
|
||||
|
||||
this.folds.forEach(function(fold) {
|
||||
ret.push(" " + fold.toString());
|
||||
});
|
||||
ret.push("]")
|
||||
return ret.join("\n");
|
||||
}
|
||||
|
||||
this.idxToPosition = function(idx) {
|
||||
var lastFoldEndColumn = 0;
|
||||
var fold;
|
||||
|
||||
for (var i = 0; i < this.folds.length; i++) {
|
||||
var fold = this.folds[i];
|
||||
|
||||
idx -= fold.start.column - lastFoldEndColumn;
|
||||
if (idx < 0) {
|
||||
return {
|
||||
row: fold.start.row,
|
||||
column: fold.start.column + idx
|
||||
};
|
||||
}
|
||||
|
||||
idx -= fold.placeholder.length;
|
||||
if (idx < 0) {
|
||||
return fold.start;
|
||||
}
|
||||
|
||||
lastFoldEndColumn = fold.end.column;
|
||||
}
|
||||
|
||||
return {
|
||||
row: this.end.row,
|
||||
column: this.end.column + idx
|
||||
};
|
||||
}
|
||||
}).call(FoldLine.prototype);
|
||||
|
||||
exports.FoldLine = FoldLine;
|
||||
});
|
||||
@@ -0,0 +1,759 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Range = require("../range").Range;
|
||||
var FoldLine = require("./fold_line").FoldLine;
|
||||
var Fold = require("./fold").Fold;
|
||||
var TokenIterator = require("../token_iterator").TokenIterator;
|
||||
|
||||
function Folding() {
|
||||
/*
|
||||
* Looks up a fold at a given row/column. Possible values for side:
|
||||
* -1: ignore a fold if fold.start = row/column
|
||||
* +1: ignore a fold if fold.end = row/column
|
||||
*/
|
||||
this.getFoldAt = function(row, column, side) {
|
||||
var foldLine = this.getFoldLine(row);
|
||||
if (!foldLine)
|
||||
return null;
|
||||
|
||||
var folds = foldLine.folds;
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
var fold = folds[i];
|
||||
if (fold.range.contains(row, column)) {
|
||||
if (side == 1 && fold.range.isEnd(row, column)) {
|
||||
continue;
|
||||
} else if (side == -1 && fold.range.isStart(row, column)) {
|
||||
continue;
|
||||
}
|
||||
return fold;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns all folds in the given range. Note, that this will return folds
|
||||
*
|
||||
*/
|
||||
this.getFoldsInRange = function(range) {
|
||||
range = range.clone();
|
||||
var start = range.start;
|
||||
var end = range.end;
|
||||
var foldLines = this.$foldData;
|
||||
var foundFolds = [];
|
||||
|
||||
start.column += 1;
|
||||
end.column -= 1;
|
||||
|
||||
for (var i = 0; i < foldLines.length; i++) {
|
||||
var cmp = foldLines[i].range.compareRange(range);
|
||||
if (cmp == 2) {
|
||||
// Range is before foldLine. No intersection. This means,
|
||||
// there might be other foldLines that intersect.
|
||||
continue;
|
||||
}
|
||||
else if (cmp == -2) {
|
||||
// Range is after foldLine. There can't be any other foldLines then,
|
||||
// so let's give up.
|
||||
break;
|
||||
}
|
||||
|
||||
var folds = foldLines[i].folds;
|
||||
for (var j = 0; j < folds.length; j++) {
|
||||
var fold = folds[j];
|
||||
cmp = fold.range.compareRange(range);
|
||||
if (cmp == -2) {
|
||||
break;
|
||||
} else if (cmp == 2) {
|
||||
continue;
|
||||
} else
|
||||
// WTF-state: Can happen due to -1/+1 to start/end column.
|
||||
if (cmp == 42) {
|
||||
break;
|
||||
}
|
||||
foundFolds.push(fold);
|
||||
}
|
||||
}
|
||||
return foundFolds;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns all folds in the document
|
||||
*/
|
||||
this.getAllFolds = function() {
|
||||
var folds = [];
|
||||
var foldLines = this.$foldData;
|
||||
|
||||
function addFold(fold) {
|
||||
folds.push(fold);
|
||||
if (!fold.subFolds)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < fold.subFolds.length; i++)
|
||||
addFold(fold.subFolds[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < foldLines.length; i++)
|
||||
for (var j = 0; j < foldLines[i].folds.length; j++)
|
||||
addFold(foldLines[i].folds[j]);
|
||||
|
||||
return folds;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns the string between folds at the given position.
|
||||
* E.g.
|
||||
* foo<fold>b|ar<fold>wolrd -> "bar"
|
||||
* foo<fold>bar<fold>wol|rd -> "world"
|
||||
* foo<fold>bar<fo|ld>wolrd -> <null>
|
||||
*
|
||||
* where | means the position of row/column
|
||||
*
|
||||
* The trim option determs if the return string should be trimed according
|
||||
* to the "side" passed with the trim value:
|
||||
*
|
||||
* E.g.
|
||||
* foo<fold>b|ar<fold>wolrd -trim=-1> "b"
|
||||
* foo<fold>bar<fold>wol|rd -trim=+1> "rld"
|
||||
* fo|o<fold>bar<fold>wolrd -trim=00> "foo"
|
||||
*/
|
||||
this.getFoldStringAt = function(row, column, trim, foldLine) {
|
||||
foldLine = foldLine || this.getFoldLine(row);
|
||||
if (!foldLine)
|
||||
return null;
|
||||
|
||||
var lastFold = {
|
||||
end: { column: 0 }
|
||||
};
|
||||
// TODO: Refactor to use getNextFoldTo function.
|
||||
var str, fold;
|
||||
for (var i = 0; i < foldLine.folds.length; i++) {
|
||||
fold = foldLine.folds[i];
|
||||
var cmp = fold.range.compareEnd(row, column);
|
||||
if (cmp == -1) {
|
||||
str = this
|
||||
.getLine(fold.start.row)
|
||||
.substring(lastFold.end.column, fold.start.column);
|
||||
break;
|
||||
}
|
||||
else if (cmp === 0) {
|
||||
return null;
|
||||
}
|
||||
lastFold = fold;
|
||||
}
|
||||
if (!str)
|
||||
str = this.getLine(fold.start.row).substring(lastFold.end.column);
|
||||
|
||||
if (trim == -1)
|
||||
return str.substring(0, column - lastFold.end.column);
|
||||
else if (trim == 1)
|
||||
return str.substring(column - lastFold.end.column);
|
||||
else
|
||||
return str;
|
||||
};
|
||||
|
||||
this.getFoldLine = function(docRow, startFoldLine) {
|
||||
var foldData = this.$foldData;
|
||||
var i = 0;
|
||||
if (startFoldLine)
|
||||
i = foldData.indexOf(startFoldLine);
|
||||
if (i == -1)
|
||||
i = 0;
|
||||
for (i; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i];
|
||||
if (foldLine.start.row <= docRow && foldLine.end.row >= docRow) {
|
||||
return foldLine;
|
||||
} else if (foldLine.end.row > docRow) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// returns the fold which starts after or contains docRow
|
||||
this.getNextFoldLine = function(docRow, startFoldLine) {
|
||||
var foldData = this.$foldData;
|
||||
var i = 0;
|
||||
if (startFoldLine)
|
||||
i = foldData.indexOf(startFoldLine);
|
||||
if (i == -1)
|
||||
i = 0;
|
||||
for (i; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i];
|
||||
if (foldLine.end.row >= docRow) {
|
||||
return foldLine;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.getFoldedRowCount = function(first, last) {
|
||||
var foldData = this.$foldData, rowCount = last-first+1;
|
||||
for (var i = 0; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i],
|
||||
end = foldLine.end.row,
|
||||
start = foldLine.start.row;
|
||||
if (end >= last) {
|
||||
if(start < last) {
|
||||
if(start >= first)
|
||||
rowCount -= last-start;
|
||||
else
|
||||
rowCount = 0;//in one fold
|
||||
}
|
||||
break;
|
||||
} else if(end >= first){
|
||||
if (start >= first) //fold inside range
|
||||
rowCount -= end-start;
|
||||
else
|
||||
rowCount -= end-first+1;
|
||||
}
|
||||
}
|
||||
return rowCount;
|
||||
};
|
||||
|
||||
this.$addFoldLine = function(foldLine) {
|
||||
this.$foldData.push(foldLine);
|
||||
this.$foldData.sort(function(a, b) {
|
||||
return a.start.row - b.start.row;
|
||||
});
|
||||
return foldLine;
|
||||
};
|
||||
|
||||
/*
|
||||
* Adds a new fold.
|
||||
*
|
||||
* @returns
|
||||
* The new created Fold object or an existing fold object in case the
|
||||
* passed in range fits an existing fold exactly.
|
||||
*/
|
||||
this.addFold = function(placeholder, range) {
|
||||
var foldData = this.$foldData;
|
||||
var added = false;
|
||||
var fold;
|
||||
|
||||
if (placeholder instanceof Fold)
|
||||
fold = placeholder;
|
||||
else
|
||||
fold = new Fold(range, placeholder);
|
||||
|
||||
this.$clipRangeToDocument(fold.range);
|
||||
|
||||
var startRow = fold.start.row;
|
||||
var startColumn = fold.start.column;
|
||||
var endRow = fold.end.row;
|
||||
var endColumn = fold.end.column;
|
||||
|
||||
// --- Some checking ---
|
||||
if (fold.placeholder.length < 2)
|
||||
throw "Placeholder has to be at least 2 characters";
|
||||
|
||||
if (startRow == endRow && endColumn - startColumn < 2)
|
||||
throw "The range has to be at least 2 characters width";
|
||||
|
||||
var startFold = this.getFoldAt(startRow, startColumn, 1);
|
||||
var endFold = this.getFoldAt(endRow, endColumn, -1);
|
||||
if (startFold && endFold == startFold)
|
||||
return startFold.addSubFold(fold);
|
||||
|
||||
if (
|
||||
(startFold && !startFold.range.isStart(startRow, startColumn))
|
||||
|| (endFold && !endFold.range.isEnd(endRow, endColumn))
|
||||
) {
|
||||
throw "A fold can't intersect already existing fold" + fold.range + startFold.range;
|
||||
}
|
||||
|
||||
// Check if there are folds in the range we create the new fold for.
|
||||
var folds = this.getFoldsInRange(fold.range);
|
||||
if (folds.length > 0) {
|
||||
// Remove the folds from fold data.
|
||||
this.removeFolds(folds);
|
||||
// Add the removed folds as subfolds on the new fold.
|
||||
fold.subFolds = folds;
|
||||
}
|
||||
|
||||
for (var i = 0; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i];
|
||||
if (endRow == foldLine.start.row) {
|
||||
foldLine.addFold(fold);
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
else if (startRow == foldLine.end.row) {
|
||||
foldLine.addFold(fold);
|
||||
added = true;
|
||||
if (!fold.sameRow) {
|
||||
// Check if we might have to merge two FoldLines.
|
||||
var foldLineNext = foldData[i + 1];
|
||||
if (foldLineNext && foldLineNext.start.row == endRow) {
|
||||
// We need to merge!
|
||||
foldLine.merge(foldLineNext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (endRow <= foldLine.start.row) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!added)
|
||||
foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold));
|
||||
|
||||
if (this.$useWrapMode)
|
||||
this.$updateWrapData(foldLine.start.row, foldLine.start.row);
|
||||
else
|
||||
this.$updateRowLengthCache(foldLine.start.row, foldLine.start.row);
|
||||
|
||||
// Notify that fold data has changed.
|
||||
this.$modified = true;
|
||||
this._emit("changeFold", { data: fold });
|
||||
|
||||
return fold;
|
||||
};
|
||||
|
||||
this.addFolds = function(folds) {
|
||||
folds.forEach(function(fold) {
|
||||
this.addFold(fold);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.removeFold = function(fold) {
|
||||
var foldLine = fold.foldLine;
|
||||
var startRow = foldLine.start.row;
|
||||
var endRow = foldLine.end.row;
|
||||
|
||||
var foldLines = this.$foldData;
|
||||
var folds = foldLine.folds;
|
||||
// Simple case where there is only one fold in the FoldLine such that
|
||||
// the entire fold line can get removed directly.
|
||||
if (folds.length == 1) {
|
||||
foldLines.splice(foldLines.indexOf(foldLine), 1);
|
||||
} else
|
||||
// If the fold is the last fold of the foldLine, just remove it.
|
||||
if (foldLine.range.isEnd(fold.end.row, fold.end.column)) {
|
||||
folds.pop();
|
||||
foldLine.end.row = folds[folds.length - 1].end.row;
|
||||
foldLine.end.column = folds[folds.length - 1].end.column;
|
||||
} else
|
||||
// If the fold is the first fold of the foldLine, just remove it.
|
||||
if (foldLine.range.isStart(fold.start.row, fold.start.column)) {
|
||||
folds.shift();
|
||||
foldLine.start.row = folds[0].start.row;
|
||||
foldLine.start.column = folds[0].start.column;
|
||||
} else
|
||||
// We know there are more then 2 folds and the fold is not at the edge.
|
||||
// This means, the fold is somewhere in between.
|
||||
//
|
||||
// If the fold is in one row, we just can remove it.
|
||||
if (fold.sameRow) {
|
||||
folds.splice(folds.indexOf(fold), 1);
|
||||
} else
|
||||
// The fold goes over more then one row. This means remvoing this fold
|
||||
// will cause the fold line to get splitted up. newFoldLine is the second part
|
||||
{
|
||||
var newFoldLine = foldLine.split(fold.start.row, fold.start.column);
|
||||
folds = newFoldLine.folds;
|
||||
folds.shift();
|
||||
newFoldLine.start.row = folds[0].start.row;
|
||||
newFoldLine.start.column = folds[0].start.column;
|
||||
}
|
||||
|
||||
if (this.$useWrapMode)
|
||||
this.$updateWrapData(startRow, endRow);
|
||||
else
|
||||
this.$updateRowLengthCache(startRow, endRow);
|
||||
|
||||
// Notify that fold data has changed.
|
||||
this.$modified = true;
|
||||
this._emit("changeFold", { data: fold });
|
||||
};
|
||||
|
||||
this.removeFolds = function(folds) {
|
||||
// We need to clone the folds array passed in as it might be the folds
|
||||
// array of a fold line and as we call this.removeFold(fold), folds
|
||||
// are removed from folds and changes the current index.
|
||||
var cloneFolds = [];
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
cloneFolds.push(folds[i]);
|
||||
}
|
||||
|
||||
cloneFolds.forEach(function(fold) {
|
||||
this.removeFold(fold);
|
||||
}, this);
|
||||
this.$modified = true;
|
||||
};
|
||||
|
||||
this.expandFold = function(fold) {
|
||||
this.removeFold(fold);
|
||||
fold.subFolds.forEach(function(fold) {
|
||||
this.addFold(fold);
|
||||
}, this);
|
||||
fold.subFolds = [];
|
||||
};
|
||||
|
||||
this.expandFolds = function(folds) {
|
||||
folds.forEach(function(fold) {
|
||||
this.expandFold(fold);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.unfold = function(location, expandInner) {
|
||||
var range, folds;
|
||||
if (location == null)
|
||||
range = new Range(0, 0, this.getLength(), 0);
|
||||
else if (typeof location == "number")
|
||||
range = new Range(location, 0, location, this.getLine(location).length);
|
||||
else if ("row" in location)
|
||||
range = Range.fromPoints(location, location);
|
||||
else
|
||||
range = location;
|
||||
|
||||
folds = this.getFoldsInRange(range);
|
||||
if (expandInner) {
|
||||
this.removeFolds(folds);
|
||||
} else {
|
||||
// TODO: might need to remove and add folds in one go instead of using
|
||||
// expandFolds several times.
|
||||
while (folds.length) {
|
||||
this.expandFolds(folds);
|
||||
folds = this.getFoldsInRange(range);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Checks if a given documentRow is folded. This is true if there are some
|
||||
* folded parts such that some parts of the line is still visible.
|
||||
**/
|
||||
this.isRowFolded = function(docRow, startFoldRow) {
|
||||
return !!this.getFoldLine(docRow, startFoldRow);
|
||||
};
|
||||
|
||||
this.getRowFoldEnd = function(docRow, startFoldRow) {
|
||||
var foldLine = this.getFoldLine(docRow, startFoldRow);
|
||||
return (foldLine
|
||||
? foldLine.end.row
|
||||
: docRow);
|
||||
};
|
||||
|
||||
this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) {
|
||||
if (startRow == null) {
|
||||
startRow = foldLine.start.row;
|
||||
startColumn = 0;
|
||||
}
|
||||
|
||||
if (endRow == null) {
|
||||
endRow = foldLine.end.row;
|
||||
endColumn = this.getLine(endRow).length;
|
||||
}
|
||||
|
||||
// Build the textline using the FoldLine walker.
|
||||
var doc = this.doc;
|
||||
var textLine = "";
|
||||
|
||||
foldLine.walk(function(placeholder, row, column, lastColumn) {
|
||||
if (row < startRow) {
|
||||
return;
|
||||
} else if (row == startRow) {
|
||||
if (column < startColumn) {
|
||||
return;
|
||||
}
|
||||
lastColumn = Math.max(startColumn, lastColumn);
|
||||
}
|
||||
if (placeholder) {
|
||||
textLine += placeholder;
|
||||
} else {
|
||||
textLine += doc.getLine(row).substring(lastColumn, column);
|
||||
}
|
||||
}.bind(this), endRow, endColumn);
|
||||
return textLine;
|
||||
};
|
||||
|
||||
this.getDisplayLine = function(row, endColumn, startRow, startColumn) {
|
||||
var foldLine = this.getFoldLine(row);
|
||||
|
||||
if (!foldLine) {
|
||||
var line;
|
||||
line = this.doc.getLine(row);
|
||||
return line.substring(startColumn || 0, endColumn || line.length);
|
||||
} else {
|
||||
return this.getFoldDisplayLine(
|
||||
foldLine, row, endColumn, startRow, startColumn);
|
||||
}
|
||||
};
|
||||
|
||||
this.$cloneFoldData = function() {
|
||||
var fd = [];
|
||||
fd = this.$foldData.map(function(foldLine) {
|
||||
var folds = foldLine.folds.map(function(fold) {
|
||||
return fold.clone();
|
||||
});
|
||||
return new FoldLine(fd, folds);
|
||||
});
|
||||
|
||||
return fd;
|
||||
};
|
||||
|
||||
this.toggleFold = function(tryToUnfold) {
|
||||
var selection = this.selection;
|
||||
var range = selection.getRange();
|
||||
var fold;
|
||||
var bracketPos;
|
||||
|
||||
if (range.isEmpty()) {
|
||||
var cursor = range.start;
|
||||
fold = this.getFoldAt(cursor.row, cursor.column);
|
||||
|
||||
if (fold) {
|
||||
this.expandFold(fold);
|
||||
return;
|
||||
}
|
||||
else if (bracketPos = this.findMatchingBracket(cursor)) {
|
||||
if (range.comparePoint(bracketPos) == 1) {
|
||||
range.end = bracketPos;
|
||||
}
|
||||
else {
|
||||
range.start = bracketPos;
|
||||
range.start.column++;
|
||||
range.end.column--;
|
||||
}
|
||||
}
|
||||
else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) {
|
||||
if (range.comparePoint(bracketPos) == 1)
|
||||
range.end = bracketPos;
|
||||
else
|
||||
range.start = bracketPos;
|
||||
|
||||
range.start.column++;
|
||||
}
|
||||
else {
|
||||
range = this.getCommentFoldRange(cursor.row, cursor.column) || range;
|
||||
}
|
||||
} else {
|
||||
var folds = this.getFoldsInRange(range);
|
||||
if (tryToUnfold && folds.length) {
|
||||
this.expandFolds(folds);
|
||||
return;
|
||||
}
|
||||
else if (folds.length == 1 ) {
|
||||
fold = folds[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!fold)
|
||||
fold = this.getFoldAt(range.start.row, range.start.column);
|
||||
|
||||
if (fold && fold.range.toString() == range.toString()) {
|
||||
this.expandFold(fold);
|
||||
return;
|
||||
}
|
||||
|
||||
var placeholder = "...";
|
||||
if (!range.isMultiLine()) {
|
||||
placeholder = this.getTextRange(range);
|
||||
if(placeholder.length < 4)
|
||||
return;
|
||||
placeholder = placeholder.trim().substring(0, 2) + "..";
|
||||
}
|
||||
|
||||
this.addFold(placeholder, range);
|
||||
};
|
||||
|
||||
this.getCommentFoldRange = function(row, column) {
|
||||
var iterator = new TokenIterator(this, row, column);
|
||||
var token = iterator.getCurrentToken();
|
||||
if (token && /^comment|string/.test(token.type)) {
|
||||
var range = new Range();
|
||||
var re = new RegExp(token.type.replace(/\..*/, "\\."));
|
||||
do {
|
||||
token = iterator.stepBackward();
|
||||
} while(token && re.test(token.type));
|
||||
|
||||
iterator.stepForward();
|
||||
range.start.row = iterator.getCurrentTokenRow();
|
||||
range.start.column = iterator.getCurrentTokenColumn() + 2;
|
||||
|
||||
iterator = new TokenIterator(this, row, column);
|
||||
|
||||
do {
|
||||
token = iterator.stepForward();
|
||||
} while(token && re.test(token.type));
|
||||
|
||||
token = iterator.stepBackward();
|
||||
|
||||
range.end.row = iterator.getCurrentTokenRow();
|
||||
range.end.column = iterator.getCurrentTokenColumn() + token.value.length;
|
||||
return range;
|
||||
}
|
||||
};
|
||||
|
||||
this.foldAll = function(startRow, endRow) {
|
||||
var foldWidgets = this.foldWidgets;
|
||||
endRow = endRow || this.getLength();
|
||||
for (var row = startRow || 0; row < endRow; row++) {
|
||||
if (foldWidgets[row] == null)
|
||||
foldWidgets[row] = this.getFoldWidget(row);
|
||||
if (foldWidgets[row] != "start")
|
||||
continue;
|
||||
|
||||
var range = this.getFoldWidgetRange(row);
|
||||
// sometimes range can be incompatible with existing fold
|
||||
// wouldn't it be better for addFold to return null istead of throwing?
|
||||
if (range && range.end.row < endRow) try {
|
||||
this.addFold("...", range);
|
||||
} catch(e) {}
|
||||
}
|
||||
};
|
||||
|
||||
this.$foldStyles = {
|
||||
"manual": 1,
|
||||
"markbegin": 1,
|
||||
"markbeginend": 1
|
||||
};
|
||||
this.$foldStyle = "markbegin";
|
||||
this.setFoldStyle = function(style) {
|
||||
if (!this.$foldStyles[style])
|
||||
throw new Error("invalid fold style: " + style + "[" + Object.keys(this.$foldStyles).join(", ") + "]");
|
||||
|
||||
if (this.$foldStyle == style)
|
||||
return;
|
||||
|
||||
this.$foldStyle = style;
|
||||
|
||||
if (style == "manual")
|
||||
this.unfold();
|
||||
|
||||
// reset folding
|
||||
var mode = this.$foldMode;
|
||||
this.$setFolding(null);
|
||||
this.$setFolding(mode);
|
||||
};
|
||||
|
||||
// structured folding
|
||||
this.$setFolding = function(foldMode) {
|
||||
if (this.$foldMode == foldMode)
|
||||
return;
|
||||
|
||||
this.$foldMode = foldMode;
|
||||
|
||||
this.removeListener('change', this.$updateFoldWidgets);
|
||||
this._emit("changeAnnotation");
|
||||
|
||||
if (!foldMode || this.$foldStyle == "manual") {
|
||||
this.foldWidgets = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.foldWidgets = [];
|
||||
this.getFoldWidget = foldMode.getFoldWidget.bind(foldMode, this, this.$foldStyle);
|
||||
this.getFoldWidgetRange = foldMode.getFoldWidgetRange.bind(foldMode, this, this.$foldStyle);
|
||||
|
||||
this.$updateFoldWidgets = this.updateFoldWidgets.bind(this);
|
||||
this.on('change', this.$updateFoldWidgets);
|
||||
|
||||
};
|
||||
|
||||
this.onFoldWidgetClick = function(row, e) {
|
||||
var type = this.getFoldWidget(row);
|
||||
var line = this.getLine(row);
|
||||
var onlySubfolds = e.shiftKey;
|
||||
var addSubfolds = onlySubfolds || e.ctrlKey || e.altKey || e.metaKey;
|
||||
var fold;
|
||||
|
||||
if (type == "end")
|
||||
fold = this.getFoldAt(row, 0, -1);
|
||||
else
|
||||
fold = this.getFoldAt(row, line.length, 1);
|
||||
|
||||
if (fold) {
|
||||
if (addSubfolds)
|
||||
this.removeFold(fold);
|
||||
else
|
||||
this.expandFold(fold);
|
||||
return;
|
||||
}
|
||||
|
||||
var range = this.getFoldWidgetRange(row);
|
||||
if (range) {
|
||||
// sometimes singleline folds can be missed by the code above
|
||||
if (!range.isMultiLine()) {
|
||||
fold = this.getFoldAt(range.start.row, range.start.column, 1);
|
||||
if (fold && range.isEqual(fold.range)) {
|
||||
this.removeFold(fold);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlySubfolds)
|
||||
this.addFold("...", range);
|
||||
|
||||
if (addSubfolds)
|
||||
this.foldAll(range.start.row + 1, range.end.row);
|
||||
} else {
|
||||
if (addSubfolds)
|
||||
this.foldAll(row + 1, this.getLength());
|
||||
e.target.className += " invalid"
|
||||
}
|
||||
};
|
||||
|
||||
this.updateFoldWidgets = function(e) {
|
||||
var delta = e.data;
|
||||
var range = delta.range;
|
||||
var firstRow = range.start.row;
|
||||
var len = range.end.row - firstRow;
|
||||
|
||||
if (len === 0) {
|
||||
this.foldWidgets[firstRow] = null;
|
||||
} else if (delta.action == "removeText" || delta.action == "removeLines") {
|
||||
this.foldWidgets.splice(firstRow, len + 1, null);
|
||||
} else {
|
||||
var args = Array(len + 1);
|
||||
args.unshift(firstRow, 1);
|
||||
this.foldWidgets.splice.apply(this.foldWidgets, args);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
exports.Folding = Folding;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,981 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var lang = require("./lib/lang");
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var UndoManager = require("./undomanager").UndoManager;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
|
||||
function createFoldTestSession() {
|
||||
var lines = [
|
||||
"function foo(items) {",
|
||||
" for (var i=0; i<items.length; i++) {",
|
||||
" alert(items[i] + \"juhu\");",
|
||||
" } // Real Tab.",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"));
|
||||
session.setUndoManager(new UndoManager());
|
||||
session.addFold("args...", new Range(0, 13, 0, 18));
|
||||
session.addFold("foo...", new Range(1, 10, 2, 10));
|
||||
session.addFold("bar...", new Range(2, 20, 2, 25));
|
||||
return session;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test: find matching opening bracket in Text mode" : function() {
|
||||
var session = new EditSession(["(()(", "())))"]);
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 3}), 0, 1);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 2}), 1, 0);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 3}), 0, 3);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 4}), 0, 0);
|
||||
assert.equal(session.findMatchingBracket({row: 1, column: 5}), null);
|
||||
},
|
||||
|
||||
"test: find matching closing bracket in Text mode" : function() {
|
||||
var session = new EditSession(["(()(", "())))"]);
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 1}), 1, 1);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 1}), 1, 1);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 4}), 1, 2);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 2}), 0, 2);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 1}), 1, 3);
|
||||
assert.equal(session.findMatchingBracket({row: 0, column: 0}), null);
|
||||
},
|
||||
|
||||
"test: find matching opening bracket in JavaScript mode" : function() {
|
||||
var lines = [
|
||||
"function foo() {",
|
||||
" var str = \"{ foo()\";",
|
||||
" if (debug) {",
|
||||
" // write str (a string) to the console",
|
||||
" console.log(str);",
|
||||
" }",
|
||||
" str += \" bar() }\";",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 14}), 0, 12);
|
||||
assert.position(session.findMatchingBracket({row: 7, column: 1}), 0, 15);
|
||||
assert.position(session.findMatchingBracket({row: 6, column: 20}), 1, 15);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 22}), 1, 20);
|
||||
assert.position(session.findMatchingBracket({row: 3, column: 31}), 3, 21);
|
||||
assert.position(session.findMatchingBracket({row: 4, column: 24}), 4, 19);
|
||||
assert.equal(session.findMatchingBracket({row: 0, column: 1}), null);
|
||||
},
|
||||
|
||||
"test: find matching closing bracket in JavaScript mode" : function() {
|
||||
var lines = [
|
||||
"function foo() {",
|
||||
" var str = \"{ foo()\";",
|
||||
" if (debug) {",
|
||||
" // write str (a string) to the console",
|
||||
" console.log(str);",
|
||||
" }",
|
||||
" str += \" bar() }\";",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 13}), 0, 13);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 16}), 7, 0);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 16}), 6, 19);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 21}), 1, 21);
|
||||
assert.position(session.findMatchingBracket({row: 3, column: 22}), 3, 30);
|
||||
assert.position(session.findMatchingBracket({row: 4, column: 20}), 4, 23);
|
||||
},
|
||||
|
||||
"test: handle unbalanced brackets in JavaScript mode" : function() {
|
||||
var lines = [
|
||||
"function foo() {",
|
||||
" var str = \"{ foo()\";",
|
||||
" if (debug) {",
|
||||
" // write str a string) to the console",
|
||||
" console.log(str);",
|
||||
" ",
|
||||
" str += \" bar() \";",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
|
||||
|
||||
assert.equal(session.findMatchingBracket({row: 0, column: 16}), null);
|
||||
assert.equal(session.findMatchingBracket({row: 3, column: 30}), null);
|
||||
assert.equal(session.findMatchingBracket({row: 1, column: 16}), null);
|
||||
},
|
||||
|
||||
"test: match different bracket types" : function() {
|
||||
var session = new EditSession(["({[", ")]}"]);
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 1}), 1, 0);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 2}), 1, 2);
|
||||
assert.position(session.findMatchingBracket({row: 0, column: 3}), 1, 1);
|
||||
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 1}), 0, 0);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 2}), 0, 2);
|
||||
assert.position(session.findMatchingBracket({row: 1, column: 3}), 0, 1);
|
||||
},
|
||||
|
||||
"test: move lines down" : function() {
|
||||
var session = new EditSession(["a1", "a2", "a3", "a4"]);
|
||||
|
||||
session.moveLinesDown(0, 1);
|
||||
assert.equal(session.getValue(), ["a3", "a1", "a2", "a4"].join("\n"));
|
||||
|
||||
session.moveLinesDown(1, 2);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesDown(2, 3);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesDown(2, 2);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a2", "a1"].join("\n"));
|
||||
},
|
||||
|
||||
"test: move lines up" : function() {
|
||||
var session = new EditSession(["a1", "a2", "a3", "a4"]);
|
||||
|
||||
session.moveLinesUp(2, 3);
|
||||
assert.equal(session.getValue(), ["a1", "a3", "a4", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesUp(1, 2);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesUp(0, 1);
|
||||
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
|
||||
|
||||
session.moveLinesUp(2, 2);
|
||||
assert.equal(session.getValue(), ["a3", "a1", "a4", "a2"].join("\n"));
|
||||
},
|
||||
|
||||
"test: duplicate lines" : function() {
|
||||
var session = new EditSession(["1", "2", "3", "4"]);
|
||||
|
||||
session.duplicateLines(1, 2);
|
||||
assert.equal(session.getValue(), ["1", "2", "3", "2", "3", "4"].join("\n"));
|
||||
},
|
||||
|
||||
"test: duplicate last line" : function() {
|
||||
var session = new EditSession(["1", "2", "3"]);
|
||||
|
||||
session.duplicateLines(2, 2);
|
||||
assert.equal(session.getValue(), ["1", "2", "3", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: duplicate first line" : function() {
|
||||
var session = new EditSession(["1", "2", "3"]);
|
||||
|
||||
session.duplicateLines(0, 0);
|
||||
assert.equal(session.getValue(), ["1", "1", "2", "3"].join("\n"));
|
||||
},
|
||||
|
||||
"test: getScreenLastRowColumn": function() {
|
||||
var session = new EditSession([
|
||||
"juhu",
|
||||
"12\t\t34",
|
||||
"ぁぁa"
|
||||
]);
|
||||
|
||||
assert.equal(session.getScreenLastRowColumn(0), 4);
|
||||
assert.equal(session.getScreenLastRowColumn(1), 10);
|
||||
assert.equal(session.getScreenLastRowColumn(2), 5);
|
||||
},
|
||||
|
||||
"test: convert document to screen coordinates" : function() {
|
||||
var session = new EditSession("01234\t567890\t1234");
|
||||
session.setTabSize(4);
|
||||
|
||||
assert.equal(session.documentToScreenColumn(0, 0), 0);
|
||||
assert.equal(session.documentToScreenColumn(0, 4), 4);
|
||||
assert.equal(session.documentToScreenColumn(0, 5), 5);
|
||||
assert.equal(session.documentToScreenColumn(0, 6), 8);
|
||||
assert.equal(session.documentToScreenColumn(0, 12), 14);
|
||||
assert.equal(session.documentToScreenColumn(0, 13), 16);
|
||||
|
||||
session.setTabSize(2);
|
||||
|
||||
assert.equal(session.documentToScreenColumn(0, 0), 0);
|
||||
assert.equal(session.documentToScreenColumn(0, 4), 4);
|
||||
assert.equal(session.documentToScreenColumn(0, 5), 5);
|
||||
assert.equal(session.documentToScreenColumn(0, 6), 6);
|
||||
assert.equal(session.documentToScreenColumn(0, 7), 7);
|
||||
assert.equal(session.documentToScreenColumn(0, 12), 12);
|
||||
assert.equal(session.documentToScreenColumn(0, 13), 14);
|
||||
},
|
||||
|
||||
"test: convert document to screen coordinates with leading tabs": function() {
|
||||
var session = new EditSession("\t\t123");
|
||||
session.setTabSize(4);
|
||||
|
||||
assert.equal(session.documentToScreenColumn(0, 0), 0);
|
||||
assert.equal(session.documentToScreenColumn(0, 1), 4);
|
||||
assert.equal(session.documentToScreenColumn(0, 2), 8);
|
||||
assert.equal(session.documentToScreenColumn(0, 3), 9);
|
||||
},
|
||||
|
||||
"test: documentToScreen without soft wrap": function() {
|
||||
var session = new EditSession([
|
||||
"juhu",
|
||||
"12\t\t34",
|
||||
"ぁぁa"
|
||||
]);
|
||||
|
||||
assert.position(session.documentToScreenPosition(0, 3), 0, 3);
|
||||
assert.position(session.documentToScreenPosition(1, 3), 1, 4);
|
||||
assert.position(session.documentToScreenPosition(1, 4), 1, 8);
|
||||
assert.position(session.documentToScreenPosition(2, 2), 2, 4);
|
||||
},
|
||||
|
||||
"test: documentToScreen with soft wrap": function() {
|
||||
var session = new EditSession(["foo bar foo bar"]);
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(12, 12);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.position(session.documentToScreenPosition(0, 11), 0, 11);
|
||||
assert.position(session.documentToScreenPosition(0, 12), 1, 0);
|
||||
},
|
||||
|
||||
"test: documentToScreen with soft wrap and multibyte characters": function() {
|
||||
var session = new EditSession(["ぁぁa"]);
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(2, 2);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.position(session.documentToScreenPosition(0, 1), 1, 0);
|
||||
assert.position(session.documentToScreenPosition(0, 2), 2, 0);
|
||||
assert.position(session.documentToScreenPosition(0, 4), 2, 1);
|
||||
},
|
||||
|
||||
"test: documentToScreen should clip position to the document boundaries": function() {
|
||||
var session = new EditSession("foo bar\njuhu kinners");
|
||||
|
||||
assert.position(session.documentToScreenPosition(-1, 4), 0, 0);
|
||||
assert.position(session.documentToScreenPosition(3, 0), 1, 12);
|
||||
},
|
||||
|
||||
"test: convert screen to document coordinates" : function() {
|
||||
var session = new EditSession("01234\t567890\t1234");
|
||||
session.setTabSize(4);
|
||||
|
||||
assert.equal(session.screenToDocumentColumn(0, 0), 0);
|
||||
assert.equal(session.screenToDocumentColumn(0, 4), 4);
|
||||
assert.equal(session.screenToDocumentColumn(0, 5), 5);
|
||||
assert.equal(session.screenToDocumentColumn(0, 6), 5);
|
||||
assert.equal(session.screenToDocumentColumn(0, 7), 5);
|
||||
assert.equal(session.screenToDocumentColumn(0, 8), 6);
|
||||
assert.equal(session.screenToDocumentColumn(0, 9), 7);
|
||||
assert.equal(session.screenToDocumentColumn(0, 15), 12);
|
||||
assert.equal(session.screenToDocumentColumn(0, 19), 16);
|
||||
|
||||
session.setTabSize(2);
|
||||
|
||||
assert.equal(session.screenToDocumentColumn(0, 0), 0);
|
||||
assert.equal(session.screenToDocumentColumn(0, 4), 4);
|
||||
assert.equal(session.screenToDocumentColumn(0, 5), 5);
|
||||
assert.equal(session.screenToDocumentColumn(0, 6), 6);
|
||||
assert.equal(session.screenToDocumentColumn(0, 12), 12);
|
||||
assert.equal(session.screenToDocumentColumn(0, 13), 12);
|
||||
assert.equal(session.screenToDocumentColumn(0, 14), 13);
|
||||
},
|
||||
|
||||
"test: screenToDocument with soft wrap": function() {
|
||||
var session = new EditSession(["foo bar foo bar"]);
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(12, 12);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.position(session.screenToDocumentPosition(1, 0), 0, 12);
|
||||
assert.position(session.screenToDocumentPosition(0, 11), 0, 11);
|
||||
// Check if the position is clamped the right way.
|
||||
assert.position(session.screenToDocumentPosition(0, 12), 0, 11);
|
||||
assert.position(session.screenToDocumentPosition(0, 20), 0, 11);
|
||||
},
|
||||
|
||||
"test: screenToDocument with soft wrap and multi byte characters": function() {
|
||||
var session = new EditSession(["ぁ a"]);
|
||||
session.setUseWrapMode(true);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
assert.position(session.screenToDocumentPosition(0, 1), 0, 0);
|
||||
assert.position(session.screenToDocumentPosition(0, 2), 0, 1);
|
||||
assert.position(session.screenToDocumentPosition(0, 3), 0, 2);
|
||||
assert.position(session.screenToDocumentPosition(0, 4), 0, 3);
|
||||
assert.position(session.screenToDocumentPosition(0, 5), 0, 3);
|
||||
},
|
||||
|
||||
"test: screenToDocument should clip position to the document boundaries": function() {
|
||||
var session = new EditSession("foo bar\njuhu kinners");
|
||||
|
||||
assert.position(session.screenToDocumentPosition(-1, 4), 0, 0);
|
||||
assert.position(session.screenToDocumentPosition(0, -1), 0, 0);
|
||||
assert.position(session.screenToDocumentPosition(0, 30), 0, 7);
|
||||
assert.position(session.screenToDocumentPosition(2, 4), 1, 12);
|
||||
assert.position(session.screenToDocumentPosition(1, 30), 1, 12);
|
||||
assert.position(session.screenToDocumentPosition(20, 50), 1, 12);
|
||||
assert.position(session.screenToDocumentPosition(20, 5), 1, 12);
|
||||
|
||||
// and the same for folded rows
|
||||
session.addFold("...", new Range(0,1,1,3));
|
||||
assert.position(session.screenToDocumentPosition(1, 2), 1, 12);
|
||||
// for wrapped rows
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(5,5);
|
||||
assert.position(session.screenToDocumentPosition(4, 1), 1, 12);
|
||||
},
|
||||
|
||||
"test: wrapLine split function" : function() {
|
||||
function computeAndAssert(line, assertEqual, wrapLimit, tabSize) {
|
||||
wrapLimit = wrapLimit || 12;
|
||||
tabSize = tabSize || 4;
|
||||
line = lang.stringTrimRight(line);
|
||||
var tokens = EditSession.prototype.$getDisplayTokens(line);
|
||||
var splits = EditSession.prototype.$computeWrapSplits(tokens, wrapLimit, tabSize);
|
||||
// console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
|
||||
assert.ok(splits.length == assertEqual.length);
|
||||
for (var i = 0; i < splits.length; i++) {
|
||||
assert.ok(splits[i] == assertEqual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Basic splitting.
|
||||
computeAndAssert("foo bar foo bar", [ 12 ]);
|
||||
computeAndAssert("foo bar f bar", [ 12 ]);
|
||||
computeAndAssert("foo bar f r", [ 14 ]);
|
||||
computeAndAssert("foo bar foo bar foo bara foo", [12, 25]);
|
||||
|
||||
// Don't split if there is only whitespaces/tabs at the end of the line.
|
||||
computeAndAssert("foo foo foo \t \t", [ ]);
|
||||
|
||||
// If there is no space to split, force split.
|
||||
computeAndAssert("foooooooooooooo", [ 12 ]);
|
||||
computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]);
|
||||
computeAndAssert("foo bar fooooooooooobooooooo", [8, 20]);
|
||||
|
||||
// Basic splitting + tabs.
|
||||
computeAndAssert("foo \t\tbar", [ 6 ]);
|
||||
computeAndAssert("foo \t \tbar", [ 7 ]);
|
||||
|
||||
// Ignore spaces/tabs at beginning of split.
|
||||
computeAndAssert("foo \t \t \t \t bar", [ 14 ]);
|
||||
|
||||
// Test wrapping for asian characters.
|
||||
computeAndAssert("ぁぁ", [1], 2);
|
||||
computeAndAssert(" ぁぁ", [1, 2], 2);
|
||||
computeAndAssert(" ぁ\tぁ", [1, 3], 2);
|
||||
computeAndAssert(" ぁぁ\tぁ", [1, 4], 4);
|
||||
|
||||
// Test wrapping for punctuation.
|
||||
computeAndAssert(" ab.c;ef++", [1, 3, 5, 7, 8], 2);
|
||||
computeAndAssert(" a.b", [1, 2, 3], 1);
|
||||
computeAndAssert("#>>", [1, 2], 1);
|
||||
},
|
||||
|
||||
"test get longest line" : function() {
|
||||
var session = new EditSession(["12"]);
|
||||
session.setTabSize(4);
|
||||
assert.equal(session.getScreenWidth(), 2);
|
||||
|
||||
session.doc.insertNewLine({row: 0, column: Infinity});
|
||||
session.doc.insertLines(1, ["123"]);
|
||||
assert.equal(session.getScreenWidth(), 3);
|
||||
|
||||
session.doc.insertNewLine({row: 0, column: Infinity});
|
||||
session.doc.insertLines(1, ["\t\t"]);
|
||||
|
||||
assert.equal(session.getScreenWidth(), 8);
|
||||
|
||||
session.setTabSize(2);
|
||||
assert.equal(session.getScreenWidth(), 4);
|
||||
},
|
||||
|
||||
"test getDisplayString": function() {
|
||||
var session = new EditSession(["12"]);
|
||||
session.setTabSize(4);
|
||||
|
||||
assert.equal(session.$getDisplayTokens("\t").length, 4);
|
||||
assert.equal(session.$getDisplayTokens("abc").length, 3);
|
||||
assert.equal(session.$getDisplayTokens("abc\t").length, 4);
|
||||
},
|
||||
|
||||
"test issue 83": function() {
|
||||
var session = new EditSession("");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
var document = session.getDocument();
|
||||
|
||||
session.setUseWrapMode(true);
|
||||
|
||||
document.insertLines(0, ["a", "b"]);
|
||||
document.insertLines(2, ["c", "d"]);
|
||||
document.removeLines(1, 2);
|
||||
},
|
||||
|
||||
"test wrapMode init has to create wrapData array": function() {
|
||||
var session = new EditSession("foo bar\nfoo bar");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
var document = session.getDocument();
|
||||
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(3, 3);
|
||||
session.adjustWrapLimit(80);
|
||||
|
||||
// Test if wrapData is there and was computed.
|
||||
assert.equal(session.$wrapData.length, 2);
|
||||
assert.equal(session.$wrapData[0].length, 1);
|
||||
assert.equal(session.$wrapData[1].length, 1);
|
||||
},
|
||||
|
||||
"test first line blank with wrap": function() {
|
||||
var session = new EditSession("\nfoo");
|
||||
session.setUseWrapMode(true);
|
||||
assert.equal(session.doc.getValue(), ["", "foo"].join("\n"));
|
||||
},
|
||||
|
||||
"test first line blank with wrap 2" : function() {
|
||||
var session = new EditSession("");
|
||||
session.setUseWrapMode(true);
|
||||
session.setValue("\nfoo");
|
||||
|
||||
assert.equal(session.doc.getValue(), ["", "foo"].join("\n"));
|
||||
},
|
||||
|
||||
"test fold getFoldDisplayLine": function() {
|
||||
var session = createFoldTestSession();
|
||||
function assertDisplayLine(foldLine, str) {
|
||||
var line = session.getLine(foldLine.end.row);
|
||||
var displayLine =
|
||||
session.getFoldDisplayLine(foldLine, foldLine.end.row, line.length);
|
||||
assert.equal(displayLine, str);
|
||||
}
|
||||
|
||||
assertDisplayLine(session.$foldData[0], "function foo(args...) {")
|
||||
assertDisplayLine(session.$foldData[1], " for (vfoo...ert(items[bar...\"juhu\");");
|
||||
},
|
||||
|
||||
"test foldLine idxToPosition": function() {
|
||||
var session = createFoldTestSession();
|
||||
|
||||
function assertIdx2Pos(foldLineIdx, idx, row, column) {
|
||||
var foldLine = session.$foldData[foldLineIdx];
|
||||
assert.position(foldLine.idxToPosition(idx), row, column);
|
||||
}
|
||||
|
||||
// "function foo(items) {",
|
||||
// " for (var i=0; i<items.length; i++) {",
|
||||
// " alert(items[i] + \"juhu\");",
|
||||
// " } // Real Tab.",
|
||||
// "}"
|
||||
|
||||
assertIdx2Pos(0, 12, 0, 12);
|
||||
assertIdx2Pos(0, 13, 0, 13);
|
||||
assertIdx2Pos(0, 14, 0, 13);
|
||||
assertIdx2Pos(0, 19, 0, 13);
|
||||
assertIdx2Pos(0, 20, 0, 18);
|
||||
|
||||
assertIdx2Pos(1, 10, 1, 10);
|
||||
assertIdx2Pos(1, 11, 1, 10);
|
||||
assertIdx2Pos(1, 15, 1, 10);
|
||||
assertIdx2Pos(1, 16, 2, 10);
|
||||
assertIdx2Pos(1, 26, 2, 20);
|
||||
assertIdx2Pos(1, 27, 2, 20);
|
||||
assertIdx2Pos(1, 32, 2, 25);
|
||||
},
|
||||
|
||||
"test fold documentToScreen": function() {
|
||||
var session = createFoldTestSession();
|
||||
function assertDoc2Screen(docRow, docCol, screenRow, screenCol) {
|
||||
assert.position(
|
||||
session.documentToScreenPosition(docRow, docCol),
|
||||
screenRow, screenCol
|
||||
);
|
||||
}
|
||||
|
||||
// One fold ending in the same row.
|
||||
assertDoc2Screen(0, 0, 0, 0);
|
||||
assertDoc2Screen(0, 13, 0, 13);
|
||||
assertDoc2Screen(0, 14, 0, 13);
|
||||
assertDoc2Screen(0, 17, 0, 13);
|
||||
assertDoc2Screen(0, 18, 0, 20);
|
||||
|
||||
// Fold ending on some other row.
|
||||
assertDoc2Screen(1, 0, 1, 0);
|
||||
assertDoc2Screen(1, 10, 1, 10);
|
||||
assertDoc2Screen(1, 11, 1, 10);
|
||||
assertDoc2Screen(1, 99, 1, 10);
|
||||
|
||||
assertDoc2Screen(2, 0, 1, 10);
|
||||
assertDoc2Screen(2, 9, 1, 10);
|
||||
assertDoc2Screen(2, 10, 1, 16);
|
||||
assertDoc2Screen(2, 11, 1, 17);
|
||||
|
||||
// Fold in the same row with fold over more then one row in the same row.
|
||||
assertDoc2Screen(2, 19, 1, 25);
|
||||
assertDoc2Screen(2, 20, 1, 26);
|
||||
assertDoc2Screen(2, 21, 1, 26);
|
||||
|
||||
assertDoc2Screen(2, 24, 1, 26);
|
||||
assertDoc2Screen(2, 25, 1, 32);
|
||||
assertDoc2Screen(2, 26, 1, 33);
|
||||
assertDoc2Screen(2, 99, 1, 40);
|
||||
|
||||
// Test one position after the folds. Should be all like normal.
|
||||
assertDoc2Screen(3, 0, 2, 0);
|
||||
},
|
||||
|
||||
"test fold screenToDocument": function() {
|
||||
var session = createFoldTestSession();
|
||||
function assertScreen2Doc(docRow, docCol, screenRow, screenCol) {
|
||||
assert.position(
|
||||
session.screenToDocumentPosition(screenRow, screenCol),
|
||||
docRow, docCol
|
||||
);
|
||||
}
|
||||
|
||||
// One fold ending in the same row.
|
||||
assertScreen2Doc(0, 0, 0, 0);
|
||||
assertScreen2Doc(0, 13, 0, 13);
|
||||
assertScreen2Doc(0, 13, 0, 14);
|
||||
assertScreen2Doc(0, 18, 0, 20);
|
||||
assertScreen2Doc(0, 19, 0, 21);
|
||||
|
||||
// Fold ending on some other row.
|
||||
assertScreen2Doc(1, 0, 1, 0);
|
||||
assertScreen2Doc(1, 10, 1, 10);
|
||||
assertScreen2Doc(1, 10, 1, 11);
|
||||
|
||||
assertScreen2Doc(1, 10, 1, 15);
|
||||
assertScreen2Doc(2, 10, 1, 16);
|
||||
assertScreen2Doc(2, 11, 1, 17);
|
||||
|
||||
// Fold in the same row with fold over more then one row in the same row.
|
||||
assertScreen2Doc(2, 19, 1, 25);
|
||||
assertScreen2Doc(2, 20, 1, 26);
|
||||
assertScreen2Doc(2, 20, 1, 27);
|
||||
|
||||
assertScreen2Doc(2, 20, 1, 31);
|
||||
assertScreen2Doc(2, 25, 1, 32);
|
||||
assertScreen2Doc(2, 26, 1, 33);
|
||||
assertScreen2Doc(2, 33, 1, 99);
|
||||
|
||||
// Test one position after the folds. Should be all like normal.
|
||||
assertScreen2Doc(3, 0, 2, 0);
|
||||
},
|
||||
|
||||
"test getFoldsInRange()": function() {
|
||||
var session = createFoldTestSession();
|
||||
var foldLines = session.$foldData;
|
||||
var folds = foldLines[0].folds.concat(foldLines[1].folds);
|
||||
|
||||
function test(startRow, startColumn, endColumn, endRow, folds) {
|
||||
var r = new Range(startRow, startColumn, endColumn, endRow);
|
||||
var retFolds = session.getFoldsInRange(r);
|
||||
|
||||
assert.ok(retFolds.length == folds.length);
|
||||
for (var i = 0; i < retFolds.length; i++) {
|
||||
assert.equal(retFolds[i].range + "", folds[i].range + "");
|
||||
}
|
||||
}
|
||||
|
||||
test(0, 0, 0, 13, [ ]);
|
||||
test(0, 0, 0, 14, [ folds[0] ]);
|
||||
test(0, 0, 0, 18, [ folds[0] ]);
|
||||
test(0, 0, 1, 10, [ folds[0] ]);
|
||||
test(0, 0, 1, 11, [ folds[0], folds[1] ]);
|
||||
test(0, 18, 1, 11, [ folds[1] ]);
|
||||
test(2, 0, 2, 13, [ folds[1] ]);
|
||||
test(2, 10, 2, 20, [ ]);
|
||||
test(2, 10, 2, 11, [ ]);
|
||||
test(2, 19, 2, 20, [ ]);
|
||||
},
|
||||
|
||||
"test fold one-line text insert": function() {
|
||||
// These are mostly test for the FoldLine.addRemoveChars function.
|
||||
var session = createFoldTestSession();
|
||||
var undoManager = session.getUndoManager();
|
||||
var foldLines = session.$foldData;
|
||||
|
||||
function insert(row, column, text) {
|
||||
session.insert({row: row, column: column}, text);
|
||||
|
||||
// Force the session to store all changes made to the document NOW
|
||||
// on the undoManager's queue. Otherwise we can't undo in separate
|
||||
// steps later.
|
||||
session.$syncInformUndoManager();
|
||||
}
|
||||
|
||||
var foldLine, fold, folds;
|
||||
// First line.
|
||||
foldLine = session.$foldData[0];
|
||||
fold = foldLine.folds[0];
|
||||
|
||||
insert(0, 0, "0");
|
||||
assert.range(foldLine.range, 0, 14, 0, 19);
|
||||
assert.range(fold.range, 0, 14, 0, 19);
|
||||
insert(0, 14, "1");
|
||||
assert.range(foldLine.range, 0, 15, 0, 20);
|
||||
assert.range(fold.range, 0, 15, 0, 20);
|
||||
insert(0, 20, "2");
|
||||
assert.range(foldLine.range, 0, 15, 0, 20);
|
||||
assert.range(fold.range, 0, 15, 0, 20);
|
||||
|
||||
// Second line.
|
||||
foldLine = session.$foldData[1];
|
||||
folds = foldLine.folds;
|
||||
|
||||
insert(1, 0, "3");
|
||||
assert.range(foldLine.range, 1, 11, 2, 25);
|
||||
assert.range(folds[0].range, 1, 11, 2, 10);
|
||||
assert.range(folds[1].range, 2, 20, 2, 25);
|
||||
|
||||
insert(1, 11, "4");
|
||||
assert.range(foldLine.range, 1, 12, 2, 25);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 20, 2, 25);
|
||||
|
||||
insert(2, 10, "5");
|
||||
assert.range(foldLine.range, 1, 12, 2, 26);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 21, 2, 26);
|
||||
|
||||
insert(2, 21, "6");
|
||||
assert.range(foldLine.range, 1, 12, 2, 27);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 22, 2, 27);
|
||||
|
||||
insert(2, 27, "7");
|
||||
assert.range(foldLine.range, 1, 12, 2, 27);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 22, 2, 27);
|
||||
|
||||
// UNDO = REMOVE
|
||||
undoManager.undo(); // 6
|
||||
assert.range(foldLine.range, 1, 12, 2, 27);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 22, 2, 27);
|
||||
|
||||
undoManager.undo(); // 5
|
||||
assert.range(foldLine.range, 1, 12, 2, 26);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 21, 2, 26);
|
||||
|
||||
undoManager.undo(); // 4
|
||||
assert.range(foldLine.range, 1, 12, 2, 25);
|
||||
assert.range(folds[0].range, 1, 12, 2, 10);
|
||||
assert.range(folds[1].range, 2, 20, 2, 25);
|
||||
|
||||
undoManager.undo(); // 3
|
||||
assert.range(foldLine.range, 1, 11, 2, 25);
|
||||
assert.range(folds[0].range, 1, 11, 2, 10);
|
||||
assert.range(folds[1].range, 2, 20, 2, 25);
|
||||
|
||||
undoManager.undo(); // Beginning first line.
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 0, 15, 0, 20);
|
||||
assert.range(foldLines[1].range, 1, 10, 2, 25);
|
||||
|
||||
foldLine = session.$foldData[0];
|
||||
fold = foldLine.folds[0];
|
||||
|
||||
undoManager.undo(); // 2
|
||||
assert.range(foldLine.range, 0, 15, 0, 20);
|
||||
assert.range(fold.range, 0, 15, 0, 20);
|
||||
|
||||
undoManager.undo(); // 1
|
||||
assert.range(foldLine.range, 0, 14, 0, 19);
|
||||
assert.range(fold.range, 0, 14, 0, 19);
|
||||
|
||||
undoManager.undo(); // 0
|
||||
assert.range(foldLine.range, 0, 13, 0, 18);
|
||||
assert.range(fold.range, 0, 13, 0, 18);
|
||||
},
|
||||
|
||||
"test fold multi-line insert/remove": function() {
|
||||
var session = createFoldTestSession(),
|
||||
undoManager = session.getUndoManager(),
|
||||
foldLines = session.$foldData;
|
||||
function insert(row, column, text) {
|
||||
session.insert({row: row, column: column}, text);
|
||||
// Force the session to store all changes made to the document NOW
|
||||
// on the undoManager's queue. Otherwise we can't undo in separate
|
||||
// steps later.
|
||||
session.$syncInformUndoManager();
|
||||
}
|
||||
|
||||
var foldLines = session.$foldData, foldLine, fold, folds;
|
||||
|
||||
insert(0, 0, "\nfo0");
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 2, 10, 3, 25);
|
||||
|
||||
insert(2, 0, "\nba1");
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 3, 13, 4, 25);
|
||||
|
||||
insert(3, 10, "\nfo2");
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 25);
|
||||
|
||||
insert(5, 10, "\nba3");
|
||||
assert.equal(foldLines.length, 3);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 10);
|
||||
assert.range(foldLines[2].range, 6, 13, 6, 18);
|
||||
|
||||
insert(6, 18, "\nfo4");
|
||||
assert.equal(foldLines.length, 3);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 10);
|
||||
assert.range(foldLines[2].range, 6, 13, 6, 18);
|
||||
|
||||
undoManager.undo(); // 3
|
||||
assert.equal(foldLines.length, 3);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 10);
|
||||
assert.range(foldLines[2].range, 6, 13, 6, 18);
|
||||
|
||||
undoManager.undo(); // 2
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 4, 6, 5, 25);
|
||||
|
||||
undoManager.undo(); // 1
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 3, 13, 4, 25);
|
||||
|
||||
undoManager.undo(); // 0
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 1, 16, 1, 21);
|
||||
assert.range(foldLines[1].range, 2, 10, 3, 25);
|
||||
|
||||
undoManager.undo(); // Beginning
|
||||
assert.equal(foldLines.length, 2);
|
||||
assert.range(foldLines[0].range, 0, 13, 0, 18);
|
||||
assert.range(foldLines[1].range, 1, 10, 2, 25);
|
||||
// TODO: Add test for inseration inside of folds.
|
||||
},
|
||||
|
||||
"test fold wrap data compution": function() {
|
||||
function assertArray(a, b) {
|
||||
assert.ok(a.length == b.length);
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
assert.equal(a[i], b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function assertWrap(line0, line1, line2) {
|
||||
line0 && assertArray(wrapData[0], line0);
|
||||
line1 && assertArray(wrapData[1], line1);
|
||||
line2 && assertArray(wrapData[2], line2);
|
||||
}
|
||||
|
||||
function removeFoldAssertWrap(docRow, docColumn, line0, line1, line2) {
|
||||
session.removeFold(session.getFoldAt(docRow, docColumn));
|
||||
assertWrap(line0, line1, line2);
|
||||
}
|
||||
|
||||
var lines = [
|
||||
"foo bar foo bar",
|
||||
"foo bar foo bar",
|
||||
"foo bar foo bar"
|
||||
];
|
||||
|
||||
var session = new EditSession(lines.join("\n"));
|
||||
session.setUseWrapMode(true);
|
||||
session.$wrapLimit = 7;
|
||||
session.$updateWrapData(0, 2);
|
||||
var wrapData = session.$wrapData;
|
||||
|
||||
// Do a simple assertion without folds to check basic functionallity.
|
||||
assertWrap([8], [8], [8]);
|
||||
|
||||
// --- Do in line folding ---
|
||||
|
||||
// Adding a fold. The split position is inside of the fold. As placeholder
|
||||
// are not splitable, the split should be before the split.
|
||||
session.addFold("woot", new Range(0, 4, 0, 15));
|
||||
assertWrap([4], [8], [8]);
|
||||
|
||||
// Remove the fold again which should reset the wrapData.
|
||||
removeFoldAssertWrap(0, 4, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot", new Range(0, 6, 0, 9));
|
||||
assertWrap([6, 13], [8], [8]);
|
||||
removeFoldAssertWrap(0, 6, [8], [8], [8]);
|
||||
|
||||
// The fold fits into the wrap limit - no split expected.
|
||||
session.addFold("woot", new Range(0, 3, 0, 15));
|
||||
assertWrap([], [8], [8]);
|
||||
removeFoldAssertWrap(0, 4, [8], [8], [8]);
|
||||
|
||||
// Fold after split position should be all fine.
|
||||
session.addFold("woot", new Range(0, 8, 0, 15));
|
||||
assertWrap([8], [8], [8]);
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
// Fold's placeholder is far too long for wrapSplit.
|
||||
session.addFold("woot0123456789", new Range(0, 8, 0, 15));
|
||||
assertWrap([8], [8], [8]);
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
// Fold's placeholder is far too long for wrapSplit
|
||||
// + content at the end of the line
|
||||
session.addFold("woot0123456789", new Range(0, 6, 0, 8));
|
||||
assertWrap([6, 20], [8], [8]);
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot0123456789", new Range(0, 6, 0, 8));
|
||||
session.addFold("woot0123456789", new Range(0, 8, 0, 10));
|
||||
assertWrap([6, 20, 34], [8], [8]);
|
||||
session.removeFold(session.getFoldAt(0, 7));
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot0123456789", new Range(0, 7, 0, 9));
|
||||
session.addFold("woot0123456789", new Range(0, 13, 0, 15));
|
||||
assertWrap([7, 21, 25], [8], [8]);
|
||||
session.removeFold(session.getFoldAt(0, 7));
|
||||
removeFoldAssertWrap(0, 14, [8], [8], [8]);
|
||||
|
||||
// --- Do some multiline folding ---
|
||||
|
||||
// Add a fold over two lines. Note, that the wrapData[1] stays the
|
||||
// same. This is an implementation detail and expected behavior.
|
||||
session.addFold("woot", new Range(0, 8, 1, 15));
|
||||
assertWrap([8], [8 /* See comments */], [8]);
|
||||
removeFoldAssertWrap(0, 8, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot", new Range(0, 9, 1, 11));
|
||||
assertWrap([8, 14], [8 /* See comments */], [8]);
|
||||
removeFoldAssertWrap(0, 9, [8], [8], [8]);
|
||||
|
||||
session.addFold("woot", new Range(0, 9, 1, 15));
|
||||
assertWrap([8], [8 /* See comments */], [8]);
|
||||
removeFoldAssertWrap(0, 9, [8], [8], [8]);
|
||||
|
||||
return session;
|
||||
},
|
||||
|
||||
"test add fold": function() {
|
||||
var session = createFoldTestSession();
|
||||
var fold;
|
||||
|
||||
function tryAddFold(placeholder, range, shouldFail) {
|
||||
var fail = false;
|
||||
try {
|
||||
fold = session.addFold(placeholder, range);
|
||||
} catch (e) {
|
||||
fail = true;
|
||||
}
|
||||
if (fail != shouldFail) {
|
||||
throw "Expected to get an exception";
|
||||
}
|
||||
}
|
||||
|
||||
tryAddFold("foo", new Range(0, 13, 0, 17), false);
|
||||
tryAddFold("foo", new Range(0, 14, 0, 18), true);
|
||||
tryAddFold("foo", new Range(0, 13, 0, 18), false);
|
||||
assert.equal(session.$foldData[0].folds.length, 1);
|
||||
|
||||
tryAddFold("f", new Range(0, 13, 0, 18), true);
|
||||
tryAddFold("foo", new Range(0, 18, 0, 21), false);
|
||||
assert.equal(session.$foldData[0].folds.length, 2);
|
||||
session.removeFold(fold);
|
||||
|
||||
tryAddFold("foo", new Range(0, 18, 0, 22), false);
|
||||
tryAddFold("foo", new Range(0, 18, 0, 19), true);
|
||||
tryAddFold("foo", new Range(0, 22, 1, 10), false);
|
||||
},
|
||||
|
||||
"test add subfolds": function() {
|
||||
var session = createFoldTestSession();
|
||||
var fold, oldFold;
|
||||
var foldData = session.$foldData;
|
||||
|
||||
oldFold = foldData[0].folds[0];
|
||||
|
||||
fold = session.addFold("fold0", new Range(0, 10, 0, 21));
|
||||
assert.equal(foldData[0].folds.length, 1);
|
||||
assert.equal(fold.subFolds.length, 1);
|
||||
assert.equal(fold.subFolds[0], oldFold);
|
||||
|
||||
session.expandFold(fold);
|
||||
assert.equal(foldData[0].folds.length, 1);
|
||||
assert.equal(foldData[0].folds[0], oldFold);
|
||||
assert.equal(fold.subFolds.length, 0);
|
||||
|
||||
fold = session.addFold("fold0", new Range(0, 13, 2, 10));
|
||||
assert.equal(foldData.length, 1);
|
||||
assert.equal(fold.subFolds.length, 2);
|
||||
assert.equal(fold.subFolds[0], oldFold);
|
||||
|
||||
session.expandFold(fold);
|
||||
assert.equal(foldData.length, 2);
|
||||
assert.equal(foldData[0].folds.length, 1);
|
||||
assert.equal(foldData[0].folds[0], oldFold);
|
||||
assert.equal(fold.subFolds.length, 0);
|
||||
|
||||
session.unfold(null, true);
|
||||
fold = session.addFold("fold0", new Range(0, 0, 0, 21));
|
||||
session.addFold("fold0", new Range(0, 1, 0, 5));
|
||||
session.addFold("fold0", new Range(0, 6, 0, 8));
|
||||
assert.equal(fold.subFolds.length, 2);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var Text = require("./mode/text").Mode;
|
||||
var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
var CssMode = require("./mode/css").Mode;
|
||||
var HtmlMode = require("./mode/html").Mode;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
|
||||
setUp : function(next) {
|
||||
this.session1 = new EditSession(["abc", "def"]);
|
||||
this.session2 = new EditSession(["ghi", "jkl"]);
|
||||
|
||||
|
||||
this.editor = new Editor(new MockRenderer());
|
||||
next();
|
||||
},
|
||||
|
||||
"test: change document" : function() {
|
||||
this.editor.setSession(this.session1);
|
||||
assert.equal(this.editor.getSession(), this.session1);
|
||||
|
||||
this.editor.setSession(this.session2);
|
||||
assert.equal(this.editor.getSession(), this.session2);
|
||||
},
|
||||
|
||||
"test: only changes to the new document should have effect" : function() {
|
||||
var called = false;
|
||||
this.editor.onDocumentChange = function() {
|
||||
called = true;
|
||||
};
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
this.editor.setSession(this.session2);
|
||||
|
||||
this.session1.duplicateLines(0, 0);
|
||||
assert.notOk(called);
|
||||
|
||||
this.session2.duplicateLines(0, 0);
|
||||
assert.ok(called);
|
||||
},
|
||||
|
||||
"test: should use cursor of new document" : function() {
|
||||
this.session1.getSelection().moveCursorTo(0, 1);
|
||||
this.session2.getSelection().moveCursorTo(1, 0);
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
assert.position(this.editor.getCursorPosition(), 0, 1);
|
||||
|
||||
this.editor.setSession(this.session2);
|
||||
assert.position(this.editor.getCursorPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test: only changing the cursor of the new doc should not have an effect" : function() {
|
||||
this.editor.onCursorChange = function() {
|
||||
called = true;
|
||||
};
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
this.editor.setSession(this.session2);
|
||||
assert.position(this.editor.getCursorPosition(), 0, 0);
|
||||
|
||||
var called = false;
|
||||
this.session1.getSelection().moveCursorTo(0, 1);
|
||||
assert.position(this.editor.getCursorPosition(), 0, 0);
|
||||
assert.notOk(called);
|
||||
|
||||
this.session2.getSelection().moveCursorTo(1, 1);
|
||||
assert.position(this.editor.getCursorPosition(), 1, 1);
|
||||
assert.ok(called);
|
||||
},
|
||||
|
||||
"test: should use selection of new document" : function() {
|
||||
this.session1.getSelection().selectTo(0, 1);
|
||||
this.session2.getSelection().selectTo(1, 0);
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 0, 1);
|
||||
|
||||
this.editor.setSession(this.session2);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 1, 0);
|
||||
},
|
||||
|
||||
"test: only changing the selection of the new doc should not have an effect" : function() {
|
||||
this.editor.onSelectionChange = function() {
|
||||
called = true;
|
||||
};
|
||||
|
||||
this.editor.setSession(this.session1);
|
||||
this.editor.setSession(this.session2);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 0, 0);
|
||||
|
||||
var called = false;
|
||||
this.session1.getSelection().selectTo(0, 1);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 0, 0);
|
||||
assert.notOk(called);
|
||||
|
||||
this.session2.getSelection().selectTo(1, 1);
|
||||
assert.position(this.editor.getSelection().getSelectionLead(), 1, 1);
|
||||
assert.ok(called);
|
||||
},
|
||||
|
||||
"test: should use mode of new document" : function() {
|
||||
this.editor.onChangeMode = function() {
|
||||
called = true;
|
||||
};
|
||||
this.editor.setSession(this.session1);
|
||||
this.editor.setSession(this.session2);
|
||||
|
||||
var called = false;
|
||||
this.session1.setMode(new Text());
|
||||
assert.notOk(called);
|
||||
|
||||
this.session2.setMode(new JavaScriptMode());
|
||||
assert.ok(called);
|
||||
},
|
||||
|
||||
"test: should use stop worker of old document" : function(next) {
|
||||
var self = this;
|
||||
|
||||
// 1. Open an editor and set the session to CssMode
|
||||
self.editor.setSession(self.session1);
|
||||
self.session1.setMode(new CssMode());
|
||||
|
||||
// 2. Add a line or two of valid CSS.
|
||||
self.session1.setValue("DIV { color: red; }");
|
||||
|
||||
// 3. Clear the session value.
|
||||
self.session1.setValue("");
|
||||
|
||||
// 4. Set the session to HtmlMode
|
||||
self.session1.setMode(new HtmlMode());
|
||||
|
||||
// 5. Try to type valid HTML
|
||||
self.session1.insert({row: 0, column: 0}, "<html></html>");
|
||||
|
||||
setTimeout(function() {
|
||||
assert.equal(Object.keys(self.session1.getAnnotations()).length, 0);
|
||||
next();
|
||||
}, 600);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mihai Sucan.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
var lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
|
||||
"Mauris at arcu mi, eu lobortis mauris. Quisque ut libero eget " +
|
||||
"diam congue vehicula. Quisque ut odio ut mi aliquam tincidunt. " +
|
||||
"Duis lacinia aliquam lorem eget eleifend. Morbi eget felis mi. " +
|
||||
"Duis quam ligula, consequat vitae convallis volutpat, blandit " +
|
||||
"nec neque. Nulla facilisi. Etiam suscipit lorem ac justo " +
|
||||
"sollicitudin tristique. Phasellus ut posuere nunc. Aliquam " +
|
||||
"scelerisque mollis felis non gravida. Vestibulum lacus sem, " +
|
||||
"posuere non bibendum id, luctus non dolor. Aenean id metus " +
|
||||
"lorem, vel dapibus est. Donec gravida feugiat augue nec " +
|
||||
"accumsan.Lorem ipsum dolor sit amet, consectetur adipiscing " +
|
||||
"elit. Nulla vulputate, velit vitae tincidunt congue, nunc " +
|
||||
"augue accumsan velit, eu consequat turpis lectus ac orci. " +
|
||||
"Pellentesque ornare dolor feugiat dui auctor eu varius nulla " +
|
||||
"fermentum. Sed aliquam odio at velit lacinia vel fermentum " +
|
||||
"felis sodales. In dignissim magna eget nunc lobortis non " +
|
||||
"fringilla nibh ullamcorper. Donec facilisis malesuada elit " +
|
||||
"at egestas. Etiam bibendum, diam vitae tempor aliquet, dui " +
|
||||
"libero vehicula odio, eget bibendum mauris velit eu lorem.\n" +
|
||||
"consectetur";
|
||||
|
||||
function callHighlighterUpdate(session, firstRow, lastRow) {
|
||||
var rangeCount = 0;
|
||||
var mockMarkerLayer = { drawSingleLineMarker: function() {rangeCount++;} }
|
||||
session.$searchHighlight.update([], mockMarkerLayer, session, {
|
||||
firstRow: firstRow,
|
||||
lastRow: lastRow
|
||||
});
|
||||
return rangeCount;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setUp: function(next) {
|
||||
this.session = new EditSession(lipsum);
|
||||
this.editor = new Editor(new MockRenderer(), this.session);
|
||||
this.selection = this.session.getSelection();
|
||||
this.search = this.editor.$search;
|
||||
next();
|
||||
},
|
||||
|
||||
"test: highlight selected words by default": function() {
|
||||
assert.equal(this.editor.getHighlightSelectedWord(), true);
|
||||
},
|
||||
|
||||
"test: highlight a word": function() {
|
||||
this.editor.moveCursorTo(0, 9);
|
||||
this.selection.selectWord();
|
||||
|
||||
var highlighter = this.editor.session.$searchHighlight;
|
||||
assert.ok(highlighter != null);
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "ipsum");
|
||||
assert.equal(highlighter.cache.length, 0);
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 2);
|
||||
},
|
||||
|
||||
"test: highlight a word and clear highlight": function() {
|
||||
this.editor.moveCursorTo(0, 8);
|
||||
this.selection.selectWord();
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "ipsum");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 2);
|
||||
|
||||
this.session.highlight("");
|
||||
assert.equal(this.session.$searchHighlight.cache.length, 0);
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: highlight another word": function() {
|
||||
this.selection.moveCursorTo(0, 14);
|
||||
this.selection.selectWord();
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "dolor");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 4);
|
||||
},
|
||||
|
||||
"test: no selection, no highlight": function() {
|
||||
this.selection.clearSelection();
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: select a word, no highlight": function() {
|
||||
this.selection.moveCursorTo(0, 14);
|
||||
this.selection.selectWord();
|
||||
|
||||
this.editor.setHighlightSelectedWord(false);
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "dolor");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: select a word with no matches": function() {
|
||||
this.editor.setHighlightSelectedWord(true);
|
||||
|
||||
var currentOptions = this.search.getOptions();
|
||||
var newOptions = {
|
||||
wrap: true,
|
||||
wholeWord: true,
|
||||
caseSensitive: true,
|
||||
needle: "Mauris"
|
||||
};
|
||||
this.search.set(newOptions);
|
||||
|
||||
var match = this.search.find(this.session);
|
||||
assert.notEqual(match, null, "found a match for 'Mauris'");
|
||||
|
||||
this.search.set(currentOptions);
|
||||
|
||||
this.selection.setSelectionRange(match);
|
||||
|
||||
assert.equal(this.session.getTextRange(match), "Mauris");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 1);
|
||||
},
|
||||
|
||||
"test: partial word selection 1": function() {
|
||||
this.selection.moveCursorTo(0, 14);
|
||||
this.selection.selectWord();
|
||||
this.selection.selectLeft();
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "dolo");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: partial word selection 2": function() {
|
||||
this.selection.moveCursorTo(0, 13);
|
||||
this.selection.selectWord();
|
||||
this.selection.selectRight();
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "dolor ");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: partial word selection 3": function() {
|
||||
this.selection.moveCursorTo(0, 14);
|
||||
this.selection.selectWord();
|
||||
this.selection.selectLeft();
|
||||
this.selection.shiftSelection(1);
|
||||
|
||||
var range = this.selection.getRange();
|
||||
assert.equal(this.session.getTextRange(range), "olor");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
|
||||
},
|
||||
|
||||
"test: select last word": function() {
|
||||
this.selection.moveCursorTo(0, 1);
|
||||
|
||||
var currentOptions = this.search.getOptions();
|
||||
var newOptions = {
|
||||
wrap: true,
|
||||
wholeWord: true,
|
||||
caseSensitive: true,
|
||||
backwards: true,
|
||||
needle: "consectetur"
|
||||
};
|
||||
this.search.set(newOptions);
|
||||
|
||||
var match = this.search.find(this.session);
|
||||
assert.notEqual(match, null, "found a match for 'consectetur'");
|
||||
assert.position(match.start, 1, 0);
|
||||
|
||||
this.search.set(currentOptions);
|
||||
|
||||
this.selection.setSelectionRange(match);
|
||||
|
||||
assert.equal(this.session.getTextRange(match), "consectetur");
|
||||
assert.equal(callHighlighterUpdate(this.session, 0, 1), 3);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
createEditSession : function(rows, cols) {
|
||||
var line = new Array(cols + 1).join("a");
|
||||
var text = new Array(rows).join(line + "\n") + line;
|
||||
return new EditSession(text);
|
||||
},
|
||||
|
||||
"test: navigate to end of file should scroll the last line into view" : function() {
|
||||
var doc = this.createEditSession(200, 10);
|
||||
var editor = new Editor(new MockRenderer(), doc);
|
||||
|
||||
editor.navigateFileEnd();
|
||||
var cursor = editor.getCursorPosition();
|
||||
|
||||
assert.ok(editor.getFirstVisibleRow() <= cursor.row);
|
||||
assert.ok(editor.getLastVisibleRow() >= cursor.row);
|
||||
},
|
||||
|
||||
"test: navigate to start of file should scroll the first row into view" : function() {
|
||||
var doc = this.createEditSession(200, 10);
|
||||
var editor = new Editor(new MockRenderer(), doc);
|
||||
|
||||
editor.moveCursorTo(editor.getLastVisibleRow() + 20);
|
||||
editor.navigateFileStart();
|
||||
|
||||
assert.equal(editor.getFirstVisibleRow(), 0);
|
||||
},
|
||||
|
||||
"test: goto hidden line should scroll the line into the middle of the viewport" : function() {
|
||||
var editor = new Editor(new MockRenderer(), this.createEditSession(200, 5));
|
||||
|
||||
editor.navigateTo(0, 0);
|
||||
editor.gotoLine(101);
|
||||
assert.position(editor.getCursorPosition(), 100, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 89);
|
||||
|
||||
editor.navigateTo(100, 0);
|
||||
editor.gotoLine(11);
|
||||
assert.position(editor.getCursorPosition(), 10, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 0);
|
||||
|
||||
editor.navigateTo(100, 0);
|
||||
editor.gotoLine(6);
|
||||
assert.position(editor.getCursorPosition(), 5, 0);
|
||||
assert.equal(0, editor.getFirstVisibleRow(), 0);
|
||||
|
||||
editor.navigateTo(100, 0);
|
||||
editor.gotoLine(1);
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 0);
|
||||
|
||||
editor.navigateTo(0, 0);
|
||||
editor.gotoLine(191);
|
||||
assert.position(editor.getCursorPosition(), 190, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 179);
|
||||
|
||||
editor.navigateTo(0, 0);
|
||||
editor.gotoLine(196);
|
||||
assert.position(editor.getCursorPosition(), 195, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 180);
|
||||
},
|
||||
|
||||
"test: goto visible line should only move the cursor and not scroll": function() {
|
||||
var editor = new Editor(new MockRenderer(), this.createEditSession(200, 5));
|
||||
|
||||
editor.navigateTo(0, 0);
|
||||
editor.gotoLine(12);
|
||||
assert.position(editor.getCursorPosition(), 11, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 0);
|
||||
|
||||
editor.navigateTo(30, 0);
|
||||
editor.gotoLine(33);
|
||||
assert.position(editor.getCursorPosition(), 32, 0);
|
||||
assert.equal(editor.getFirstVisibleRow(), 30);
|
||||
},
|
||||
|
||||
"test: navigate from the end of a long line down to a short line and back should maintain the curser column": function() {
|
||||
var editor = new Editor(new MockRenderer(), new EditSession(["123456", "1"]));
|
||||
|
||||
editor.navigateTo(0, 6);
|
||||
assert.position(editor.getCursorPosition(), 0, 6);
|
||||
|
||||
editor.navigateDown();
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
|
||||
editor.navigateUp();
|
||||
assert.position(editor.getCursorPosition(), 0, 6);
|
||||
},
|
||||
|
||||
"test: reset desired column on navigate left or right": function() {
|
||||
var editor = new Editor(new MockRenderer(), new EditSession(["123456", "12"]));
|
||||
|
||||
editor.navigateTo(0, 6);
|
||||
assert.position(editor.getCursorPosition(), 0, 6);
|
||||
|
||||
editor.navigateDown();
|
||||
assert.position(editor.getCursorPosition(), 1, 2);
|
||||
|
||||
editor.navigateLeft();
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
|
||||
editor.navigateUp();
|
||||
assert.position(editor.getCursorPosition(), 0, 1);
|
||||
},
|
||||
|
||||
"test: typing text should update the desired column": function() {
|
||||
var editor = new Editor(new MockRenderer(), new EditSession(["1234", "1234567890"]));
|
||||
|
||||
editor.navigateTo(0, 3);
|
||||
editor.insert("juhu");
|
||||
|
||||
editor.navigateDown();
|
||||
assert.position(editor.getCursorPosition(), 1, 7);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,562 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("./test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var JavaScriptMode = require("./mode/javascript").Mode;
|
||||
var UndoManager = require("./undomanager").UndoManager;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var assert = require("./test/assertions");
|
||||
|
||||
module.exports = {
|
||||
"test: delete line from the middle" : function() {
|
||||
var session = new EditSession(["a", "b", "c", "d"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "a\nc\nd");
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "a\nd");
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "a");
|
||||
assert.position(editor.getCursorPosition(), 0, 1);
|
||||
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "");
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
},
|
||||
|
||||
"test: delete multiple selected lines" : function() {
|
||||
var session = new EditSession(["a", "b", "c", "d"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.removeLines();
|
||||
assert.equal(session.toString(), "a\nd");
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test: delete first line" : function() {
|
||||
var session = new EditSession(["a", "b", "c"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.removeLines();
|
||||
|
||||
assert.equal(session.toString(), "b\nc");
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
},
|
||||
|
||||
"test: delete last should also delete the new line of the previous line" : function() {
|
||||
var session = new EditSession(["a", "b", "c", ""].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(3, 0);
|
||||
|
||||
editor.removeLines();
|
||||
assert.equal(session.toString(), "a\nb\nc");
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
|
||||
editor.removeLines();
|
||||
assert.equal(session.toString(), "a\nb");
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
},
|
||||
|
||||
"test: indent block" : function() {
|
||||
var session = new EditSession(["a12345", "b12345", "c12345"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 3);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.indent();
|
||||
|
||||
assert.equal(["a12345", " b12345", " c12345"].join("\n"), session.toString());
|
||||
|
||||
assert.position(editor.getCursorPosition(), 2, 7);
|
||||
|
||||
var range = editor.getSelectionRange();
|
||||
assert.position(range.start, 1, 7);
|
||||
assert.position(range.end, 2, 7);
|
||||
},
|
||||
|
||||
"test: indent selected lines" : function() {
|
||||
var session = new EditSession(["a12345", "b12345", "c12345"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.indent();
|
||||
assert.equal(["a12345", " b12345", "c12345"].join("\n"), session.toString());
|
||||
},
|
||||
|
||||
"test: no auto indent if cursor is before the {" : function() {
|
||||
var session = new EditSession("{", new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 0);
|
||||
editor.onTextInput("\n");
|
||||
assert.equal(["", "{"].join("\n"), session.toString());
|
||||
},
|
||||
|
||||
"test: outdent block" : function() {
|
||||
var session = new EditSession([" a12345", " b12345", " c12345"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 5);
|
||||
editor.getSelection().selectDown();
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.blockOutdent();
|
||||
assert.equal(session.toString(), [" a12345", "b12345", " c12345"].join("\n"));
|
||||
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
|
||||
var range = editor.getSelectionRange();
|
||||
assert.position(range.start, 0, 1);
|
||||
assert.position(range.end, 2, 1);
|
||||
|
||||
editor.blockOutdent();
|
||||
assert.equal(session.toString(), ["a12345", "b12345", "c12345"].join("\n"));
|
||||
|
||||
var range = editor.getSelectionRange();
|
||||
assert.position(range.start, 0, 0);
|
||||
assert.position(range.end, 2, 0);
|
||||
},
|
||||
|
||||
"test: outent without a selection should update cursor" : function() {
|
||||
var session = new EditSession(" 12");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 3);
|
||||
editor.blockOutdent(" ");
|
||||
|
||||
assert.equal(session.toString(), " 12");
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
},
|
||||
|
||||
"test: comment lines should perserve selection" : function() {
|
||||
var session = new EditSession([" abc", "cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 2);
|
||||
editor.getSelection().selectDown();
|
||||
editor.toggleCommentLines();
|
||||
|
||||
assert.equal(["// abc", "//cde"].join("\n"), session.toString());
|
||||
|
||||
var selection = editor.getSelectionRange();
|
||||
assert.position(selection.start, 0, 4);
|
||||
assert.position(selection.end, 1, 4);
|
||||
},
|
||||
|
||||
"test: uncomment lines should perserve selection" : function() {
|
||||
var session = new EditSession(["// abc", "//cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 1);
|
||||
editor.getSelection().selectDown();
|
||||
editor.getSelection().selectRight();
|
||||
editor.getSelection().selectRight();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
|
||||
assert.equal([" abc", "cde"].join("\n"), session.toString());
|
||||
assert.range(editor.getSelectionRange(), 0, 0, 1, 1);
|
||||
},
|
||||
|
||||
"test: toggle comment lines twice should return the original text" : function() {
|
||||
var session = new EditSession([" abc", "cde", "fg"], new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 0);
|
||||
editor.getSelection().selectDown();
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
editor.toggleCommentLines();
|
||||
|
||||
assert.equal([" abc", "cde", "fg"].join("\n"), session.toString());
|
||||
},
|
||||
|
||||
|
||||
"test: comment lines - if the selection end is at the line start it should stay there": function() {
|
||||
//select down
|
||||
var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 0);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
assert.range(editor.getSelectionRange(), 0, 2, 1, 0);
|
||||
|
||||
// select up
|
||||
var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode());
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.getSelection().selectUp();
|
||||
|
||||
editor.toggleCommentLines();
|
||||
assert.range(editor.getSelectionRange(), 0, 2, 1, 0);
|
||||
},
|
||||
|
||||
"test: move lines down should select moved lines" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(0, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.moveLinesDown();
|
||||
assert.equal(["33", "11", "22", "44"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
|
||||
|
||||
editor.moveLinesDown();
|
||||
assert.equal(["33", "44", "11", "22"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 2, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 2);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 2, 0);
|
||||
|
||||
// moving again should have no effect
|
||||
editor.moveLinesDown();
|
||||
assert.equal(["33", "44", "11", "22"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 2, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 2);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 2, 0);
|
||||
},
|
||||
|
||||
"test: move lines up should select moved lines" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(2, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.moveLinesUp();
|
||||
assert.equal(session.toString(), ["11", "33", "44", "22"].join("\n"));
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
|
||||
|
||||
editor.moveLinesUp();
|
||||
assert.equal(session.toString(), ["33", "44", "11", "22"].join("\n"));
|
||||
assert.position(editor.getCursorPosition(), 0, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 2, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 0, 0);
|
||||
},
|
||||
|
||||
"test: move line without active selection should not move cursor relative to the moved line" : function()
|
||||
{
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.clearSelection();
|
||||
|
||||
editor.moveLinesDown();
|
||||
assert.equal(["11", "33", "22", "44"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 2, 1);
|
||||
|
||||
editor.clearSelection();
|
||||
|
||||
editor.moveLinesUp();
|
||||
assert.equal(["11", "22", "33", "44"].join("\n"), session.toString());
|
||||
assert.position(editor.getCursorPosition(), 1, 1);
|
||||
},
|
||||
|
||||
"test: copy lines down should select lines and place cursor at the selection start" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.copyLinesDown();
|
||||
assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString());
|
||||
|
||||
assert.position(editor.getCursorPosition(), 3, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 5, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 3, 0);
|
||||
},
|
||||
|
||||
"test: copy lines up should select lines and place cursor at the selection start" : function() {
|
||||
var session = new EditSession(["11", "22", "33", "44"].join("\n"));
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.getSelection().selectDown();
|
||||
|
||||
editor.copyLinesUp();
|
||||
assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString());
|
||||
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
|
||||
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
|
||||
},
|
||||
|
||||
"test: input a tab with soft tab should convert it to spaces" : function() {
|
||||
var session = new EditSession("");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
session.setTabSize(2);
|
||||
session.setUseSoftTabs(true);
|
||||
|
||||
editor.onTextInput("\t");
|
||||
assert.equal(session.toString(), " ");
|
||||
|
||||
session.setTabSize(5);
|
||||
editor.onTextInput("\t");
|
||||
assert.equal(session.toString(), " ");
|
||||
},
|
||||
|
||||
"test: input tab without soft tabs should keep the tab character" : function() {
|
||||
var session = new EditSession("");
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
session.setUseSoftTabs(false);
|
||||
|
||||
editor.onTextInput("\t");
|
||||
assert.equal(session.toString(), "\t");
|
||||
},
|
||||
|
||||
"test: undo/redo for delete line" : function() {
|
||||
var session = new EditSession(["111", "222", "333"]);
|
||||
var undoManager = new UndoManager();
|
||||
session.setUndoManager(undoManager);
|
||||
|
||||
var initialText = session.toString();
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
|
||||
editor.removeLines();
|
||||
var step1 = session.toString();
|
||||
assert.equal(step1, "222\n333");
|
||||
session.$syncInformUndoManager();
|
||||
|
||||
editor.removeLines();
|
||||
var step2 = session.toString();
|
||||
assert.equal(step2, "333");
|
||||
session.$syncInformUndoManager();
|
||||
|
||||
editor.removeLines();
|
||||
var step3 = session.toString();
|
||||
assert.equal(step3, "");
|
||||
session.$syncInformUndoManager();
|
||||
|
||||
undoManager.undo();
|
||||
session.$syncInformUndoManager();
|
||||
assert.equal(session.toString(), step2);
|
||||
|
||||
undoManager.undo();
|
||||
session.$syncInformUndoManager();
|
||||
assert.equal(session.toString(), step1);
|
||||
|
||||
undoManager.undo();
|
||||
session.$syncInformUndoManager();
|
||||
assert.equal(session.toString(), initialText);
|
||||
|
||||
undoManager.undo();
|
||||
session.$syncInformUndoManager();
|
||||
assert.equal(session.toString(), initialText);
|
||||
},
|
||||
|
||||
"test: remove left should remove character left of the cursor" : function() {
|
||||
var session = new EditSession(["123", "456"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.remove("left");
|
||||
assert.equal(session.toString(), "123\n56");
|
||||
},
|
||||
|
||||
"test: remove left should remove line break if cursor is at line start" : function() {
|
||||
var session = new EditSession(["123", "456"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.remove("left");
|
||||
assert.equal(session.toString(), "123456");
|
||||
},
|
||||
|
||||
"test: remove left should remove tabsize spaces if cursor is on a tab stop and preceeded by spaces" : function() {
|
||||
var session = new EditSession(["123", " 456"]);
|
||||
session.setUseSoftTabs(true);
|
||||
session.setTabSize(4);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 8);
|
||||
editor.remove("left");
|
||||
assert.equal(session.toString(), "123\n 456");
|
||||
},
|
||||
|
||||
"test: transpose at line start should be a noop": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.transposeLetters();
|
||||
|
||||
assert.equal(session.getValue(), ["123", "4567", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transpose in line should swap the charaters before and after the cursor": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 2);
|
||||
editor.transposeLetters();
|
||||
|
||||
assert.equal(session.getValue(), ["123", "4657", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transpose at line end should swap the last two characters": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 4);
|
||||
editor.transposeLetters();
|
||||
|
||||
assert.equal(session.getValue(), ["123", "4576", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transpose with non empty selection should be a noop": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 1);
|
||||
editor.getSelection().selectRight();
|
||||
editor.transposeLetters();
|
||||
|
||||
assert.equal(session.getValue(), ["123", "4567", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transpose should move the cursor behind the last swapped character": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 2);
|
||||
editor.transposeLetters();
|
||||
assert.position(editor.getCursorPosition(), 1, 3);
|
||||
},
|
||||
|
||||
"test: remove to line end": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 2);
|
||||
editor.removeToLineEnd();
|
||||
assert.equal(session.getValue(), ["123", "45", "89"].join("\n"));
|
||||
},
|
||||
|
||||
"test: remove to line end at line end should remove the new line": function() {
|
||||
var session = new EditSession(["123", "4567", "89"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 4);
|
||||
editor.removeToLineEnd();
|
||||
assert.position(editor.getCursorPosition(), 1, 4);
|
||||
assert.equal(session.getValue(), ["123", "456789"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transform selection to uppercase": function() {
|
||||
var session = new EditSession(["ajax", "dot", "org"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.getSelection().selectLineEnd();
|
||||
editor.toUpperCase()
|
||||
assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transform word to uppercase": function() {
|
||||
var session = new EditSession(["ajax", "dot", "org"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.toUpperCase()
|
||||
assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n"));
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
},
|
||||
|
||||
"test: transform selection to lowercase": function() {
|
||||
var session = new EditSession(["AJAX", "DOT", "ORG"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.getSelection().selectLineEnd();
|
||||
editor.toLowerCase()
|
||||
assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n"));
|
||||
},
|
||||
|
||||
"test: transform word to lowercase": function() {
|
||||
var session = new EditSession(["AJAX", "DOT", "ORG"]);
|
||||
|
||||
var editor = new Editor(new MockRenderer(), session);
|
||||
editor.moveCursorTo(1, 0);
|
||||
editor.toLowerCase()
|
||||
assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n"));
|
||||
assert.position(editor.getCursorPosition(), 1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
.ace_editor {
|
||||
font-family: 'Monaco', 'Menlo', 'Droid Sans Mono', 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ace_editor .ace_gutter {
|
||||
width: 25px !important;
|
||||
display: block;
|
||||
float: left;
|
||||
text-align: right;
|
||||
padding: 0 3px 0 0;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.ace_line { clear: both; }
|
||||
|
||||
*.ace_gutter-cell {
|
||||
-moz-user-select: -moz-none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jan Jongboom <fabian AT ajax DOT org>
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("../edit_session").EditSession;
|
||||
var TextLayer = require("../layer/text").Text;
|
||||
var baseStyles = require("../requirejs/text!./static.css");
|
||||
|
||||
/* Transforms a given input code snippet into HTML using the given mode
|
||||
*
|
||||
* @param {string} input Code snippet
|
||||
* @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode')
|
||||
* @param {string} r Code snippet
|
||||
* @returns {object} An object containing: html, css
|
||||
*/
|
||||
|
||||
exports.render = function(input, mode, theme, lineStart, disableGutter) {
|
||||
lineStart = parseInt(lineStart || 1, 10);
|
||||
|
||||
var session = new EditSession("");
|
||||
session.setMode(mode);
|
||||
session.setUseWorker(false);
|
||||
|
||||
var textLayer = new TextLayer(document.createElement("div"));
|
||||
textLayer.setSession(session);
|
||||
textLayer.config = {
|
||||
characterWidth: 10,
|
||||
lineHeight: 20
|
||||
};
|
||||
|
||||
session.setValue(input);
|
||||
|
||||
var stringBuilder = [];
|
||||
var length = session.getLength();
|
||||
|
||||
for(var ix = 0; ix < length; ix++) {
|
||||
var lineTokens = session.getTokens(ix);
|
||||
stringBuilder.push("<div class='ace_line'>");
|
||||
if (!disableGutter)
|
||||
stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + (ix + lineStart) + "</span>");
|
||||
textLayer.$renderLine(stringBuilder, 0, lineTokens, true);
|
||||
stringBuilder.push("</div>");
|
||||
}
|
||||
|
||||
// let's prepare the whole html
|
||||
var html = "<div class=':cssClass'>\
|
||||
<div class='ace_editor ace_scroller ace_text-layer'>\
|
||||
:code\
|
||||
</div>\
|
||||
</div>".replace(/:cssClass/, theme.cssClass).replace(/:code/, stringBuilder.join(""));
|
||||
|
||||
textLayer.destroy();
|
||||
|
||||
return {
|
||||
css: baseStyles + theme.cssText,
|
||||
html: html
|
||||
};
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
require("../test/mockdom");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var highlighter = require("./static_highlight");
|
||||
var JavaScriptMode = require("../mode/javascript").Mode;
|
||||
|
||||
// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite
|
||||
module.exports = {
|
||||
timeout: 10000,
|
||||
|
||||
"test simple snippet": function(next) {
|
||||
var theme = require("../theme/tomorrow");
|
||||
var snippet = "/** this is a function\n\
|
||||
*\n\
|
||||
*/\n\
|
||||
function hello (a, b, c) {\n\
|
||||
console.log(a * b + c + 'sup?');\n\
|
||||
}";
|
||||
var mode = new JavaScriptMode();
|
||||
|
||||
var isError = false, result;
|
||||
try {
|
||||
result = highlighter.render(snippet, mode, theme);
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
isError = true;
|
||||
}
|
||||
// todo: write something more meaningful
|
||||
assert.equal(isError, false);
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
"test css from theme is used": function(next) {
|
||||
var theme = require("../theme/tomorrow");
|
||||
var snippet = "/** this is a function\n\
|
||||
*\n\
|
||||
*/\n\
|
||||
function hello (a, b, c) {\n\
|
||||
console.log(a * b + c + 'sup?');\n\
|
||||
}";
|
||||
var mode = new JavaScriptMode();
|
||||
|
||||
var isError = false, result;
|
||||
result = highlighter.render(snippet, mode, theme);
|
||||
|
||||
assert.ok(result.css.indexOf(theme.cssText) !== -1);
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
"test theme classname should be in output html": function (next) {
|
||||
var theme = require("../theme/tomorrow");
|
||||
var snippet = "/** this is a function\n\
|
||||
*\n\
|
||||
*/\n\
|
||||
function hello (a, b, c) {\n\
|
||||
console.log(a * b + c + 'sup?');\n\
|
||||
}";
|
||||
var mode = new JavaScriptMode();
|
||||
|
||||
var isError = false, result;
|
||||
result = highlighter.render(snippet, mode, theme);
|
||||
assert.equal(!!result.html.match(/<div class='ace-tomorrow'>/), true);
|
||||
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec();
|
||||
}
|
||||
@@ -0,0 +1,536 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kevin Dangoor (kdangoor@mozilla.com)
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
* Harutyun Amirjanyan [harutyun@c9.io]
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var event = require("../lib/event");
|
||||
var UA = require("../lib/useragent");
|
||||
var net = require("../lib/net");
|
||||
var ace = require("../ace");
|
||||
|
||||
require("ace/theme/textmate");
|
||||
|
||||
module.exports = exports = ace;
|
||||
|
||||
/*
|
||||
* Returns the CSS property of element.
|
||||
* 1) If the CSS property is on the style object of the element, use it, OR
|
||||
* 2) Compute the CSS property
|
||||
*
|
||||
* If the property can't get computed, is 'auto' or 'intrinsic', the former
|
||||
* calculated property is used (this can happen in cases where the textarea
|
||||
* is hidden and has no dimension styles).
|
||||
*/
|
||||
var getCSSProperty = function(element, container, property) {
|
||||
var ret = element.style[property];
|
||||
|
||||
if (!ret) {
|
||||
if (window.getComputedStyle) {
|
||||
ret = window.getComputedStyle(element, '').getPropertyValue(property);
|
||||
} else {
|
||||
ret = element.currentStyle[property];
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret || ret == 'auto' || ret == 'intrinsic') {
|
||||
ret = container.style[property];
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
function applyStyles(elm, styles) {
|
||||
for (var style in styles) {
|
||||
elm.style[style] = styles[style];
|
||||
}
|
||||
}
|
||||
|
||||
function setupContainer(element, getValue) {
|
||||
if (element.type != 'textarea') {
|
||||
throw "Textarea required!";
|
||||
}
|
||||
|
||||
var parentNode = element.parentNode;
|
||||
|
||||
// This will hold the editor.
|
||||
var container = document.createElement('div');
|
||||
|
||||
// To put Ace in the place of the textarea, we have to copy a few of the
|
||||
// textarea's style attributes to the div container.
|
||||
//
|
||||
// The problem is that the properties have to get computed (they might be
|
||||
// defined by a CSS file on the page - you can't access such rules that
|
||||
// apply to an element via elm.style). Computed properties are converted to
|
||||
// pixels although the dimension might be given as percentage. When the
|
||||
// window resizes, the dimensions defined by percentages changes, so the
|
||||
// properties have to get recomputed to get the new/true pixels.
|
||||
var resizeEvent = function() {
|
||||
var style = 'position:relative;';
|
||||
[
|
||||
'margin-top', 'margin-left', 'margin-right', 'margin-bottom'
|
||||
].forEach(function(item) {
|
||||
style += item + ':' +
|
||||
getCSSProperty(element, container, item) + ';';
|
||||
});
|
||||
|
||||
// Calculating the width/height of the textarea is somewhat tricky. To
|
||||
// do it right, you have to include the paddings to the sides as well
|
||||
// (eg. width = width + padding-left, -right). This works well, as
|
||||
// long as the width of the element is not set or given in pixels. In
|
||||
// this case and after the textarea is hidden, getCSSProperty(element,
|
||||
// container, 'width') will still return pixel value. If the element
|
||||
// has realtiv dimensions (e.g. width='95<percent>')
|
||||
// getCSSProperty(...) will return pixel values only as long as the
|
||||
// textarea is visible. After it is hidden getCSSProperty will return
|
||||
// the relative dimensions as they are set on the element (in the case
|
||||
// of width, 95<percent>).
|
||||
// Making the sum of pixel vaules (e.g. padding) and realtive values
|
||||
// (e.g. <percent>) is not possible. As such the padding styles are
|
||||
// ignored.
|
||||
|
||||
// The complete width is the width of the textarea + the padding
|
||||
// to the left and right.
|
||||
var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px");
|
||||
var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px");
|
||||
style += 'height:' + height + ';width:' + width + ';';
|
||||
|
||||
// Set the display property to 'inline-block'.
|
||||
style += 'display:inline-block;';
|
||||
container.setAttribute('style', style);
|
||||
};
|
||||
event.addListener(window, 'resize', resizeEvent);
|
||||
|
||||
// Call the resizeEvent once, so that the size of the container is
|
||||
// calculated.
|
||||
resizeEvent();
|
||||
|
||||
// Insert the div container after the element.
|
||||
if (element.nextSibling) {
|
||||
parentNode.insertBefore(container, element.nextSibling);
|
||||
} else {
|
||||
parentNode.appendChild(container);
|
||||
}
|
||||
|
||||
// Override the forms onsubmit function. Set the innerHTML and value
|
||||
// of the textarea before submitting.
|
||||
while (parentNode !== document) {
|
||||
if (parentNode.tagName.toUpperCase() === 'FORM') {
|
||||
var oldSumit = parentNode.onsubmit;
|
||||
// Override the onsubmit function of the form.
|
||||
parentNode.onsubmit = function(evt) {
|
||||
element.innerHTML = getValue();
|
||||
element.value = getValue();
|
||||
// If there is a onsubmit function already, then call
|
||||
// it with the current context and pass the event.
|
||||
if (oldSumit) {
|
||||
oldSumit.call(this, evt);
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
parentNode = parentNode.parentNode;
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
exports.transformTextarea = function(element, loader) {
|
||||
var session;
|
||||
var container = setupContainer(element, function() {
|
||||
return session.getValue();
|
||||
});
|
||||
|
||||
// Hide the element.
|
||||
element.style.display = 'none';
|
||||
container.style.background = 'white';
|
||||
|
||||
//
|
||||
var editorDiv = document.createElement("div");
|
||||
applyStyles(editorDiv, {
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
right: "0px",
|
||||
bottom: "0px",
|
||||
border: "1px solid gray"
|
||||
});
|
||||
container.appendChild(editorDiv);
|
||||
|
||||
var settingOpener = document.createElement("div");
|
||||
applyStyles(settingOpener, {
|
||||
position: "absolute",
|
||||
width: "15px",
|
||||
right: "0px",
|
||||
bottom: "0px",
|
||||
background: "red",
|
||||
cursor: "nw-resize",
|
||||
borderStyle: "solid",
|
||||
borderWidth: "9px 8px 10px 9px",
|
||||
width: "2px",
|
||||
borderColor: "lightblue gray gray lightblue",
|
||||
zIndex: 101
|
||||
});
|
||||
|
||||
var settingDiv = document.createElement("div");
|
||||
var settingDivStyles = {
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
right: "0px",
|
||||
bottom: "0px",
|
||||
position: "absolute",
|
||||
padding: "5px",
|
||||
zIndex: 100,
|
||||
color: "white",
|
||||
display: "none",
|
||||
overflow: "auto",
|
||||
fontSize: "14px"
|
||||
};
|
||||
if (!UA.isOldIE) {
|
||||
settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)";
|
||||
} else {
|
||||
settingDivStyles.backgroundColor = "#333";
|
||||
}
|
||||
|
||||
applyStyles(settingDiv, settingDivStyles);
|
||||
container.appendChild(settingDiv);
|
||||
|
||||
// Power up ace on the textarea:
|
||||
var options = {};
|
||||
|
||||
var editor = ace.edit(editorDiv);
|
||||
session = editor.getSession();
|
||||
|
||||
session.setValue(element.value || element.innerHTML);
|
||||
editor.focus();
|
||||
|
||||
// Add the settingPanel opener to the editor's div.
|
||||
editorDiv.appendChild(settingOpener);
|
||||
|
||||
// Create the API.
|
||||
setupApi(editor, editorDiv, settingDiv, ace, options, loader);
|
||||
|
||||
// Create the setting's panel.
|
||||
setupSettingPanel(settingDiv, settingOpener, editor, options);
|
||||
|
||||
var state = "";
|
||||
event.addListener(settingOpener, "mousemove", function(e) {
|
||||
var rect = this.getBoundingClientRect();
|
||||
var x = e.clientX - rect.left, y = e.clientY - rect.top;
|
||||
if (x + y < (rect.width + rect.height)/2) {
|
||||
this.style.cursor = "pointer";
|
||||
state = "toggle";
|
||||
} else {
|
||||
state = "resize";
|
||||
this.style.cursor = "nw-resize";
|
||||
}
|
||||
});
|
||||
|
||||
event.addListener(settingOpener, "mousedown", function(e) {
|
||||
if (state == "toggle") {
|
||||
editor.setDisplaySettings();
|
||||
return;
|
||||
}
|
||||
container.style.zIndex = 100000;
|
||||
var rect = container.getBoundingClientRect();
|
||||
var startX = rect.width + rect.left - e.clientX;
|
||||
var startY = rect.height + rect.top - e.clientY;
|
||||
event.capture(settingOpener, function(e) {
|
||||
container.style.width = e.clientX - rect.left + startX + "px";
|
||||
container.style.height = e.clientY - rect.top + startY + "px";
|
||||
editor.resize();
|
||||
}, function() {});
|
||||
});
|
||||
|
||||
return editor;
|
||||
};
|
||||
|
||||
function load(url, module, callback) {
|
||||
net.loadScript(url, function() {
|
||||
require([module], callback);
|
||||
});
|
||||
}
|
||||
|
||||
function setupApi(editor, editorDiv, settingDiv, ace, options, loader) {
|
||||
var session = editor.getSession();
|
||||
var renderer = editor.renderer;
|
||||
loader = loader || load;
|
||||
|
||||
function toBool(value) {
|
||||
return value == "true";
|
||||
}
|
||||
|
||||
editor.setDisplaySettings = function(display) {
|
||||
if (display == null)
|
||||
display = settingDiv.style.display == "none";
|
||||
settingDiv.style.display = display ? "block" : "none";
|
||||
};
|
||||
|
||||
editor.setOption = function(key, value) {
|
||||
if (options[key] == value) return;
|
||||
|
||||
switch (key) {
|
||||
case "gutter":
|
||||
renderer.setShowGutter(toBool(value));
|
||||
break;
|
||||
|
||||
case "mode":
|
||||
if (value != "text") {
|
||||
// Load the required mode file. Files get loaded only once.
|
||||
loader("mode-" + value + ".js", "ace/mode/" + value, function() {
|
||||
var aceMode = require("../mode/" + value).Mode;
|
||||
session.setMode(new aceMode());
|
||||
});
|
||||
} else {
|
||||
session.setMode(new (require("../mode/text").Mode));
|
||||
}
|
||||
break;
|
||||
|
||||
case "theme":
|
||||
if (value != "textmate") {
|
||||
// Load the required theme file. Files get loaded only once.
|
||||
loader("theme-" + value + ".js", "ace/theme/" + value, function() {
|
||||
editor.setTheme("ace/theme/" + value);
|
||||
});
|
||||
} else {
|
||||
editor.setTheme("ace/theme/textmate");
|
||||
}
|
||||
break;
|
||||
|
||||
case "fontSize":
|
||||
editorDiv.style.fontSize = value;
|
||||
break;
|
||||
|
||||
case "softWrap":
|
||||
switch (value) {
|
||||
case "off":
|
||||
session.setUseWrapMode(false);
|
||||
renderer.setPrintMarginColumn(80);
|
||||
break;
|
||||
case "40":
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(40, 40);
|
||||
renderer.setPrintMarginColumn(40);
|
||||
break;
|
||||
case "80":
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(80, 80);
|
||||
renderer.setPrintMarginColumn(80);
|
||||
break;
|
||||
case "free":
|
||||
session.setUseWrapMode(true);
|
||||
session.setWrapLimitRange(null, null);
|
||||
renderer.setPrintMarginColumn(80);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "useSoftTabs":
|
||||
session.setUseSoftTabs(toBool(value));
|
||||
break;
|
||||
|
||||
case "showPrintMargin":
|
||||
renderer.setShowPrintMargin(toBool(value));
|
||||
break;
|
||||
|
||||
case "showInvisibles":
|
||||
editor.setShowInvisibles(toBool(value));
|
||||
break;
|
||||
}
|
||||
|
||||
options[key] = value;
|
||||
};
|
||||
|
||||
editor.getOption = function(key) {
|
||||
return options[key];
|
||||
};
|
||||
|
||||
editor.getOptions = function() {
|
||||
return options;
|
||||
};
|
||||
|
||||
for (var option in exports.options) {
|
||||
editor.setOption(option, exports.options[option]);
|
||||
}
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
function setupSettingPanel(settingDiv, settingOpener, editor, options) {
|
||||
var BOOL = {
|
||||
"true": true,
|
||||
"false": false
|
||||
};
|
||||
|
||||
var desc = {
|
||||
mode: "Mode:",
|
||||
gutter: "Display Gutter:",
|
||||
theme: "Theme:",
|
||||
fontSize: "Font Size:",
|
||||
softWrap: "Soft Wrap:",
|
||||
showPrintMargin: "Show Print Margin:",
|
||||
useSoftTabs: "Use Soft Tabs:",
|
||||
showInvisibles: "Show Invisibles"
|
||||
};
|
||||
|
||||
var optionValues = {
|
||||
mode: {
|
||||
text: "Plain",
|
||||
javascript: "JavaScript",
|
||||
xml: "XML",
|
||||
html: "HTML",
|
||||
css: "CSS",
|
||||
scss: "SCSS",
|
||||
python: "Python",
|
||||
php: "PHP",
|
||||
java: "Java",
|
||||
ruby: "Ruby",
|
||||
c_cpp: "C/C++",
|
||||
coffee: "CoffeeScript",
|
||||
json: "json",
|
||||
perl: "Perl",
|
||||
clojure: "Clojure",
|
||||
ocaml: "OCaml",
|
||||
csharp: "C#",
|
||||
haxe: "haXe",
|
||||
svg: "SVG",
|
||||
textile: "Textile",
|
||||
groovy: "Groovy",
|
||||
liquid: "Liquid",
|
||||
Scala: "Scala"
|
||||
},
|
||||
theme: {
|
||||
clouds: "Clouds",
|
||||
clouds_midnight: "Clouds Midnight",
|
||||
cobalt: "Cobalt",
|
||||
crimson_editor: "Crimson Editor",
|
||||
dawn: "Dawn",
|
||||
eclipse: "Eclipse",
|
||||
idle_fingers: "Idle Fingers",
|
||||
kr_theme: "Kr Theme",
|
||||
merbivore: "Merbivore",
|
||||
merbivore_soft: "Merbivore Soft",
|
||||
mono_industrial: "Mono Industrial",
|
||||
monokai: "Monokai",
|
||||
pastel_on_dark: "Pastel On Dark",
|
||||
solarized_dark: "Solarized Dark",
|
||||
solarized_light: "Solarized Light",
|
||||
textmate: "Textmate",
|
||||
twilight: "Twilight",
|
||||
vibrant_ink: "Vibrant Ink"
|
||||
},
|
||||
gutter: BOOL,
|
||||
fontSize: {
|
||||
"10px": "10px",
|
||||
"11px": "11px",
|
||||
"12px": "12px",
|
||||
"14px": "14px",
|
||||
"16px": "16px"
|
||||
},
|
||||
softWrap: {
|
||||
off: "Off",
|
||||
40: "40",
|
||||
80: "80",
|
||||
free: "Free"
|
||||
},
|
||||
showPrintMargin: BOOL,
|
||||
useSoftTabs: BOOL,
|
||||
showInvisibles: BOOL
|
||||
};
|
||||
|
||||
var table = [];
|
||||
table.push("<table><tr><th>Setting</th><th>Value</th></tr>");
|
||||
|
||||
function renderOption(builder, option, obj, cValue) {
|
||||
builder.push("<select title='" + option + "'>");
|
||||
for (var value in obj) {
|
||||
builder.push("<option value='" + value + "' ");
|
||||
|
||||
if (cValue == value) {
|
||||
builder.push(" selected ");
|
||||
}
|
||||
|
||||
builder.push(">",
|
||||
obj[value],
|
||||
"</option>");
|
||||
}
|
||||
builder.push("</select>");
|
||||
}
|
||||
|
||||
for (var option in options) {
|
||||
table.push("<tr><td>", desc[option], "</td>");
|
||||
table.push("<td>");
|
||||
renderOption(table, option, optionValues[option], options[option]);
|
||||
table.push("</td></tr>");
|
||||
}
|
||||
table.push("</table>");
|
||||
settingDiv.innerHTML = table.join("");
|
||||
|
||||
var selects = settingDiv.getElementsByTagName("select");
|
||||
for (var i = 0; i < selects.length; i++) {
|
||||
var onChange = (function() {
|
||||
var select = selects[i];
|
||||
return function() {
|
||||
var option = select.title;
|
||||
var value = select.value;
|
||||
editor.setOption(option, value);
|
||||
};
|
||||
})();
|
||||
selects[i].onchange = onChange;
|
||||
}
|
||||
|
||||
var button = document.createElement("input");
|
||||
button.type = "button";
|
||||
button.value = "Hide";
|
||||
event.addListener(button, "click", function() {
|
||||
editor.setDisplaySettings(false);
|
||||
});
|
||||
settingDiv.appendChild(button);
|
||||
}
|
||||
|
||||
// Default startup options.
|
||||
exports.options = {
|
||||
mode: "text",
|
||||
theme: "textmate",
|
||||
gutter: "false",
|
||||
fontSize: "12px",
|
||||
softWrap: "off",
|
||||
showPrintMargin: "false",
|
||||
useSoftTabs: "true",
|
||||
showInvisibles: "true"
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,367 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck (julian.viereck@gmail.com)
|
||||
* Harutyun Amirjanyan (harutyun@c9.io)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
|
||||
var screenToTextBlockCoordinates = function(pageX, pageY) {
|
||||
var canvasPos = this.scroller.getBoundingClientRect();
|
||||
|
||||
var col = Math.floor(
|
||||
(pageX + this.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft()) / this.characterWidth
|
||||
);
|
||||
var row = Math.floor(
|
||||
(pageY + this.scrollTop - canvasPos.top - dom.getPageScrollTop()) / this.lineHeight
|
||||
);
|
||||
|
||||
return this.session.screenToDocumentPosition(row, col);
|
||||
};
|
||||
|
||||
var HashHandler = require("./hash_handler").HashHandler;
|
||||
exports.handler = new HashHandler();
|
||||
|
||||
var initialized = false;
|
||||
exports.handler.attach = function(editor) {
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
dom.importCssString('\
|
||||
.emacs-mode .ace_cursor{\
|
||||
border: 2px rgba(50,250,50,0.8) solid!important;\
|
||||
-moz-box-sizing: border-box!important;\
|
||||
box-sizing: border-box!important;\
|
||||
background-color: rgba(0,250,0,0.9);\
|
||||
opacity: 0.5;\
|
||||
}\
|
||||
.emacs-mode .ace_cursor.ace_hidden{\
|
||||
opacity: 1;\
|
||||
background-color: transparent;\
|
||||
}\
|
||||
.emacs-mode .ace_cursor.ace_overwrite {\
|
||||
opacity: 1;\
|
||||
background-color: transparent;\
|
||||
border-width: 0 0 2px 2px !important;\
|
||||
}\
|
||||
.emacs-mode .ace_text-layer {\
|
||||
z-index: 4\
|
||||
}\
|
||||
.emacs-mode .ace_cursor-layer {\
|
||||
z-index: 2\
|
||||
}', 'emacsMode'
|
||||
);
|
||||
}
|
||||
|
||||
editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates;
|
||||
editor.setStyle("emacs-mode");
|
||||
};
|
||||
|
||||
exports.handler.detach = function(editor) {
|
||||
delete editor.renderer.screenToTextCoordinates;
|
||||
editor.unsetStyle("emacs-mode");
|
||||
};
|
||||
|
||||
|
||||
var keys = require("../lib/keys").KEY_MODS;
|
||||
var eMods = {
|
||||
C: "ctrl", S: "shift", M: "alt"
|
||||
};
|
||||
["S-C-M", "S-C", "S-M", "C-M", "S", "C", "M"].forEach(function(c) {
|
||||
var hashId = 0;
|
||||
c.split("-").forEach(function(c){
|
||||
hashId = hashId | keys[eMods[c]];
|
||||
});
|
||||
eMods[hashId] = c.toLowerCase() + "-";
|
||||
});
|
||||
|
||||
exports.handler.bindKey = function(key, command) {
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
var ckb = this.commmandKeyBinding;
|
||||
key.split("|").forEach(function(keyPart) {
|
||||
keyPart = keyPart.toLowerCase();
|
||||
ckb[keyPart] = command;
|
||||
keyPart = keyPart.split(" ")[0];
|
||||
if (!ckb[keyPart])
|
||||
ckb[keyPart] = "null";
|
||||
}, this);
|
||||
};
|
||||
|
||||
|
||||
exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {
|
||||
if (hashId == -1) {
|
||||
if (data.count) {
|
||||
var str = Array(data.count + 1).join(key);
|
||||
data.count = null;
|
||||
return {command: "insertstring", args: str};
|
||||
}
|
||||
}
|
||||
|
||||
if (key == "\x00")
|
||||
return;
|
||||
|
||||
var modifier = eMods[hashId];
|
||||
if (modifier == "c-" || data.universalArgument) {
|
||||
var count = parseInt(key[key.length - 1]);
|
||||
if (count) {
|
||||
data.count = count;
|
||||
return {command: "null"};
|
||||
}
|
||||
}
|
||||
data.universalArgument = false;
|
||||
|
||||
if (modifier)
|
||||
key = modifier + key;
|
||||
|
||||
if (data.keyChain)
|
||||
key = data.keyChain += " " + key;
|
||||
|
||||
var command = this.commmandKeyBinding[key];
|
||||
data.keyChain = command == "null" ? key : "";
|
||||
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
if (command == "null")
|
||||
return {command: "null"};
|
||||
|
||||
if (command == "universalArgument") {
|
||||
data.universalArgument = true;
|
||||
return {command: "null"};
|
||||
}
|
||||
|
||||
if (typeof command != "string") {
|
||||
var args = command.args;
|
||||
command = command.command;
|
||||
}
|
||||
|
||||
if (typeof command == "string") {
|
||||
command = this.commands[command] || data.editor.commands.commands[command];
|
||||
}
|
||||
|
||||
if (!command.readonly && !command.isYank)
|
||||
data.lastCommand = null;
|
||||
|
||||
if (data.count) {
|
||||
var count = data.count;
|
||||
data.count = 0;
|
||||
return {
|
||||
args: args,
|
||||
command: {
|
||||
exec: function(editor, args) {
|
||||
for (var i = 0; i < count; i++)
|
||||
command.exec(editor, args);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {command: command, args: args};
|
||||
};
|
||||
|
||||
exports.emacsKeys = {
|
||||
// movement
|
||||
"Up|C-p" : "golineup",
|
||||
"Down|C-n" : "golinedown",
|
||||
"Left|C-b" : "gotoleft",
|
||||
"Right|C-f" : "gotoright",
|
||||
"C-Left|M-b" : "gotowordleft",
|
||||
"C-Right|M-f" : "gotowordright",
|
||||
"Home|C-a" : "gotolinestart",
|
||||
"End|C-e" : "gotolineend",
|
||||
"C-Home|S-M-,": "gotostart",
|
||||
"C-End|S-M-." : "gotoend",
|
||||
|
||||
// selection
|
||||
"S-Up|S-C-p" : "selectup",
|
||||
"S-Down|S-C-n" : "selectdown",
|
||||
"S-Left|S-C-b" : "selectleft",
|
||||
"S-Right|S-C-f" : "selectright",
|
||||
"S-C-Left|S-M-b" : "selectwordleft",
|
||||
"S-C-Right|S-M-f" : "selectwordright",
|
||||
"S-Home|S-C-a" : "selecttolinestart",
|
||||
"S-End|S-C-e" : "selecttolineend",
|
||||
"S-C-Home" : "selecttostart",
|
||||
"S-C-End" : "selecttoend",
|
||||
|
||||
"C-l|M-s" : "centerselection",
|
||||
"M-g": "gotoline",
|
||||
"C-x C-p": "selectall",
|
||||
|
||||
// todo fix these
|
||||
"C-Down": "gotopagedown",
|
||||
"C-Up": "gotopageup",
|
||||
"PageDown|C-v": "gotopagedown",
|
||||
"PageUp|M-v": "gotopageup",
|
||||
"S-C-Down": "selectpagedown",
|
||||
"S-C-Up": "selectpageup",
|
||||
"C-s": "findnext",
|
||||
"C-r": "findprevious",
|
||||
"M-C-s": "findnext",
|
||||
"M-C-r": "findprevious",
|
||||
"S-M-5": "replace",
|
||||
|
||||
// basic editing
|
||||
"Backspace": "backspace",
|
||||
"Delete|C-d": "del",
|
||||
"Return|C-m": {command: "insertstring", args: "\n"}, // "newline"
|
||||
"C-o": "splitline",
|
||||
|
||||
"M-d|C-Delete": {command: "killWord", args: "right"},
|
||||
"C-Backspace|M-Backspace|M-Delete": {command: "killWord", args: "left"},
|
||||
"C-k": "killLine",
|
||||
|
||||
"C-y|S-Delete": "yank",
|
||||
"M-y": "yankRotate",
|
||||
"C-g": "keyboardQuit",
|
||||
|
||||
"C-w": "killRegion",
|
||||
"M-w": "killRingSave",
|
||||
|
||||
"C-Space": "setMark",
|
||||
"C-x C-x": "exchangePointAndMark",
|
||||
|
||||
"C-t": "transposeletters",
|
||||
|
||||
"M-u": "touppercase",
|
||||
"M-l": "tolowercase",
|
||||
"M-/": "autocomplete",
|
||||
"C-u": "universalArgument",
|
||||
"M-;": "togglecomment",
|
||||
|
||||
"C-/|C-x u|S-C--|C-z": "undo",
|
||||
"S-C-/|S-C-x u|C--|S-C-z": "redo", //infinite undo?
|
||||
// vertical editing
|
||||
"C-x r": "selectRectangularRegion"
|
||||
|
||||
// todo
|
||||
// "M-x" "C-x C-t" "M-t" "M-c" "F11" "C-M- "M-q"
|
||||
};
|
||||
|
||||
|
||||
exports.handler.bindKeys(exports.emacsKeys);
|
||||
|
||||
exports.handler.addCommands({
|
||||
selectRectangularRegion: function(editor) {
|
||||
editor.multiSelect.toggleBlockSelection();
|
||||
},
|
||||
setMark: function() {
|
||||
},
|
||||
exchangePointAndMark: {
|
||||
exec: function(editor) {
|
||||
var range = editor.selection.getRange();
|
||||
editor.selection.setSelectionRange(range, !editor.selection.isBackwards());
|
||||
},
|
||||
readonly: true,
|
||||
multiselectAction: "forEach"
|
||||
},
|
||||
killWord: {
|
||||
exec: function(editor, dir) {
|
||||
editor.clearSelection();
|
||||
if (dir == "left")
|
||||
editor.selection.selectWordLeft();
|
||||
else
|
||||
editor.selection.selectWordRight();
|
||||
|
||||
var range = editor.getSelectionRange();
|
||||
var text = editor.session.getTextRange(range);
|
||||
exports.killRing.add(text);
|
||||
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
},
|
||||
multiselectAction: "forEach"
|
||||
},
|
||||
killLine: function(editor) {
|
||||
editor.selection.selectLine();
|
||||
var range = editor.getSelectionRange();
|
||||
var text = editor.session.getTextRange(range);
|
||||
exports.killRing.add(text);
|
||||
|
||||
editor.session.remove(range);
|
||||
editor.clearSelection();
|
||||
},
|
||||
yank: function(editor) {
|
||||
editor.onPaste(exports.killRing.get());
|
||||
editor.keyBinding.$data.lastCommand = "yank";
|
||||
},
|
||||
yankRotate: function(editor) {
|
||||
if (editor.keyBinding.$data.lastCommand != "yank")
|
||||
return;
|
||||
|
||||
editor.undo();
|
||||
editor.onPaste(exports.killRing.rotate());
|
||||
editor.keyBinding.$data.lastCommand = "yank";
|
||||
},
|
||||
killRegion: function(editor) {
|
||||
exports.killRing.add(editor.getCopyText());
|
||||
editor.cut();
|
||||
},
|
||||
killRingSave: function(editor) {
|
||||
exports.killRing.add(editor.getCopyText());
|
||||
}
|
||||
});
|
||||
|
||||
var commands = exports.handler.commands;
|
||||
commands.yank.isYank = true;
|
||||
commands.yankRotate.isYank = true;
|
||||
|
||||
exports.killRing = {
|
||||
$data: [],
|
||||
add: function(str) {
|
||||
str && this.$data.push(str);
|
||||
if (this.$data.length > 30)
|
||||
this.$data.shift();
|
||||
},
|
||||
get: function() {
|
||||
return this.$data[this.$data.length - 1] || "";
|
||||
},
|
||||
pop: function() {
|
||||
if (this.$data.length > 1)
|
||||
this.$data.pop();
|
||||
return this.get();
|
||||
},
|
||||
rotate: function() {
|
||||
this.$data.unshift(this.$data.pop());
|
||||
return this.get();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
@@ -0,0 +1,170 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck (julian.viereck@gmail.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keyUtil = require("../lib/keys");
|
||||
|
||||
function HashHandler(config, platform) {
|
||||
this.platform = platform;
|
||||
this.commands = {};
|
||||
this.commmandKeyBinding = {};
|
||||
|
||||
this.addCommands(config);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.addCommand = function(command) {
|
||||
if (this.commands[command.name])
|
||||
this.removeCommand(command);
|
||||
|
||||
this.commands[command.name] = command;
|
||||
|
||||
if (command.bindKey)
|
||||
this._buildKeyHash(command);
|
||||
};
|
||||
|
||||
this.removeCommand = function(command) {
|
||||
var name = (typeof command === 'string' ? command : command.name);
|
||||
command = this.commands[name];
|
||||
delete this.commands[name];
|
||||
|
||||
// exhaustive search is brute force but since removeCommand is
|
||||
// not a performance critical operation this should be OK
|
||||
var ckb = this.commmandKeyBinding;
|
||||
for (var hashId in ckb) {
|
||||
for (var key in ckb[hashId]) {
|
||||
if (ckb[hashId][key] == command)
|
||||
delete ckb[hashId][key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.bindKey = function(key, command) {
|
||||
if(!key)
|
||||
return;
|
||||
if (typeof command == "function") {
|
||||
this.addCommand({exec: command, bindKey: key, name: key});
|
||||
return;
|
||||
}
|
||||
|
||||
var ckb = this.commmandKeyBinding;
|
||||
key.split("|").forEach(function(keyPart) {
|
||||
var binding = this.parseKeys(keyPart, command);
|
||||
var hashId = binding.hashId;
|
||||
(ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command;
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.addCommands = function(commands) {
|
||||
commands && Object.keys(commands).forEach(function(name) {
|
||||
var command = commands[name];
|
||||
if (typeof command === "string")
|
||||
return this.bindKey(command, name);
|
||||
|
||||
if (typeof command === "function")
|
||||
command = { exec: command };
|
||||
|
||||
if (!command.name)
|
||||
command.name = name;
|
||||
|
||||
this.addCommand(command);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.removeCommands = function(commands) {
|
||||
Object.keys(commands).forEach(function(name) {
|
||||
this.removeCommand(commands[name]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this.bindKeys = function(keyList) {
|
||||
Object.keys(keyList).forEach(function(key) {
|
||||
this.bindKey(key, keyList[key]);
|
||||
}, this);
|
||||
};
|
||||
|
||||
this._buildKeyHash = function(command) {
|
||||
var binding = command.bindKey;
|
||||
if (!binding)
|
||||
return;
|
||||
|
||||
var key = typeof binding == "string" ? binding: binding[this.platform];
|
||||
this.bindKey(key, command);
|
||||
};
|
||||
|
||||
this.parseKeys = function(keys) {
|
||||
var key;
|
||||
var hashId = 0;
|
||||
var parts = keys.toLowerCase().trim().split(/\s*\-\s*/);
|
||||
|
||||
for (var i = 0, l = parts.length; i < l; i++) {
|
||||
if (keyUtil.KEY_MODS[parts[i]])
|
||||
hashId = hashId | keyUtil.KEY_MODS[parts[i]];
|
||||
else
|
||||
key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
|
||||
}
|
||||
|
||||
if (parts[0] == "text" && parts.length == 2) {
|
||||
hashId = -1;
|
||||
key = parts[1];
|
||||
}
|
||||
|
||||
return {
|
||||
key: key,
|
||||
hashId: hashId
|
||||
};
|
||||
};
|
||||
|
||||
this.findKeyCommand = function findKeyCommand(hashId, keyString) {
|
||||
var ckbr = this.commmandKeyBinding;
|
||||
return ckbr[hashId] && ckbr[hashId][keyString.toLowerCase()];
|
||||
};
|
||||
|
||||
this.handleKeyboard = function(data, hashId, keyString, keyCode) {
|
||||
return {
|
||||
command: this.findKeyCommand(hashId, keyString)
|
||||
};
|
||||
};
|
||||
|
||||
}).call(HashHandler.prototype)
|
||||
|
||||
exports.HashHandler = HashHandler;
|
||||
});
|
||||
@@ -0,0 +1,143 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
* Harutyun Amirjanyan <amirjanyan@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keyUtil = require("../lib/keys");
|
||||
var event = require("../lib/event");
|
||||
|
||||
var KeyBinding = function(editor) {
|
||||
this.$editor = editor;
|
||||
this.$data = { };
|
||||
this.$handlers = [];
|
||||
this.setDefaultHandler(editor.commands);
|
||||
};
|
||||
|
||||
(function() {
|
||||
this.setDefaultHandler = function(kb) {
|
||||
this.removeKeyboardHandler(this.$defaultHandler);
|
||||
this.$defaultHandler = kb;
|
||||
this.addKeyboardHandler(kb, 0);
|
||||
this.$data = {editor: this.$editor};
|
||||
};
|
||||
|
||||
this.setKeyboardHandler = function(kb) {
|
||||
if (this.$handlers[this.$handlers.length - 1] == kb)
|
||||
return;
|
||||
|
||||
while (this.$handlers[1])
|
||||
this.removeKeyboardHandler(this.$handlers[1]);
|
||||
|
||||
this.addKeyboardHandler(kb, 1);
|
||||
};
|
||||
|
||||
this.addKeyboardHandler = function(kb, pos) {
|
||||
if (!kb)
|
||||
return;
|
||||
var i = this.$handlers.indexOf(kb);
|
||||
if (i != -1)
|
||||
this.$handlers.splice(i, 1);
|
||||
|
||||
if (pos == undefined)
|
||||
this.$handlers.push(kb);
|
||||
else
|
||||
this.$handlers.splice(pos, 0, kb);
|
||||
|
||||
if (i == -1 && kb.attach)
|
||||
kb.attach(this.$editor);
|
||||
};
|
||||
|
||||
this.removeKeyboardHandler = function(kb) {
|
||||
var i = this.$handlers.indexOf(kb);
|
||||
if (i == -1)
|
||||
return false;
|
||||
this.$handlers.splice(i, 1);
|
||||
kb.detach && kb.detach(this.$editor);
|
||||
return true;
|
||||
};
|
||||
|
||||
this.getKeyboardHandler = function() {
|
||||
return this.$handlers[this.$handlers.length - 1];
|
||||
};
|
||||
|
||||
this.$callKeyboardHandlers = function (hashId, keyString, keyCode, e) {
|
||||
var toExecute;
|
||||
for (var i = this.$handlers.length; i--;) {
|
||||
toExecute = this.$handlers[i].handleKeyboard(
|
||||
this.$data, hashId, keyString, keyCode, e
|
||||
);
|
||||
if (toExecute && toExecute.command)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!toExecute || !toExecute.command)
|
||||
return false;
|
||||
|
||||
var success = false;
|
||||
var commands = this.$editor.commands;
|
||||
|
||||
// allow keyboardHandler to consume keys
|
||||
if (toExecute.command != "null")
|
||||
success = commands.exec(toExecute.command, this.$editor, toExecute.args, e);
|
||||
else
|
||||
success = toExecute.passEvent != true;
|
||||
|
||||
// do not stop input events to not break repeating
|
||||
if (success && e && hashId != -1)
|
||||
event.stopEvent(e);
|
||||
|
||||
return success;
|
||||
};
|
||||
|
||||
this.onCommandKey = function(e, hashId, keyCode) {
|
||||
var keyString = keyUtil.keyCodeToString(keyCode);
|
||||
this.$callKeyboardHandlers(hashId, keyString, keyCode, e);
|
||||
};
|
||||
|
||||
this.onTextInput = function(text) {
|
||||
var success = this.$callKeyboardHandlers(-1, text);
|
||||
if (!success)
|
||||
this.$editor.commands.exec("insertstring", this.$editor, text);
|
||||
};
|
||||
|
||||
}).call(KeyBinding.prototype);
|
||||
|
||||
exports.KeyBinding = KeyBinding;
|
||||
});
|
||||
@@ -0,0 +1,257 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Skywriter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Viereck (julian.viereck@gmail.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
// If you're developing a new keymapping and want to get an idea what's going
|
||||
// on, then enable debugging.
|
||||
var DEBUG = false;
|
||||
|
||||
function StateHandler(keymapping) {
|
||||
this.keymapping = this.$buildKeymappingRegex(keymapping);
|
||||
}
|
||||
|
||||
StateHandler.prototype = {
|
||||
/*
|
||||
* Build the RegExp from the keymapping as RegExp can't stored directly
|
||||
* in the metadata JSON and as the RegExp used to match the keys/buffer
|
||||
* need to be adapted.
|
||||
*/
|
||||
$buildKeymappingRegex: function(keymapping) {
|
||||
for (var state in keymapping) {
|
||||
this.$buildBindingsRegex(keymapping[state]);
|
||||
}
|
||||
return keymapping;
|
||||
},
|
||||
|
||||
$buildBindingsRegex: function(bindings) {
|
||||
// Escape a given Regex string.
|
||||
bindings.forEach(function(binding) {
|
||||
if (binding.key) {
|
||||
binding.key = new RegExp('^' + binding.key + '$');
|
||||
} else if (Array.isArray(binding.regex)) {
|
||||
if (!('key' in binding))
|
||||
binding.key = new RegExp('^' + binding.regex[1] + '$');
|
||||
binding.regex = new RegExp(binding.regex.join('') + '$');
|
||||
} else if (binding.regex) {
|
||||
binding.regex = new RegExp(binding.regex + '$');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
$composeBuffer: function(data, hashId, key, e) {
|
||||
// Initialize the data object.
|
||||
if (data.state == null || data.buffer == null) {
|
||||
data.state = "start";
|
||||
data.buffer = "";
|
||||
}
|
||||
|
||||
var keyArray = [];
|
||||
if (hashId & 1) keyArray.push("ctrl");
|
||||
if (hashId & 8) keyArray.push("command");
|
||||
if (hashId & 2) keyArray.push("option");
|
||||
if (hashId & 4) keyArray.push("shift");
|
||||
if (key) keyArray.push(key);
|
||||
|
||||
var symbolicName = keyArray.join("-");
|
||||
var bufferToUse = data.buffer + symbolicName;
|
||||
|
||||
// Don't add the symbolic name to the key buffer if the alt_ key is
|
||||
// part of the symbolic name. If it starts with alt_, this means
|
||||
// that the user hit an alt keycombo and there will be a single,
|
||||
// new character detected after this event, which then will be
|
||||
// added to the buffer (e.g. alt_j will result in ∆).
|
||||
//
|
||||
// We test for 2 and not for & 2 as we only want to exclude the case where
|
||||
// the option key is pressed alone.
|
||||
if (hashId != 2) {
|
||||
data.buffer = bufferToUse;
|
||||
}
|
||||
|
||||
var bufferObj = {
|
||||
bufferToUse: bufferToUse,
|
||||
symbolicName: symbolicName
|
||||
};
|
||||
|
||||
if (e) {
|
||||
bufferObj.keyIdentifier = e.keyIdentifier
|
||||
}
|
||||
|
||||
return bufferObj;
|
||||
},
|
||||
|
||||
$find: function(data, buffer, symbolicName, hashId, key, keyIdentifier) {
|
||||
// Holds the command to execute and the args if a command matched.
|
||||
var result = {};
|
||||
|
||||
// Loop over all the bindings of the keymap until a match is found.
|
||||
this.keymapping[data.state].some(function(binding) {
|
||||
var match;
|
||||
|
||||
// Check if the key matches.
|
||||
if (binding.key && !binding.key.test(symbolicName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the regex matches.
|
||||
if (binding.regex && !(match = binding.regex.exec(buffer))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the match function matches.
|
||||
if (binding.match && !binding.match(buffer, hashId, key, symbolicName, keyIdentifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for disallowed matches.
|
||||
if (binding.disallowMatches) {
|
||||
for (var i = 0; i < binding.disallowMatches.length; i++) {
|
||||
if (!!match[binding.disallowMatches[i]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a command to execute, then figure out the
|
||||
// command and the arguments.
|
||||
if (binding.exec) {
|
||||
result.command = binding.exec;
|
||||
|
||||
// Build the arguments.
|
||||
if (binding.params) {
|
||||
var value;
|
||||
result.args = {};
|
||||
binding.params.forEach(function(param) {
|
||||
if (param.match != null && match != null) {
|
||||
value = match[param.match] || param.defaultValue;
|
||||
} else {
|
||||
value = param.defaultValue;
|
||||
}
|
||||
|
||||
if (param.type === 'number') {
|
||||
value = parseInt(value);
|
||||
}
|
||||
|
||||
result.args[param.name] = value;
|
||||
});
|
||||
}
|
||||
data.buffer = "";
|
||||
}
|
||||
|
||||
// Handle the 'then' property.
|
||||
if (binding.then) {
|
||||
data.state = binding.then;
|
||||
data.buffer = "";
|
||||
}
|
||||
|
||||
// If no command is set, then execute the "null" fake command.
|
||||
if (result.command == null) {
|
||||
result.command = "null";
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
console.log("KeyboardStateMapper#find", binding);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (result.command) {
|
||||
return result;
|
||||
} else {
|
||||
data.buffer = "";
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* This function is called by keyBinding.
|
||||
*/
|
||||
handleKeyboard: function(data, hashId, key, keyCode, e) {
|
||||
if (hashId == -1)
|
||||
hashId = 0
|
||||
// If we pressed any command key but no other key, then ignore the input.
|
||||
// Otherwise "shift-" is added to the buffer, and later on "shift-g"
|
||||
// which results in "shift-shift-g" which doesn't make sense.
|
||||
if (hashId != 0 && (key == "" || key == String.fromCharCode(0))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Compute the current value of the keyboard input buffer.
|
||||
var r = this.$composeBuffer(data, hashId, key, e);
|
||||
var buffer = r.bufferToUse;
|
||||
var symbolicName = r.symbolicName;
|
||||
var keyId = r.keyIdentifier;
|
||||
|
||||
r = this.$find(data, buffer, symbolicName, hashId, key, keyId);
|
||||
if (DEBUG) {
|
||||
console.log("KeyboardStateMapper#match", buffer, symbolicName, r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a useful matching function and therefore is defined here so that
|
||||
* users of KeyboardStateMapper can use it.
|
||||
*
|
||||
* @return boolean
|
||||
* If no command key (Command|Option|Shift|Ctrl) is pressed, it
|
||||
* returns true. If the only the Shift key is pressed + a character
|
||||
* true is returned as well. Otherwise, false is returned.
|
||||
* Summing up, the function returns true whenever the user typed
|
||||
* a normal character on the keyboard and no shortcut.
|
||||
*/
|
||||
exports.matchCharacterOnly = function(buffer, hashId, key, symbolicName) {
|
||||
// If no command keys are pressed, then catch the input.
|
||||
if (hashId == 0) {
|
||||
return true;
|
||||
}
|
||||
// If only the shift key is pressed and a character key, then
|
||||
// catch that input as well.
|
||||
else if ((hashId == 4) && key.length == 1) {
|
||||
return true;
|
||||
}
|
||||
// Otherwise, we let the input got through.
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
exports.StateHandler = StateHandler;
|
||||
});
|
||||
@@ -0,0 +1,315 @@
|
||||
/* vim:ts=4:sts=4:sw=4:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Mihai Sucan <mihai DOT sucan AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var event = require("../lib/event");
|
||||
var useragent = require("../lib/useragent");
|
||||
var dom = require("../lib/dom");
|
||||
|
||||
var TextInput = function(parentNode, host) {
|
||||
var text = dom.createElement("textarea");
|
||||
/*/ debug
|
||||
text.style.opacity = 1
|
||||
text.style.background = "rgba(0, 250, 0, 0.3)"
|
||||
text.style.outline = "rgba(0, 250, 0, 0.8) solid 1px"
|
||||
text.style.outlineOffset = "3px"
|
||||
/**/
|
||||
if (useragent.isTouchPad)
|
||||
text.setAttribute("x-palm-disable-auto-cap", true);
|
||||
|
||||
text.setAttribute("wrap", "off");
|
||||
|
||||
text.style.top = "-2em";
|
||||
parentNode.insertBefore(text, parentNode.firstChild);
|
||||
|
||||
var PLACEHOLDER = useragent.isIE ? "\x01" : "\x01";
|
||||
sendText();
|
||||
|
||||
var inCompostion = false;
|
||||
var copied = false;
|
||||
var pasted = false;
|
||||
var tempStyle = '';
|
||||
|
||||
function reset(full) {
|
||||
try {
|
||||
if (full) {
|
||||
text.value = PLACEHOLDER;
|
||||
text.selectionStart = 0;
|
||||
text.selectionEnd = 1;
|
||||
} else
|
||||
text.select();
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function sendText(valueToSend) {
|
||||
if (!copied) {
|
||||
var value = valueToSend || text.value;
|
||||
if (value) {
|
||||
if (value.length > 1) {
|
||||
if (value.charAt(0) == PLACEHOLDER)
|
||||
value = value.substr(1);
|
||||
else if (value.charAt(value.length - 1) == PLACEHOLDER)
|
||||
value = value.slice(0, -1);
|
||||
}
|
||||
|
||||
if (value && value != PLACEHOLDER) {
|
||||
if (pasted)
|
||||
host.onPaste(value);
|
||||
else
|
||||
host.onTextInput(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copied = false;
|
||||
pasted = false;
|
||||
|
||||
// Safari doesn't fire copy events if no text is selected
|
||||
reset(true);
|
||||
}
|
||||
|
||||
var onTextInput = function(e) {
|
||||
if (!inCompostion)
|
||||
sendText(e.data);
|
||||
setTimeout(function () {
|
||||
if (!inCompostion)
|
||||
reset(true);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var onPropertyChange = function(e) {
|
||||
setTimeout(function() {
|
||||
if (!inCompostion)
|
||||
sendText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var onCompositionStart = function(e) {
|
||||
inCompostion = true;
|
||||
host.onCompositionStart();
|
||||
setTimeout(onCompositionUpdate, 0);
|
||||
};
|
||||
|
||||
var onCompositionUpdate = function() {
|
||||
if (!inCompostion) return;
|
||||
host.onCompositionUpdate(text.value);
|
||||
};
|
||||
|
||||
var onCompositionEnd = function(e) {
|
||||
inCompostion = false;
|
||||
host.onCompositionEnd();
|
||||
};
|
||||
|
||||
var onCopy = function(e) {
|
||||
copied = true;
|
||||
var copyText = host.getCopyText();
|
||||
if(copyText)
|
||||
text.value = copyText;
|
||||
else
|
||||
e.preventDefault();
|
||||
reset();
|
||||
setTimeout(function () {
|
||||
sendText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var onCut = function(e) {
|
||||
copied = true;
|
||||
var copyText = host.getCopyText();
|
||||
if(copyText) {
|
||||
text.value = copyText;
|
||||
host.onCut();
|
||||
} else
|
||||
e.preventDefault();
|
||||
reset();
|
||||
setTimeout(function () {
|
||||
sendText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
|
||||
event.addListener(text, "input", useragent.isIE ? onPropertyChange : onTextInput);
|
||||
|
||||
event.addListener(text, "paste", function(e) {
|
||||
// Mark that the next input text comes from past.
|
||||
pasted = true;
|
||||
// Some browsers support the event.clipboardData API. Use this to get
|
||||
// the pasted content which increases speed if pasting a lot of lines.
|
||||
if (e.clipboardData && e.clipboardData.getData) {
|
||||
sendText(e.clipboardData.getData("text/plain"));
|
||||
e.preventDefault();
|
||||
}
|
||||
else {
|
||||
// If a browser doesn't support any of the things above, use the regular
|
||||
// method to detect the pasted input.
|
||||
onPropertyChange();
|
||||
}
|
||||
});
|
||||
|
||||
if ("onbeforecopy" in text && typeof clipboardData !== "undefined") {
|
||||
event.addListener(text, "beforecopy", function(e) {
|
||||
if (tempStyle)
|
||||
return; // without this text is copied when contextmenu is shown
|
||||
var copyText = host.getCopyText();
|
||||
if (copyText)
|
||||
clipboardData.setData("Text", copyText);
|
||||
else
|
||||
e.preventDefault();
|
||||
});
|
||||
event.addListener(parentNode, "keydown", function(e) {
|
||||
if (e.ctrlKey && e.keyCode == 88) {
|
||||
var copyText = host.getCopyText();
|
||||
if (copyText) {
|
||||
clipboardData.setData("Text", copyText);
|
||||
host.onCut();
|
||||
}
|
||||
event.preventDefault(e);
|
||||
}
|
||||
});
|
||||
event.addListener(text, "cut", onCut); // for ie9 context menu
|
||||
}
|
||||
else if (useragent.isOpera) {
|
||||
event.addListener(parentNode, "keydown", function(e) {
|
||||
if ((useragent.isMac && !e.metaKey) || !e.ctrlKey)
|
||||
return;
|
||||
|
||||
if ((e.keyCode == 88 || e.keyCode == 67)) {
|
||||
var copyText = host.getCopyText();
|
||||
if (copyText) {
|
||||
text.value = copyText;
|
||||
text.select();
|
||||
if (e.keyCode == 88)
|
||||
host.onCut();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
event.addListener(text, "copy", onCopy);
|
||||
event.addListener(text, "cut", onCut);
|
||||
}
|
||||
|
||||
event.addListener(text, "compositionstart", onCompositionStart);
|
||||
if (useragent.isGecko) {
|
||||
event.addListener(text, "text", onCompositionUpdate);
|
||||
}
|
||||
if (useragent.isWebKit) {
|
||||
event.addListener(text, "keyup", onCompositionUpdate);
|
||||
}
|
||||
event.addListener(text, "compositionend", onCompositionEnd);
|
||||
|
||||
event.addListener(text, "blur", function() {
|
||||
host.onBlur();
|
||||
});
|
||||
|
||||
event.addListener(text, "focus", function() {
|
||||
host.onFocus();
|
||||
reset();
|
||||
});
|
||||
|
||||
this.focus = function() {
|
||||
reset();
|
||||
text.focus();
|
||||
};
|
||||
|
||||
this.blur = function() {
|
||||
text.blur();
|
||||
};
|
||||
|
||||
function isFocused() {
|
||||
return document.activeElement === text;
|
||||
}
|
||||
this.isFocused = isFocused;
|
||||
|
||||
this.getElement = function() {
|
||||
return text;
|
||||
};
|
||||
|
||||
this.onContextMenu = function(e) {
|
||||
if (!tempStyle)
|
||||
tempStyle = text.style.cssText;
|
||||
|
||||
text.style.cssText =
|
||||
"position:fixed; z-index:100000;" + //"background:rgba(250, 0, 0, 0.3); opacity:1;" +
|
||||
"left:" + (e.clientX - 2) + "px; top:" + (e.clientY - 2) + "px;";
|
||||
|
||||
if (host.selection.isEmpty())
|
||||
text.value = "";
|
||||
|
||||
if (e.type != "mousedown")
|
||||
return;
|
||||
|
||||
if (host.renderer.$keepTextAreaAtCursor)
|
||||
host.renderer.$keepTextAreaAtCursor = null;
|
||||
|
||||
// on windows context menu is opened after mouseup
|
||||
if (useragent.isGecko && useragent.isWin)
|
||||
event.capture(host.container, function(e) {
|
||||
text.style.left = e.clientX - 2 + "px";
|
||||
text.style.top = e.clientY - 2 + "px";
|
||||
}, onContextMenuClose);
|
||||
};
|
||||
|
||||
function onContextMenuClose() {
|
||||
setTimeout(function () {
|
||||
if (tempStyle) {
|
||||
text.style.cssText = tempStyle;
|
||||
tempStyle = '';
|
||||
}
|
||||
sendText();
|
||||
if (host.renderer.$keepTextAreaAtCursor == null) {
|
||||
host.renderer.$keepTextAreaAtCursor = true;
|
||||
host.renderer.$moveTextAreaToCursor();
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
this.onContextMenuClose = onContextMenuClose;
|
||||
|
||||
// firefox fires contextmenu event after opening it
|
||||
if (!useragent.isGecko)
|
||||
event.addListener(text, "contextmenu", function(e) {
|
||||
host.textInput.onContextMenu(e);
|
||||
onContextMenuClose()
|
||||
});
|
||||
};
|
||||
|
||||
exports.TextInput = TextInput;
|
||||
});
|
||||
@@ -0,0 +1,122 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var keyUtil = require("../lib/keys");
|
||||
var cmds = require("./vim/commands");
|
||||
var coreCommands = cmds.coreCommands;
|
||||
var util = require("./vim/maps/util");
|
||||
|
||||
var startCommands = {
|
||||
"i": {
|
||||
command: coreCommands.start
|
||||
},
|
||||
"I": {
|
||||
command: coreCommands.startBeginning
|
||||
},
|
||||
"a": {
|
||||
command: coreCommands.append
|
||||
},
|
||||
"A": {
|
||||
command: coreCommands.appendEnd
|
||||
},
|
||||
"ctrl-f": {
|
||||
command: "gotopagedown"
|
||||
},
|
||||
"ctrl-b": {
|
||||
command: "gotopageup"
|
||||
},
|
||||
};
|
||||
|
||||
exports.handler = {
|
||||
handleKeyboard: function(data, hashId, key, keyCode, e) {
|
||||
// ignore command keys (shift, ctrl etc.)
|
||||
if (hashId != 0 && (key == "" || key == "\x00"))
|
||||
return null;
|
||||
|
||||
if (hashId == 1)
|
||||
key = "ctrl-" + key;
|
||||
|
||||
if (data.state == "start") {
|
||||
if (hashId == -1 || hashId == 1) {
|
||||
if (cmds.inputBuffer.idle && startCommands[key])
|
||||
return startCommands[key];
|
||||
|
||||
return { command: {
|
||||
exec: function(editor) {cmds.inputBuffer.push(editor, key);}
|
||||
} };
|
||||
} // wait for input
|
||||
else if (key.length == 1 && (hashId == 0 || hashId == 4)) { //no modifier || shift
|
||||
return {command: "null", passEvent: true};
|
||||
} else if (key == "esc") {
|
||||
return {command: coreCommands.stop};
|
||||
}
|
||||
} else {
|
||||
if (key == "esc" || key == "ctrl-[") {
|
||||
data.state = "start";
|
||||
return {command: coreCommands.stop};
|
||||
} else if (key == "ctrl-w") {
|
||||
return {command: "removewordleft"};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
attach: function(editor) {
|
||||
editor.on("click", exports.onCursorMove);
|
||||
if (util.currentMode !== "insert")
|
||||
cmds.coreCommands.stop.exec(editor);
|
||||
},
|
||||
|
||||
detach: function(editor) {
|
||||
editor.removeListener("click", exports.onCursorMove);
|
||||
util.noMode(editor);
|
||||
util.currentMode = "normal";
|
||||
},
|
||||
|
||||
actions: cmds.actions
|
||||
};
|
||||
|
||||
|
||||
exports.onCursorMove = function(e) {
|
||||
cmds.onCursorMove(e.editor, e);
|
||||
exports.onCursorMove.scheduled = false;
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,556 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
"never use strict";
|
||||
|
||||
var util = require("./maps/util");
|
||||
var motions = require("./maps/motions");
|
||||
var operators = require("./maps/operators");
|
||||
var alias = require("./maps/aliases");
|
||||
var registers = require("./registers");
|
||||
|
||||
var NUMBER = 1;
|
||||
var OPERATOR = 2;
|
||||
var MOTION = 3;
|
||||
var ACTION = 4;
|
||||
var HMARGIN = 8; // Minimum amount of line separation between margins;
|
||||
|
||||
var repeat = function repeat(fn, count, args) {
|
||||
while (0 < count--)
|
||||
fn.apply(this, args);
|
||||
};
|
||||
|
||||
var ensureScrollMargin = function(editor) {
|
||||
var renderer = editor.renderer;
|
||||
var pos = renderer.$cursorLayer.getPixelPosition();
|
||||
|
||||
var top = pos.top;
|
||||
|
||||
var margin = HMARGIN * renderer.layerConfig.lineHeight;
|
||||
if (2 * margin > renderer.$size.scrollerHeight)
|
||||
margin = renderer.$size.scrollerHeight / 2;
|
||||
|
||||
if (renderer.scrollTop > top - margin) {
|
||||
renderer.session.setScrollTop(top - margin);
|
||||
}
|
||||
|
||||
if (renderer.scrollTop + renderer.$size.scrollerHeight < top + margin + renderer.lineHeight) {
|
||||
renderer.session.setScrollTop(top + margin + renderer.lineHeight - renderer.$size.scrollerHeight);
|
||||
}
|
||||
};
|
||||
|
||||
var actions = exports.actions = {
|
||||
"z": {
|
||||
param: true,
|
||||
fn: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "z":
|
||||
editor.alignCursor(null, 0.5);
|
||||
break;
|
||||
case "t":
|
||||
editor.alignCursor(null, 0);
|
||||
break;
|
||||
case "b":
|
||||
editor.alignCursor(null, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"r": {
|
||||
param: true,
|
||||
fn: function(editor, range, count, param) {
|
||||
if (param && param.length) {
|
||||
repeat(function() { editor.insert(param); }, count || 1);
|
||||
editor.navigateLeft();
|
||||
}
|
||||
}
|
||||
},
|
||||
"R": {
|
||||
fn: function(editor, range, count, param) {
|
||||
util.insertMode(editor);
|
||||
editor.setOverwrite(true);
|
||||
}
|
||||
},
|
||||
"~": {
|
||||
fn: function(editor, range, count) {
|
||||
repeat(function() {
|
||||
var range = editor.selection.getRange();
|
||||
if (range.isEmpty())
|
||||
range.end.column++;
|
||||
var text = editor.session.getTextRange(range);
|
||||
var toggled = text.toUpperCase();
|
||||
if (toggled == text)
|
||||
editor.navigateRight();
|
||||
else
|
||||
editor.session.replace(range, toggled);
|
||||
}, count || 1);
|
||||
}
|
||||
},
|
||||
"*": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectWord();
|
||||
editor.findNext();
|
||||
ensureScrollMargin(editor);
|
||||
var r = editor.selection.getRange();
|
||||
editor.selection.setSelectionRange(r, true);
|
||||
}
|
||||
},
|
||||
"#": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectWord();
|
||||
editor.findPrevious();
|
||||
ensureScrollMargin(editor);
|
||||
var r = editor.selection.getRange();
|
||||
editor.selection.setSelectionRange(r, true);
|
||||
}
|
||||
},
|
||||
"n": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var options = editor.getLastSearchOptions();
|
||||
options.backwards = false;
|
||||
|
||||
editor.selection.moveCursorRight();
|
||||
editor.selection.clearSelection();
|
||||
editor.findNext(options);
|
||||
|
||||
ensureScrollMargin(editor);
|
||||
var r = editor.selection.getRange();
|
||||
r.end.row = r.start.row;
|
||||
r.end.column = r.start.column;
|
||||
editor.selection.setSelectionRange(r, true);
|
||||
}
|
||||
},
|
||||
"N": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var options = editor.getLastSearchOptions();
|
||||
options.backwards = true;
|
||||
|
||||
editor.findPrevious(options);
|
||||
ensureScrollMargin(editor);
|
||||
var r = editor.selection.getRange();
|
||||
r.end.row = r.start.row;
|
||||
r.end.column = r.start.column;
|
||||
editor.selection.setSelectionRange(r, true);
|
||||
}
|
||||
},
|
||||
"v": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectRight();
|
||||
util.visualMode(editor, false);
|
||||
},
|
||||
acceptsMotion: true
|
||||
},
|
||||
"V": {
|
||||
fn: function(editor, range, count, param) {
|
||||
//editor.selection.selectLine();
|
||||
//editor.selection.selectLeft();
|
||||
var row = editor.getCursorPosition().row;
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(row, 0);
|
||||
editor.selection.selectLineEnd();
|
||||
editor.selection.visualLineStart = row;
|
||||
|
||||
util.visualMode(editor, true);
|
||||
},
|
||||
acceptsMotion: true
|
||||
},
|
||||
"Y": {
|
||||
fn: function(editor, range, count, param) {
|
||||
util.copyLine(editor);
|
||||
}
|
||||
},
|
||||
"p": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var defaultReg = registers._default;
|
||||
|
||||
editor.setOverwrite(false);
|
||||
if (defaultReg.isLine) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lines = defaultReg.text.split("\n");
|
||||
editor.session.getDocument().insertLines(pos.row + 1, lines);
|
||||
editor.moveCursorTo(pos.row + 1, 0);
|
||||
}
|
||||
else {
|
||||
editor.navigateRight();
|
||||
editor.insert(defaultReg.text);
|
||||
editor.navigateLeft();
|
||||
}
|
||||
editor.setOverwrite(true);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"P": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var defaultReg = registers._default;
|
||||
editor.setOverwrite(false);
|
||||
|
||||
if (defaultReg.isLine) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lines = defaultReg.text.split("\n");
|
||||
editor.session.getDocument().insertLines(pos.row, lines);
|
||||
editor.moveCursorTo(pos.row, 0);
|
||||
}
|
||||
else {
|
||||
editor.insert(defaultReg.text);
|
||||
}
|
||||
editor.setOverwrite(true);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"J": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var session = editor.session;
|
||||
range = editor.getSelectionRange();
|
||||
var pos = {row: range.start.row, column: range.start.column};
|
||||
count = count || range.end.row - range.start.row;
|
||||
var maxRow = Math.min(pos.row + (count || 1), session.getLength() - 1);
|
||||
|
||||
range.start.column = session.getLine(pos.row).length;
|
||||
range.end.column = session.getLine(maxRow).length;
|
||||
range.end.row = maxRow;
|
||||
|
||||
var text = "";
|
||||
for (var i = pos.row; i < maxRow; i++) {
|
||||
var nextLine = session.getLine(i + 1);
|
||||
text += " " + /^\s*(.*)$/.exec(nextLine)[1] || "";
|
||||
}
|
||||
|
||||
session.replace(range, text);
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.undo();
|
||||
}
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"ctrl-r": {
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.redo();
|
||||
}
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
":": {
|
||||
fn: function(editor, range, count, param) {
|
||||
// not implemented
|
||||
}
|
||||
},
|
||||
"/": {
|
||||
fn: function(editor, range, count, param) {
|
||||
// not implemented
|
||||
}
|
||||
},
|
||||
"?": {
|
||||
fn: function(editor, range, count, param) {
|
||||
// not implemented
|
||||
}
|
||||
},
|
||||
".": {
|
||||
fn: function(editor, range, count, param) {
|
||||
util.onInsertReplaySequence = inputBuffer.lastInsertCommands;
|
||||
var previous = inputBuffer.previous;
|
||||
if (previous) // If there is a previous action
|
||||
inputBuffer.exec(editor, previous.action, previous.param);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var inputBuffer = exports.inputBuffer = {
|
||||
accepting: [NUMBER, OPERATOR, MOTION, ACTION],
|
||||
currentCmd: null,
|
||||
//currentMode: 0,
|
||||
currentCount: "",
|
||||
|
||||
// Types
|
||||
operator: null,
|
||||
motion: null,
|
||||
|
||||
lastInsertCommands: [],
|
||||
|
||||
push: function(editor, char, keyId) {
|
||||
this.idle = false;
|
||||
var wObj = this.waitingForParam;
|
||||
if (wObj) {
|
||||
this.exec(editor, wObj, char);
|
||||
}
|
||||
// If input is a number (that doesn't start with 0)
|
||||
else if (!(char === "0" && !this.currentCount.length) &&
|
||||
(char.match(/^\d+$/) && this.isAccepting(NUMBER))) {
|
||||
// Assuming that char is always of type String, and not Number
|
||||
this.currentCount += char;
|
||||
this.currentCmd = NUMBER;
|
||||
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
|
||||
}
|
||||
else if (!this.operator && this.isAccepting(OPERATOR) && operators[char]) {
|
||||
this.operator = {
|
||||
char: char,
|
||||
count: this.getCount()
|
||||
};
|
||||
this.currentCmd = OPERATOR;
|
||||
this.accepting = [NUMBER, MOTION, ACTION];
|
||||
this.exec(editor, { operator: this.operator });
|
||||
}
|
||||
else if (motions[char] && this.isAccepting(MOTION)) {
|
||||
this.currentCmd = MOTION;
|
||||
|
||||
var ctx = {
|
||||
operator: this.operator,
|
||||
motion: {
|
||||
char: char,
|
||||
count: this.getCount()
|
||||
}
|
||||
};
|
||||
|
||||
if (motions[char].param)
|
||||
this.waitForParam(ctx);
|
||||
else
|
||||
this.exec(editor, ctx);
|
||||
}
|
||||
else if (alias[char] && this.isAccepting(MOTION)) {
|
||||
alias[char].operator.count = this.getCount();
|
||||
this.exec(editor, alias[char]);
|
||||
}
|
||||
else if (actions[char] && this.isAccepting(ACTION)) {
|
||||
var actionObj = {
|
||||
action: {
|
||||
fn: actions[char].fn,
|
||||
count: this.getCount()
|
||||
}
|
||||
};
|
||||
|
||||
if (actions[char].param) {
|
||||
this.waitForParam(actionObj);
|
||||
}
|
||||
else {
|
||||
this.exec(editor, actionObj);
|
||||
}
|
||||
|
||||
if (actions[char].acceptsMotion)
|
||||
this.idle = false;
|
||||
}
|
||||
else if (this.operator) {
|
||||
this.exec(editor, { operator: this.operator }, char);
|
||||
}
|
||||
else {
|
||||
this.reset();
|
||||
}
|
||||
},
|
||||
|
||||
waitForParam: function(cmd) {
|
||||
this.waitingForParam = cmd;
|
||||
},
|
||||
|
||||
getCount: function() {
|
||||
var count = this.currentCount;
|
||||
this.currentCount = "";
|
||||
return count && parseInt(count, 10);
|
||||
},
|
||||
|
||||
exec: function(editor, action, param) {
|
||||
var m = action.motion;
|
||||
var o = action.operator;
|
||||
var a = action.action;
|
||||
|
||||
if (!param)
|
||||
param = action.param;
|
||||
|
||||
if (o) {
|
||||
this.previous = {
|
||||
action: action,
|
||||
param: param
|
||||
};
|
||||
}
|
||||
|
||||
if (o && !editor.selection.isEmpty()) {
|
||||
if (operators[o.char].selFn) {
|
||||
operators[o.char].selFn(editor, editor.getSelectionRange(), o.count, param);
|
||||
this.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// There is an operator, but no motion or action. We try to pass the
|
||||
// current char to the operator to see if it responds to it (an example
|
||||
// of this is the 'dd' operator).
|
||||
else if (!m && !a && o && param) {
|
||||
operators[o.char].fn(editor, null, o.count, param);
|
||||
this.reset();
|
||||
}
|
||||
else if (m) {
|
||||
var run = function(fn) {
|
||||
if (fn && typeof fn === "function") { // There should always be a motion
|
||||
if (m.count && !motionObj.handlesCount)
|
||||
repeat(fn, m.count, [editor, null, m.count, param]);
|
||||
else
|
||||
fn(editor, null, m.count, param);
|
||||
}
|
||||
};
|
||||
|
||||
var motionObj = motions[m.char];
|
||||
var selectable = motionObj.sel;
|
||||
|
||||
if (!o) {
|
||||
if ((util.onVisualMode || util.onVisualLineMode) && selectable)
|
||||
run(motionObj.sel);
|
||||
else
|
||||
run(motionObj.nav);
|
||||
}
|
||||
else if (selectable) {
|
||||
repeat(function() {
|
||||
run(motionObj.sel);
|
||||
operators[o.char].fn(editor, editor.getSelectionRange(), o.count, param);
|
||||
}, o.count || 1);
|
||||
}
|
||||
this.reset();
|
||||
}
|
||||
else if (a) {
|
||||
a.fn(editor, editor.getSelectionRange(), a.count, param);
|
||||
this.reset();
|
||||
}
|
||||
handleCursorMove(editor);
|
||||
},
|
||||
|
||||
isAccepting: function(type) {
|
||||
return this.accepting.indexOf(type) !== -1;
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.operator = null;
|
||||
this.motion = null;
|
||||
this.currentCount = "";
|
||||
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
|
||||
this.idle = true;
|
||||
this.waitingForParam = null;
|
||||
}
|
||||
};
|
||||
|
||||
function setPreviousCommand(fn) {
|
||||
inputBuffer.previous = { action: { action: { fn: fn } } };
|
||||
}
|
||||
|
||||
exports.coreCommands = {
|
||||
start: {
|
||||
exec: function start(editor) {
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(start);
|
||||
}
|
||||
},
|
||||
startBeginning: {
|
||||
exec: function startBeginning(editor) {
|
||||
editor.navigateLineStart();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(startBeginning);
|
||||
}
|
||||
},
|
||||
// Stop Insert mode as soon as possible. Works like typing <Esc> in
|
||||
// insert mode.
|
||||
stop: {
|
||||
exec: function stop(editor) {
|
||||
inputBuffer.reset();
|
||||
util.onVisualMode = false;
|
||||
util.onVisualLineMode = false;
|
||||
inputBuffer.lastInsertCommands = util.normalMode(editor);
|
||||
}
|
||||
},
|
||||
append: {
|
||||
exec: function append(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
if (lineLen)
|
||||
editor.navigateRight();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(append);
|
||||
}
|
||||
},
|
||||
appendEnd: {
|
||||
exec: function appendEnd(editor) {
|
||||
editor.navigateLineEnd();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(appendEnd);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var handleCursorMove = exports.onCursorMove = function(editor, e) {
|
||||
if (util.currentMode === 'insert' || handleCursorMove.running)
|
||||
return;
|
||||
else if(!editor.selection.isEmpty()) {
|
||||
handleCursorMove.running = true;
|
||||
if (util.onVisualLineMode) {
|
||||
var originRow = editor.selection.visualLineStart;
|
||||
var cursorRow = editor.getCursorPosition().row;
|
||||
if(originRow <= cursorRow) {
|
||||
var endLine = editor.session.getLine(cursorRow);
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(originRow, 0);
|
||||
editor.selection.selectTo(cursorRow, endLine.length);
|
||||
} else {
|
||||
var endLine = editor.session.getLine(originRow);
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(originRow, endLine.length);
|
||||
editor.selection.selectTo(cursorRow, 0);
|
||||
}
|
||||
}
|
||||
handleCursorMove.running = false;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (e && (util.onVisualLineMode || util.onVisualMode)) {
|
||||
editor.selection.clearSelection();
|
||||
util.normalMode(editor);
|
||||
}
|
||||
|
||||
handleCursorMove.running = true;
|
||||
var pos = editor.getCursorPosition();
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
|
||||
if (lineLen && pos.column === lineLen)
|
||||
editor.navigateLeft();
|
||||
handleCursorMove.running = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict"
|
||||
|
||||
define(function(require, exports, module) {
|
||||
module.exports = {
|
||||
"x": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "l",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"X": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "h",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"D": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "$",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"C": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "$",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"s": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "l",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"S": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
param: "c"
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,611 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict"
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var util = require("./util");
|
||||
|
||||
var keepScrollPosition = function(editor, fn) {
|
||||
var scrollTopRow = editor.renderer.getScrollTopRow();
|
||||
var initialRow = editor.getCursorPosition().row;
|
||||
var diff = initialRow - scrollTopRow;
|
||||
fn && fn.call(editor);
|
||||
editor.renderer.scrollToRow(editor.getCursorPosition().row - diff);
|
||||
};
|
||||
|
||||
function Motion(getRange, type){
|
||||
if (type == 'extend')
|
||||
var extend = true;
|
||||
else
|
||||
var reverse = type;
|
||||
|
||||
this.nav = function(editor) {
|
||||
var r = getRange(editor);
|
||||
if (!r)
|
||||
return;
|
||||
if (!r.end)
|
||||
var a = r;
|
||||
else if (reverse)
|
||||
var a = r.start;
|
||||
else
|
||||
var a = r.end;
|
||||
|
||||
editor.clearSelection();
|
||||
editor.moveCursorTo(a.row, a.column);
|
||||
}
|
||||
this.sel = function(editor){
|
||||
var r = getRange(editor);
|
||||
if (!r)
|
||||
return;
|
||||
if (extend)
|
||||
return editor.selection.setSelectionRange(r);
|
||||
|
||||
if (!r.end)
|
||||
var a = r;
|
||||
else if (reverse)
|
||||
var a = r.start;
|
||||
else
|
||||
var a = r.end;
|
||||
|
||||
editor.selection.selectTo(a.row, a.column);
|
||||
}
|
||||
}
|
||||
|
||||
var nonWordRe = /[\s.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/;
|
||||
var wordSeparatorRe = /[.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/;
|
||||
var whiteRe = /\s/;
|
||||
var StringStream = function(editor, cursor) {
|
||||
var sel = editor.selection;
|
||||
this.range = sel.getRange();
|
||||
cursor = cursor || sel.selectionLead;
|
||||
this.row = cursor.row;
|
||||
this.col = cursor.column;
|
||||
var line = editor.session.getLine(this.row);
|
||||
var maxRow = editor.session.getLength()
|
||||
this.ch = line[this.col] || '\n'
|
||||
this.skippedLines = 0;
|
||||
|
||||
this.next = function() {
|
||||
this.ch = line[++this.col] || this.handleNewLine(1);
|
||||
//this.debug()
|
||||
return this.ch;
|
||||
}
|
||||
this.prev = function() {
|
||||
this.ch = line[--this.col] || this.handleNewLine(-1);
|
||||
//this.debug()
|
||||
return this.ch;
|
||||
}
|
||||
this.peek = function(dir) {
|
||||
var ch = line[this.col + dir];
|
||||
if (ch)
|
||||
return ch;
|
||||
if (dir == -1)
|
||||
return '\n';
|
||||
if (this.col == line.length - 1)
|
||||
return '\n';
|
||||
return editor.session.getLine(this.row + 1)[0] || '\n';
|
||||
}
|
||||
|
||||
this.handleNewLine = function(dir) {
|
||||
if (dir == 1){
|
||||
if (this.col == line.length)
|
||||
return '\n';
|
||||
if (this.row == maxRow - 1)
|
||||
return '';
|
||||
this.col = 0;
|
||||
this.row ++;
|
||||
line = editor.session.getLine(this.row);
|
||||
this.skippedLines++;
|
||||
return line[0] || '\n';
|
||||
}
|
||||
if (dir == -1) {
|
||||
if (this.row == 0)
|
||||
return '';
|
||||
this.row --;
|
||||
line = editor.session.getLine(this.row);
|
||||
this.col = line.length;
|
||||
this.skippedLines--;
|
||||
return '\n';
|
||||
}
|
||||
}
|
||||
this.debug = function() {
|
||||
console.log(line.substring(0, this.col)+'|'+this.ch+'\''+this.col+'\''+line.substr(this.col+1));
|
||||
}
|
||||
}
|
||||
|
||||
var Search = require("ace/search").Search;
|
||||
var search = new Search();
|
||||
|
||||
function find(editor, needle, dir) {
|
||||
search.$options.needle = needle;
|
||||
search.$options.backwards = dir == -1;
|
||||
return search.find(editor.session);
|
||||
}
|
||||
|
||||
var Range = require("ace/range").Range;
|
||||
|
||||
module.exports = {
|
||||
"w": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
|
||||
if (str.ch && wordSeparatorRe.test(str.ch)) {
|
||||
while (str.ch && wordSeparatorRe.test(str.ch))
|
||||
str.next();
|
||||
} else {
|
||||
while (str.ch && !nonWordRe.test(str.ch))
|
||||
str.next();
|
||||
}
|
||||
while (str.ch && whiteRe.test(str.ch) && str.skippedLines < 2)
|
||||
str.next();
|
||||
|
||||
str.skippedLines == 2 && str.prev();
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
"W": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
while(str.ch && !(whiteRe.test(str.ch) && !whiteRe.test(str.peek(1))) && str.skippedLines < 2)
|
||||
str.next();
|
||||
if (str.skippedLines == 2)
|
||||
str.prev();
|
||||
else
|
||||
str.next();
|
||||
|
||||
return {column: str.col, row: str.row}
|
||||
}),
|
||||
"b": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
|
||||
str.prev();
|
||||
while (str.ch && whiteRe.test(str.ch) && str.skippedLines > -2)
|
||||
str.prev();
|
||||
|
||||
if (str.ch && wordSeparatorRe.test(str.ch)) {
|
||||
while (str.ch && wordSeparatorRe.test(str.ch))
|
||||
str.prev();
|
||||
} else {
|
||||
while (str.ch && !nonWordRe.test(str.ch))
|
||||
str.prev();
|
||||
}
|
||||
str.ch && str.next();
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
"B": new Motion(function(editor) {
|
||||
var str = new StringStream(editor)
|
||||
str.prev();
|
||||
while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(-1))) && str.skippedLines > -2)
|
||||
str.prev();
|
||||
|
||||
if (str.skippedLines == -2)
|
||||
str.next();
|
||||
|
||||
return {column: str.col, row: str.row};
|
||||
}, true),
|
||||
"e": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
|
||||
str.next();
|
||||
while (str.ch && whiteRe.test(str.ch))
|
||||
str.next();
|
||||
|
||||
if (str.ch && wordSeparatorRe.test(str.ch)) {
|
||||
while (str.ch && wordSeparatorRe.test(str.ch))
|
||||
str.next();
|
||||
} else {
|
||||
while (str.ch && !nonWordRe.test(str.ch))
|
||||
str.next();
|
||||
}
|
||||
str.ch && str.prev();
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
"E": new Motion(function(editor) {
|
||||
var str = new StringStream(editor);
|
||||
str.next();
|
||||
while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(1))))
|
||||
str.next();
|
||||
|
||||
return {column: str.col, row: str.row};
|
||||
}),
|
||||
|
||||
"l": {
|
||||
nav: function(editor) {
|
||||
editor.navigateRight();
|
||||
},
|
||||
sel: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var col = pos.column;
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
|
||||
// Solving the behavior at the end of the line due to the
|
||||
// different 0 index-based colum positions in ACE.
|
||||
if (lineLen && col !== lineLen) //In selection mode you can select the newline
|
||||
editor.selection.selectRight();
|
||||
}
|
||||
},
|
||||
"h": {
|
||||
nav: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
if (pos.column > 0)
|
||||
editor.navigateLeft();
|
||||
},
|
||||
sel: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
if (pos.column > 0)
|
||||
editor.selection.selectLeft();
|
||||
}
|
||||
},
|
||||
"k": {
|
||||
nav: function(editor) {
|
||||
editor.navigateUp();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectUp();
|
||||
}
|
||||
},
|
||||
"j": {
|
||||
nav: function(editor) {
|
||||
editor.navigateDown();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectDown();
|
||||
}
|
||||
},
|
||||
|
||||
"i": {
|
||||
param: true,
|
||||
sel: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "w":
|
||||
editor.selection.selectWord();
|
||||
break;
|
||||
case "W":
|
||||
editor.selection.selectAWord();
|
||||
break;
|
||||
case "(":
|
||||
case "{":
|
||||
case "[":
|
||||
var cursor = editor.getCursorPosition();
|
||||
var end = editor.session.$findClosingBracket(param, cursor, /paren/);
|
||||
if (!end)
|
||||
return;
|
||||
var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/);
|
||||
if (!start)
|
||||
return;
|
||||
start.column ++;
|
||||
editor.selection.setSelectionRange(Range.fromPoints(start, end));
|
||||
break;
|
||||
case "'":
|
||||
case '"':
|
||||
case "/":
|
||||
var end = find(editor, param, 1);
|
||||
if (!end)
|
||||
return;
|
||||
var start = find(editor, param, -1);
|
||||
if (!start)
|
||||
return;
|
||||
editor.selection.setSelectionRange(Range.fromPoints(start.end, end.start));
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"a": {
|
||||
param: true,
|
||||
sel: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "w":
|
||||
editor.selection.selectAWord();
|
||||
break;
|
||||
case "W":
|
||||
editor.selection.selectAWord();
|
||||
break;
|
||||
case "(":
|
||||
case "{":
|
||||
case "[":
|
||||
var cursor = editor.getCursorPosition();
|
||||
var end = editor.session.$findClosingBracket(param, cursor, /paren/);
|
||||
if (!end)
|
||||
return;
|
||||
var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/);
|
||||
if (!start)
|
||||
return;
|
||||
end.column ++;
|
||||
editor.selection.setSelectionRange(Range.fromPoints(start, end));
|
||||
break;
|
||||
case "'":
|
||||
case "\"":
|
||||
case "/":
|
||||
var end = find(editor, param, 1);
|
||||
if (!end)
|
||||
return;
|
||||
var start = find(editor, param, -1);
|
||||
if (!start)
|
||||
return;
|
||||
end.column ++;
|
||||
editor.selection.setSelectionRange(Range.fromPoints(start.start, end.end));
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"f": {
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column + 1);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column + 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
"F": {
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
count = parseInt(count, 10) || 1;
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, cursor.column - column - 1);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, cursor.column - column - 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": {
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column);
|
||||
}
|
||||
}
|
||||
},
|
||||
"T": {
|
||||
param: true,
|
||||
handlesCount: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, -column + cursor.column);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, -column + cursor.column);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"^": {
|
||||
nav: function(editor) {
|
||||
editor.navigateLineStart();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectLineStart();
|
||||
}
|
||||
},
|
||||
"$": {
|
||||
nav: function(editor) {
|
||||
editor.navigateLineEnd();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectLineEnd();
|
||||
}
|
||||
},
|
||||
"0": {
|
||||
nav: function(editor) {
|
||||
var ed = editor;
|
||||
ed.navigateTo(ed.selection.selectionLead.row, 0);
|
||||
},
|
||||
sel: function(editor) {
|
||||
var ed = editor;
|
||||
ed.selectTo(ed.selection.selectionLead.row, 0);
|
||||
}
|
||||
},
|
||||
"G": {
|
||||
nav: function(editor, range, count, param) {
|
||||
if (!count && count !== 0) { // Stupid JS
|
||||
count = editor.session.getLength();
|
||||
}
|
||||
editor.gotoLine(count);
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
if (!count && count !== 0) { // Stupid JS
|
||||
count = editor.session.getLength();
|
||||
}
|
||||
editor.selection.selectTo(count, 0);
|
||||
}
|
||||
},
|
||||
"g": {
|
||||
param: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
switch(param) {
|
||||
case "m":
|
||||
console.log("Middle line");
|
||||
break;
|
||||
case "e":
|
||||
console.log("End of prev word");
|
||||
break;
|
||||
case "g":
|
||||
editor.gotoLine(count || 0);
|
||||
case "u":
|
||||
editor.gotoLine(count || 0);
|
||||
case "U":
|
||||
editor.gotoLine(count || 0);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
switch(param) {
|
||||
case "m":
|
||||
console.log("Middle line");
|
||||
break;
|
||||
case "e":
|
||||
console.log("End of prev word");
|
||||
break;
|
||||
case "g":
|
||||
editor.selection.selectTo(count || 0, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
"o": {
|
||||
nav: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
var content = "";
|
||||
while (0 < count--)
|
||||
content += "\n";
|
||||
|
||||
if (content.length) {
|
||||
editor.navigateLineEnd()
|
||||
editor.insert(content);
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
},
|
||||
"O": {
|
||||
nav: function(editor, range, count, param) {
|
||||
var row = editor.getCursorPosition().row;
|
||||
count = count || 1;
|
||||
var content = "";
|
||||
while (0 < count--)
|
||||
content += "\n";
|
||||
|
||||
if (content.length) {
|
||||
if(row > 0) {
|
||||
editor.navigateUp();
|
||||
editor.navigateLineEnd()
|
||||
editor.insert(content);
|
||||
} else {
|
||||
editor.session.insert({row: 0, column: 0}, content);
|
||||
editor.navigateUp();
|
||||
}
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
},
|
||||
"%": new Motion(function(editor){
|
||||
var brRe = /[\[\]{}()]/g;
|
||||
var cursor = editor.getCursorPosition();
|
||||
var ch = editor.session.getLine(cursor.row)[cursor.column];
|
||||
if (!brRe.test(ch)) {
|
||||
var range = find(editor, brRe);
|
||||
if (!range)
|
||||
return;
|
||||
cursor = range.start;
|
||||
}
|
||||
var match = editor.session.findMatchingBracket({
|
||||
row: cursor.row,
|
||||
column: cursor.column + 1
|
||||
});
|
||||
|
||||
return match;
|
||||
}),
|
||||
"ctrl-d": {
|
||||
nav: function(editor, range, count, param) {
|
||||
editor.selection.clearSelection();
|
||||
keepScrollPosition(editor, editor.gotoPageDown);
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
keepScrollPosition(editor, editor.selectPageDown);
|
||||
}
|
||||
},
|
||||
"ctrl-u": {
|
||||
nav: function(editor, range, count, param) {
|
||||
editor.selection.clearSelection();
|
||||
keepScrollPosition(editor, editor.gotoPageUp);
|
||||
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
keepScrollPosition(editor, editor.selectPageUp);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
module.exports.backspace = module.exports.left = module.exports.h;
|
||||
module.exports.right = module.exports.l;
|
||||
module.exports.up = module.exports.k;
|
||||
module.exports.down = module.exports.j;
|
||||
module.exports.pagedown = module.exports["ctrl-d"];
|
||||
module.exports.pageup = module.exports["ctrl-u"];
|
||||
|
||||
});
|
||||
@@ -0,0 +1,193 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Ajax.org Code Editor (ACE).
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ajax.org B.V.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Sergi Mansilla <sergi AT c9 DOT io>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
"never use strict";
|
||||
|
||||
var util = require("./util");
|
||||
var registers = require("../registers");
|
||||
|
||||
module.exports = {
|
||||
"d": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = util.onVisualLineMode;
|
||||
if(util.onVisualLineMode)
|
||||
editor.removeLines();
|
||||
else
|
||||
editor.session.remove(range);
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
switch (param) {
|
||||
case "d":
|
||||
registers._default.text = "";
|
||||
registers._default.isLine = true;
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.selection.selectLine();
|
||||
registers._default.text += editor.getCopyText();
|
||||
var selRange = editor.getSelectionRange();
|
||||
editor.session.remove(selRange);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
registers._default.text = registers._default.text.replace(/\n$/, "");
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
editor.selection.setSelectionRange(range);
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = false;
|
||||
editor.session.remove(range);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"c": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
editor.session.remove(range);
|
||||
util.insertMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
switch (param) {
|
||||
case "c":
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.removeLines();
|
||||
util.insertMode(editor);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
|
||||
// range.end.column ++;
|
||||
editor.session.remove(range);
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"y": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = util.onVisualLineMode;
|
||||
editor.selection.clearSelection();
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
switch (param) {
|
||||
case "y":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
registers._default.text = editor.getCopyText().replace(/\n$/, "");
|
||||
editor.selection.clearSelection();
|
||||
registers._default.isLine = true;
|
||||
editor.moveCursorToPosition(pos);
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.setSelectionRange(range);
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = false;
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
">": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.indent();
|
||||
}
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
switch (param) {
|
||||
case ">":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
editor.indent();
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorToPosition(pos);
|
||||
editor.navigateLineEnd();
|
||||
editor.navigateLineStart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"<": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.blockOutdent();
|
||||
}
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
switch (param) {
|
||||
case "<":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
editor.blockOutdent();
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorToPosition(pos);
|
||||
editor.navigateLineEnd();
|
||||
editor.navigateLineStart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||