mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-10-03 12:10:34 +00:00
Compare commits
1895 Commits
0.6.3
...
4.0.0-alpha.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 856b222a61 | |||
| fade3740c1 | |||
| 803d6218a7 | |||
| 7128db842a | |||
| 0342a11da0 | |||
| af80cbcd7c | |||
| a84d02ece0 | |||
| 45b9fc2094 | |||
| a96ef569bd | |||
| 4b3ac4e827 | |||
| 7029c01806 | |||
| 11893255d1 | |||
| 53f94b317e | |||
| 4717b0a17f | |||
| 43ce7badb7 | |||
| 9e399da06a | |||
| 026b33227d | |||
| e94634bda5 | |||
| 194ebc3da9 | |||
| 16af264360 | |||
| 64ccb6b00b | |||
| 8bf3241b63 | |||
| 6a4f6eadd2 | |||
| 532df30db7 | |||
| fd1f7a5609 | |||
| febdd8a8bd | |||
| b04724ae0b | |||
| 5dbd8f5740 | |||
| f3af207e6e | |||
| 7d05f8cb89 | |||
| 9d3c397446 | |||
| 0681a51c2f | |||
| 36e548fd3c | |||
| ec149e6112 | |||
| e1bcb4ed7d | |||
| 4aae18617b | |||
| 6d00944576 | |||
| be8b11dcb4 | |||
| 1780435c4f | |||
| ebf7a5cf50 | |||
| 5f0a81d18b | |||
| b564ef6580 | |||
| 1d877db5f0 | |||
| 92678bb93f | |||
| 4f2c729d60 | |||
| 59079bc18d | |||
| 66c2a6c076 | |||
| 182bb9eb86 | |||
| 9ab738e478 | |||
| d0555e2bd0 | |||
| cdf9842d68 | |||
| a1ae5c2295 | |||
| 373a486a14 | |||
| f262a7cd89 | |||
| b63b0cc50d | |||
| 5839d4d8a8 | |||
| d9c3cb418a | |||
| 12c7ac1498 | |||
| 2c3072fd8a | |||
| bb14f48c39 | |||
| d56019dc18 | |||
| 0a6216a093 | |||
| 4c174f916e | |||
| 4db57fe5c5 | |||
| 2a78bcebab | |||
| be14a8ea4d | |||
| 37920c758b | |||
| 52f9409e24 | |||
| 05646996c0 | |||
| c439cf8513 | |||
| 1a3e4e8337 | |||
| 631cebfd2f | |||
| f1f2024489 | |||
| 227b329e78 | |||
| da8c78b3c8 | |||
| c42c5897fe | |||
| 3aea3e5d88 | |||
| 95b3b4ebb7 | |||
| ba56801352 | |||
| 48ee0e35b0 | |||
| 2fff291cad | |||
| baea45d924 | |||
| 52d0384605 | |||
| 961b9d7031 | |||
| 5b0622014a | |||
| 7253dbc476 | |||
| b4dd3e1ddc | |||
| 4b6fc0ae2f | |||
| 5d4dc499a5 | |||
| 0e7aece96d | |||
| b7c245d75a | |||
| 5fed4e1ced | |||
| c71da9955e | |||
| 3a2abb870b | |||
| e8947a2c11 | |||
| 885a161d42 | |||
| fe0d4bf024 | |||
| aa39b8e71b | |||
| 3000dcefe1 | |||
| f1405d3958 | |||
| caeadd431b | |||
| d5796ccf04 | |||
| 71cce33836 | |||
| 9eeb7304c7 | |||
| 3b5bea0eb5 | |||
| 17d921cb11 | |||
| 10ab06a32c | |||
| 1bc802e4c8 | |||
| 9a9b5a2621 | |||
| 66231f8b7f | |||
| 7037ac55bd | |||
| cf35fef3b3 | |||
| 16800cc70a | |||
| 417013a230 | |||
| 5a57a2c62a | |||
| 4cfffb26f2 | |||
| 9d4221936e | |||
| 34baae1a5d | |||
| cd0ed86589 | |||
| 2d429b731b | |||
| 03b89194d7 | |||
| 68ec88c620 | |||
| 47a27fc12d | |||
| 9cedcc6b6e | |||
| d6de8f4173 | |||
| 1d291ff2f0 | |||
| 58ae96b7f6 | |||
| 1354582c4e | |||
| 4119917555 | |||
| 9d20a9afa5 | |||
| 45683185a2 | |||
| 6ce4949df3 | |||
| 0614613b84 | |||
| 6faf6a53f0 | |||
| bced415a50 | |||
| 805886e4a9 | |||
| 83c98cf4d8 | |||
| 86848e7acb | |||
| 9ce3646d6e | |||
| 45752fc79c | |||
| a863b55c79 | |||
| 16ca48b2c0 | |||
| 87ae2481e4 | |||
| ccb5dcf559 | |||
| 84315a99f1 | |||
| 026cc8304d | |||
| cefbfdc7b8 | |||
| 4049279269 | |||
| b04befd67c | |||
| d82032298d | |||
| 34eb35699d | |||
| 3ae72bb47c | |||
| cd2d5e5101 | |||
| 5abac3a79a | |||
| d22d090b05 | |||
| 24b657f790 | |||
| 649a6c980c | |||
| 24624f0d0e | |||
| 9aaf561c41 | |||
| 8be4cbc887 | |||
| 32556e6724 | |||
| ad425b9772 | |||
| 5238fa352c | |||
| 32183b6650 | |||
| cb3d6a7f01 | |||
| c978f0ab21 | |||
| 8753897edc | |||
| da83d9e91d | |||
| 2cf507a807 | |||
| 1489129407 | |||
| b5c407cf7b | |||
| 9d8dffb6f0 | |||
| 6015defe11 | |||
| 7f28379154 | |||
| 6f98ee1846 | |||
| 42d53ec032 | |||
| 287c80b2e1 | |||
| 33ff60cee7 | |||
| 26fc021b90 | |||
| 33d7e022e6 | |||
| 09782b964b | |||
| 7938ee8ec6 | |||
| c314281da0 | |||
| 2e8e4f63d7 | |||
| bc5df83846 | |||
| f1ef1902f3 | |||
| 748c46172b | |||
| 51f4cd6dae | |||
| 64ce8bcf42 | |||
| ff42b58f77 | |||
| 7fa3e34f9f | |||
| e46cd78f80 | |||
| fab88bb47e | |||
| fa7cf3a65f | |||
| d0885491b7 | |||
| 45c54d0cd7 | |||
| f49089a7d3 | |||
| 0b1888e184 | |||
| 2257e42299 | |||
| 0e0c1a473b | |||
| a18370551a | |||
| a8aeab17d6 | |||
| 2adca5deb9 | |||
| 3b3f43a35d | |||
| ced0be930d | |||
| 6d58a90613 | |||
| 2796065886 | |||
| b9fa6c3051 | |||
| 82c2c214eb | |||
| ee35da4be5 | |||
| 24c4f41945 | |||
| fe298f2a3f | |||
| ab3d94a55d | |||
| ff31514c66 | |||
| 3f1ec310ca | |||
| b796069ade | |||
| 839904a704 | |||
| 0e74c9bad5 | |||
| d7e415b0b3 | |||
| b170b4d197 | |||
| a14ca3e268 | |||
| 9c071dade5 | |||
| 56e44651fa | |||
| 42fac98992 | |||
| 4f5513add0 | |||
| 90cbfc0596 | |||
| 38ab9fa05a | |||
| 12e20c5fcc | |||
| 6b103f4532 | |||
| d4fa5c18a8 | |||
| 2a116dfdb0 | |||
| 0349f54f3c | |||
| 695bda312c | |||
| 144bd4c97a | |||
| e105983cf8 | |||
| ea3afbed75 | |||
| d563abe3df | |||
| 70fd4ded29 | |||
| 9ce9388dfc | |||
| c575ad83ae | |||
| 936fa1545b | |||
| c9c2dde2b6 | |||
| d9a1d387c7 | |||
| bf29d187c8 | |||
| d86f9b2667 | |||
| aca4313fc3 | |||
| 4cb5bb06fb | |||
| 24988b75ea | |||
| 775e858d05 | |||
| 1e3d871c1e | |||
| 94a4310c1e | |||
| e8ee57be83 | |||
| 50a132cb2c | |||
| 59be32a54f | |||
| 4ae7cdb5d1 | |||
| 990a4efeb5 | |||
| 9c927dcf13 | |||
| 7a08b3f109 | |||
| 94d4234cb8 | |||
| fbc851bc4e | |||
| e92b661a2a | |||
| b9fe60915f | |||
| 1bf7d092f0 | |||
| 826d472511 | |||
| a6b1f4bd87 | |||
| 004f91f02c | |||
| e6c6ec4293 | |||
| a1d3acf065 | |||
| a732660f59 | |||
| e1bb0638f8 | |||
| 788c0c7e7e | |||
| 762fe16a17 | |||
| 15123805d1 | |||
| 23aecb4f2b | |||
| f1d200b81b | |||
| b566711ee1 | |||
| 22da5aac11 | |||
| f7b95102c5 | |||
| ca70c934d6 | |||
| 1cc48fa314 | |||
| b63b5574d3 | |||
| 67106e8698 | |||
| dc2ab51a88 | |||
| cedfa186f2 | |||
| 80f0d1bfed | |||
| 7178ab1f82 | |||
| bf895b707e | |||
| 996170a4ad | |||
| aa66a4f928 | |||
| 23010fa54a | |||
| 0baebc7979 | |||
| 257158321c | |||
| ddf0a41e29 | |||
| 357e1e8e96 | |||
| 7a89f9869a | |||
| 30fbd22efe | |||
| 29df73ba72 | |||
| f8676483c1 | |||
| c79a6f2fba | |||
| c38e67ea61 | |||
| 97a5f8805e | |||
| 421fef6ebf | |||
| 33406c3082 | |||
| c3851889b0 | |||
| 4a5de2da6b | |||
| 1afb23cada | |||
| a3b0f3f868 | |||
| 0aa32916d6 | |||
| ebe845d46c | |||
| edee8d2fc5 | |||
| 5f3de0876f | |||
| 2ceab04d01 | |||
| de37de44e8 | |||
| ccb87d5a13 | |||
| e2e0ca3f05 | |||
| b33a79704b | |||
| 6def174b84 | |||
| 346a18b444 | |||
| b32685c698 | |||
| 09b3618da8 | |||
| 901328f247 | |||
| b47ebaa9d9 | |||
| 465e8d6c0a | |||
| ecd86ec877 | |||
| 5d7864154c | |||
| 7b915428f7 | |||
| 0bce3517fd | |||
| 089815a8fd | |||
| 7e8f1a9632 | |||
| 8469648241 | |||
| e7a44358a5 | |||
| fb930d889f | |||
| 721a75309b | |||
| b856bff91b | |||
| 0744f000f9 | |||
| d1e226dba5 | |||
| 1923d28d71 | |||
| 484a306adb | |||
| 5bfc9f2f56 | |||
| 86a65e5287 | |||
| 956d301dd7 | |||
| 00d1a7b5a6 | |||
| 2718c9c017 | |||
| 3234c1e03f | |||
| c8f8eece92 | |||
| 7394efa9dc | |||
| 3e4241fc88 | |||
| a5ae79604c | |||
| fc4bdd68a1 | |||
| f83975b022 | |||
| 167d3957bf | |||
| a9571fd67d | |||
| ac87f48ba5 | |||
| 05403f527d | |||
| 53c72f0806 | |||
| c8c2a61f96 | |||
| 08d780d1f6 | |||
| 2e74fafa36 | |||
| 28ac9ab88a | |||
| 26acab4dfb | |||
| d4b562e001 | |||
| 61956e0646 | |||
| 7892259fe6 | |||
| b97d1c7796 | |||
| a091c5b331 | |||
| 784b3379b5 | |||
| 62446e75d2 | |||
| 8aa2f3075c | |||
| 839ee0385a | |||
| d6b60c6116 | |||
| 9013f02850 | |||
| 961d43f085 | |||
| 7bd49606e3 | |||
| d7c8635350 | |||
| 19e9ff81d2 | |||
| e137bf632a | |||
| 2fef898a1e | |||
| 0945807184 | |||
| d85663b153 | |||
| 481a7d790c | |||
| ef589a6b13 | |||
| d5c4af3377 | |||
| 0b4df4cdf2 | |||
| d6814dc48e | |||
| ce50a1d50f | |||
| a76e018d36 | |||
| b06f1fd677 | |||
| 3d8b1880dc | |||
| 1a13c8c9bb | |||
| 852fae3a09 | |||
| d342d31c8e | |||
| 5b3f54fbc8 | |||
| 308ece784c | |||
| 0758ddf04e | |||
| f24d9aef73 | |||
| f8bb55f258 | |||
| 76daebeb84 | |||
| b0d366b7e8 | |||
| 3d0054dd64 | |||
| 13bc89ff44 | |||
| bb910f984e | |||
| e576fdea14 | |||
| c7864927ec | |||
| 54956de59f | |||
| 2cbd30d1f2 | |||
| 55614f1675 | |||
| 4f7421993f | |||
| 32ad7b530e | |||
| ee5d5010f6 | |||
| cf7e5884cd | |||
| 11a0a64d9e | |||
| b6051babac | |||
| 34947b5e20 | |||
| c621380b66 | |||
| c4b54033ce | |||
| 4d85d6eb6e | |||
| cc9274c9af | |||
| bbdf7efc34 | |||
| 38a986995a | |||
| ee8d35df7a | |||
| be411cd5ff | |||
| 2104019171 | |||
| 4e564707df | |||
| da8611e0c3 | |||
| 5d11641a5f | |||
| 24d38e4fcf | |||
| efb65a8413 | |||
| 3fc90554f5 | |||
| 4ebe28faae | |||
| 693171cb05 | |||
| 42a2d090aa | |||
| c84eaa83dd | |||
| 74c3ff80cb | |||
| 5893d3ee64 | |||
| 7f435c56a0 | |||
| 59b7100cf6 | |||
| 0923d1aa24 | |||
| ffe6c36f2f | |||
| 8c4752c5d8 | |||
| d6202e522b | |||
| 50a24c62c5 | |||
| 6b17d08892 | |||
| 79c91fd8c5 | |||
| 95764258ab | |||
| 41e6872557 | |||
| 30c96c37c2 | |||
| 20f1cf3dff | |||
| 8de0d6186e | |||
| edd7d8aefe | |||
| a8da4903f4 | |||
| c8df5033f7 | |||
| 412f418da3 | |||
| 3782d21069 | |||
| 82a29f4470 | |||
| 4a65326b24 | |||
| d75d8729be | |||
| c87060454e | |||
| bbba52c7ff | |||
| 33418bdb33 | |||
| de47db2b66 | |||
| fa6fcffbe1 | |||
| 93d3f11891 | |||
| 59479f10fc | |||
| 11e72253d4 | |||
| 37fca9c88a | |||
| 6d67048e98 | |||
| c516a5c1bd | |||
| 429431c13c | |||
| b80dfd7b9a | |||
| 4c144b6ceb | |||
| 718e32773a | |||
| fb75d5d3ee | |||
| 99bbcbebfc | |||
| 289e4b5dc1 | |||
| a974dcdab6 | |||
| 9a48620152 | |||
| e444b3a402 | |||
| fabf4f0c0a | |||
| d467888d6a | |||
| eb46311561 | |||
| 63839bb0a7 | |||
| 793fada0fb | |||
| 494ba78156 | |||
| 9816b27ebf | |||
| 1c43b7891b | |||
| 9d7739213e | |||
| 2ab5f6a305 | |||
| c73103969f | |||
| 6cbbdf5d5b | |||
| 3a48435497 | |||
| 084925de8b | |||
| 5bac2fe695 | |||
| 2c29fb241f | |||
| 77dc11bcc2 | |||
| 5154622566 | |||
| c681cd286a | |||
| c1d53ec11f | |||
| 36b49c66c6 | |||
| 80b8e340da | |||
| b51470db39 | |||
| a5f4596f8d | |||
| 5f3c3760c0 | |||
| 8b05885d57 | |||
| d9d7ab4ee5 | |||
| 30bce5f9bb | |||
| fbe0282738 | |||
| 5bad08b9a0 | |||
| 310691bca2 | |||
| 8f7967acd0 | |||
| faf18476b1 | |||
| 9acccad23a | |||
| db1a0aedf8 | |||
| 01a26fda25 | |||
| 0229272b0a | |||
| c817acff09 | |||
| a5eec81819 | |||
| 98f70879bd | |||
| ceb4627f4e | |||
| 8d9d4fe23f | |||
| 730298110c | |||
| 8578f7d0d1 | |||
| 07a5daefb0 | |||
| 0ed524bce5 | |||
| 94199af7b2 | |||
| b8d7a00f58 | |||
| aca963befc | |||
| 3ea4e334bf | |||
| 9955fa8c29 | |||
| fb37a6bcab | |||
| 4f8bdbb518 | |||
| 73c190891d | |||
| 93e701f471 | |||
| 68b9bf7e38 | |||
| 826f90505c | |||
| 7ae36f16c8 | |||
| 281f6d5535 | |||
| b4072a06c4 | |||
| cb3ee423c9 | |||
| 1360a744a7 | |||
| f3058598dc | |||
| 94db0f6ec9 | |||
| f08732095d | |||
| f946650ddb | |||
| 14fd6bbdce | |||
| 5059e8df34 | |||
| 3d405a1ac5 | |||
| 78e00db018 | |||
| e62bc31e63 | |||
| 4763f1342c | |||
| 9413e53b00 | |||
| 35d352bbeb | |||
| 8dd5e0c250 | |||
| 139e487998 | |||
| 9bb0a3fbd3 | |||
| 9a1a6f2625 | |||
| e781d6d2b1 | |||
| 5b342b50ce | |||
| 869822d180 | |||
| e50422bce5 | |||
| 999882e723 | |||
| d68dc82159 | |||
| cc9fdd0032 | |||
| 503cc4a729 | |||
| d585269228 | |||
| 50f535b910 | |||
| 978bdd149e | |||
| a9d558e891 | |||
| 8291eb58df | |||
| 7298dec353 | |||
| 7574b01863 | |||
| 98e739a12b | |||
| 262ce03e46 | |||
| 1906691a35 | |||
| 4ca23b84a4 | |||
| b05eb8440b | |||
| f4de7748f5 | |||
| 93c26a839b | |||
| 878e7441f2 | |||
| 27d387e3e1 | |||
| 7b7e4f60bc | |||
| 8bac111acf | |||
| 7a46d3b497 | |||
| 357aa92e31 | |||
| fa17f16716 | |||
| ce99c8c706 | |||
| be828cf004 | |||
| 1057bb15d3 | |||
| ea5e8891a8 | |||
| 57d83f082a | |||
| 8a3f80ba82 | |||
| 374ebd6f7a | |||
| ab2ebefe2b | |||
| c34a9f6213 | |||
| f5df41c75f | |||
| 0c2dc06cb7 | |||
| 4552ccd7d7 | |||
| 525bcd8295 | |||
| ac2ad8d8b5 | |||
| 14ce495e9e | |||
| 4aed2cf652 | |||
| 244fb0ca28 | |||
| f6e123f1ed | |||
| e1e4e7f011 | |||
| 814b6ff489 | |||
| 3aa17ab1f4 | |||
| 4646ed8f4a | |||
| 3f5c8acb3c | |||
| 93b257314a | |||
| 19a1db8cb4 | |||
| c3275a4aa9 | |||
| 927185d95c | |||
| a3df6c6f0c | |||
| e1fa977b5b | |||
| ce95f316b9 | |||
| a162af5a75 | |||
| fb0ea4610d | |||
| 4f86a9978b | |||
| cc78b880ce | |||
| 4336fdb241 | |||
| 87db7cf1d4 | |||
| 09ff802c7e | |||
| 71b59b1950 | |||
| a3300ad9c6 | |||
| 8f40d4affa | |||
| 560f3fcccb | |||
| ecaadf63c5 | |||
| d490a6e0b4 | |||
| 53ced205b8 | |||
| 61c4983949 | |||
| fb862f466f | |||
| 8d51300386 | |||
| c4b413563d | |||
| 8f852971f9 | |||
| 3c54c89464 | |||
| d07aa13822 | |||
| c218f7d0e3 | |||
| 72ad872e90 | |||
| 854f244d22 | |||
| 9acbb223db | |||
| c59fc687db | |||
| 0791b917f1 | |||
| ba182ce8e4 | |||
| 663291c515 | |||
| 99253eecea | |||
| 916a02cb36 | |||
| 114c4abcd1 | |||
| e1e3d11932 | |||
| df46217c78 | |||
| d18cc92396 | |||
| 8f63b4b790 | |||
| ce7de93936 | |||
| ef2a24fe6f | |||
| 038cd0155b | |||
| fb430ac1ed | |||
| 53cfa3703b | |||
| 7ed9e8d145 | |||
| 93e0b0cbea | |||
| 0118bd3168 | |||
| 07d5245a5f | |||
| 6b844213ec | |||
| dabdeb8a80 | |||
| ecd56315e6 | |||
| 15b9e839e9 | |||
| d7f7dcd47b | |||
| b1981e09b8 | |||
| c9edd0a795 | |||
| d83e0716bb | |||
| aed38afff3 | |||
| 1df522e6ec | |||
| bd4ef2354e | |||
| 32a49a6969 | |||
| 21806687e6 | |||
| 7ade91a091 | |||
| 4e41f96d89 | |||
| 325c32b4c9 | |||
| 7d6606a8e5 | |||
| c887d520eb | |||
| e6050fc558 | |||
| cae4853334 | |||
| 9ef2bebfe9 | |||
| 53294af810 | |||
| 7d21c815a5 | |||
| e07719a86c | |||
| fa5bee6ca3 | |||
| 3a43ef2c3f | |||
| 55deab03cd | |||
| edda84fefd | |||
| 10b191f631 | |||
| d5a575c5e0 | |||
| 82d8c3e2d9 | |||
| bc0c8dbcf3 | |||
| de0245ff40 | |||
| 7f56ff0281 | |||
| 2cfbf5411c | |||
| f70da1c82a | |||
| 0b4db49f57 | |||
| fbffd54aa2 | |||
| 4d19a33af2 | |||
| 9d67a0e656 | |||
| 093005bfd9 | |||
| 514883f0bd | |||
| 27681aad98 | |||
| 0d367da776 | |||
| c499a8a13a | |||
| 64a6de751d | |||
| d39f0d6ff0 | |||
| bdbfbf7300 | |||
| ccac3d2c3c | |||
| f07278490f | |||
| f1880fc53c | |||
| e8fe4a2dea | |||
| 1d79507665 | |||
| f05dc67887 | |||
| ca5e57c3b7 | |||
| 6b1fabdd92 | |||
| 35f0581c17 | |||
| c79f02fe48 | |||
| ec028a1c0d | |||
| e3155dd13a | |||
| b61254dda6 | |||
| b4bdf97cfe | |||
| bf98984012 | |||
| 77258cbbc9 | |||
| 4150455c3e | |||
| 008aacb5c2 | |||
| d12d6a6a46 | |||
| ef7594b8f7 | |||
| 6a73217740 | |||
| 47c44fca89 | |||
| 6fa63a5c35 | |||
| 29533908c2 | |||
| 74a1e9dee2 | |||
| b3662e07c1 | |||
| 200e0c58c9 | |||
| e67286c51d | |||
| 603622e337 | |||
| 5c2a435a25 | |||
| 4afcd722ae | |||
| 21d6964230 | |||
| 4499ccc501 | |||
| abbca568d1 | |||
| 40e49d0ac9 | |||
| 8d9a0a91f0 | |||
| 15640dfdf0 | |||
| 2f5dde5d2f | |||
| a9a8a04bca | |||
| c08e5ce62c | |||
| ec353e179d | |||
| 496f253e69 | |||
| e436115a4a | |||
| 1c61f93b5f | |||
| 0494f7d1fd | |||
| 4aa66338fc | |||
| 8cda844ef1 | |||
| dde1ef92f0 | |||
| 999f8b481f | |||
| 294951f22a | |||
| 2619737f64 | |||
| 445a90defb | |||
| d3d64f636c | |||
| eef072693b | |||
| 43c5f8d340 | |||
| b344d65302 | |||
| ce967f35ca | |||
| 80718cc783 | |||
| 73f22332ec | |||
| e963b6b65d | |||
| 327e90e8ec | |||
| 9253b764fa | |||
| 393aed6270 | |||
| b240d6a8fc | |||
| 3cda0643fb | |||
| 1ba63675d5 | |||
| 32f52f2d95 | |||
| 9215edc0a0 | |||
| 25ae21dae3 | |||
| 94393bef4b | |||
| 4f29183685 | |||
| edecf56dd6 | |||
| 08754bc626 | |||
| 702542f408 | |||
| 6990b371a6 | |||
| 8020d9045b | |||
| 34bb52a051 | |||
| a2e0bc267c | |||
| d86a95b5e1 | |||
| 585ed46034 | |||
| 82a4f80cd2 | |||
| f47a3968b7 | |||
| 0b592dd5c6 | |||
| addf6ade9a | |||
| d7d0429169 | |||
| 4bf5dc6646 | |||
| 5b20027f2e | |||
| 4499f71dba | |||
| 81b734c151 | |||
| 0b4a6b5362 | |||
| 3a0636046e | |||
| 52eccb29e4 | |||
| 86e4a935e2 | |||
| 1fa952b930 | |||
| 78e11bc6be | |||
| 40cc20e06e | |||
| c223f970ec | |||
| daa80dc949 | |||
| 255a78a534 | |||
| 6faa469bf5 | |||
| eeefac4964 | |||
| eb4770085a | |||
| 1ed63ce4f5 | |||
| e85ad95bcf | |||
| bd73c79787 | |||
| b244d506bd | |||
| 44f03865c0 | |||
| 72dfb4f11d | |||
| 6b0a4f20bf | |||
| f052aacee1 | |||
| 13e2ff8035 | |||
| 199e61e01c | |||
| 1bf6abf338 | |||
| c7b1d72bf0 | |||
| 0b3bdcb219 | |||
| 6653307fda | |||
| 642ba72a1d | |||
| 71144db09c | |||
| 395bd62663 | |||
| d8fd6430ed | |||
| 1e243281c7 | |||
| de23494409 | |||
| b23d3a9f37 | |||
| de31b90080 | |||
| ccc585ca1f | |||
| 4dbe81cb66 | |||
| d139d1d1bd | |||
| a186544fad | |||
| 7de152539d | |||
| 1e486a16bd | |||
| 7f9c24eedb | |||
| 8a3396deba | |||
| 96d5b37196 | |||
| 7b2e332f6c | |||
| ab541c1653 | |||
| 5f058f2ceb | |||
| 360381dd9f | |||
| cef4096b39 | |||
| a9c96c1afa | |||
| a446deaff3 | |||
| e5dd987d03 | |||
| 51fd8ae08c | |||
| 884540e565 | |||
| ca1313e891 | |||
| 8df18746fa | |||
| 40f829ce54 | |||
| e16b3e35f4 | |||
| 2f15e26ffa | |||
| b4cdbc6534 | |||
| 0a93ffd76b | |||
| 98e9848c4a | |||
| 42bb5fccb8 | |||
| fb921788b9 | |||
| 847c6b9aa2 | |||
| cafbcd4097 | |||
| a22539a91e | |||
| 89378c3883 | |||
| f763e1dc42 | |||
| ea13e3cec4 | |||
| 3d3302e547 | |||
| 95d81d02a1 | |||
| 8401a674c3 | |||
| 3fcf1a7723 | |||
| 1a3ee78459 | |||
| b99c499d2e | |||
| 709b388dfc | |||
| 6e83240233 | |||
| 202c235c66 | |||
| 576d773fec | |||
| 58a930e456 | |||
| 52206ce9d0 | |||
| 1de9d5683b | |||
| b66242db98 | |||
| 004ac88516 | |||
| 3d1eac234a | |||
| a78e52812f | |||
| 5993e6c791 | |||
| 1ec8b7c324 | |||
| e75002a96d | |||
| a68364d4d7 | |||
| 2b5e836a33 | |||
| 9caa9c39e5 | |||
| 096bdaba7a | |||
| d22c1f57e5 | |||
| dac00be7b5 | |||
| 4e7cb9b23f | |||
| 5fdee2cb5e | |||
| 1db3f3deab | |||
| b2af55ac63 | |||
| 40cdc285b6 | |||
| 46f017e68b | |||
| 1769ac2c2d | |||
| 067bdcda2d | |||
| 3bc1934966 | |||
| 6ee9a3a64c | |||
| c0196c97a5 | |||
| 96105d6ba0 | |||
| 853ba6079c | |||
| b6104c64fe | |||
| e95678cf3a | |||
| e2c21051aa | |||
| 7c575e1b43 | |||
| c89c253f29 | |||
| f54685e216 | |||
| 8141bcb3b6 | |||
| db3d21db49 | |||
| ca85c0ecf3 | |||
| 702db46f20 | |||
| 327d0bf5c5 | |||
| 2375296e67 | |||
| b4fcd2da14 | |||
| e3c92cce77 | |||
| 1141d34f07 | |||
| 354fe12742 | |||
| 1b19c66603 | |||
| d7077fc7db | |||
| d6bd4a0d67 | |||
| 8628c87be4 | |||
| fef822145d | |||
| cfefa7d579 | |||
| def115fe0f | |||
| 01a7c6f4e0 | |||
| 0e86cdeb4a | |||
| a65f888a77 | |||
| 71059e3ea3 | |||
| ee3faaad11 | |||
| d2aad34935 | |||
| d8ed34beba | |||
| 3154d37e41 | |||
| 272f30af53 | |||
| 4c6717e234 | |||
| 39b6562d14 | |||
| 0d966fe197 | |||
| 82f94b010f | |||
| 4555c541a8 | |||
| a853a51a0b | |||
| 756694c029 | |||
| 669f3b3984 | |||
| e7eed2abbe | |||
| 98a13cf487 | |||
| 7f9aa214a4 | |||
| 347a536a4e | |||
| 5cf0abaf2b | |||
| 09c6f025a1 | |||
| f47208528b | |||
| 87d90a65ac | |||
| 02cff8c72c | |||
| a67993ac0b | |||
| e540d25665 | |||
| 52c4dc49cf | |||
| 44ad70320a | |||
| 2b8e1c0b11 | |||
| 85a2ce9065 | |||
| a24aa79dbf | |||
| 633de85180 | |||
| f32d03eb88 | |||
| e83d63c2aa | |||
| ff30ba62ba | |||
| ea98444dc0 | |||
| 328c3a7d51 | |||
| 4b465bedea | |||
| 461ef2c68e | |||
| 46efdacd6d | |||
| a063cc1a53 | |||
| 36f2f5d52e | |||
| ddc99104d4 | |||
| 8d277e9108 | |||
| f305d57ab7 | |||
| 877f2e477b | |||
| c8e2fc0e57 | |||
| 4cb9cbb5ae | |||
| 6f3be56223 | |||
| c638c108d2 | |||
| d8f5aa680d | |||
| f2b585e446 | |||
| 78f91e0037 | |||
| 3f3c156697 | |||
| 4627bf5d1f | |||
| 93a144984a | |||
| 2d0784440c | |||
| 05a083437f | |||
| d4b5f59f92 | |||
| ff53fb6db0 | |||
| 534b3908cc | |||
| 7ea2369810 | |||
| 4d96ec10c1 | |||
| a37ee3457a | |||
| 6969bb9a5c | |||
| 4567041456 | |||
| 49f09e46da | |||
| becd027563 | |||
| 6eb1605be6 | |||
| 5c16aec096 | |||
| 835e2dc1fb | |||
| e2378ab29a | |||
| 0f1d7eb391 | |||
| dd358b8b95 | |||
| 21cf5fcaf4 | |||
| 8c7509759b | |||
| dc9ac0d0ff | |||
| 93b401ca9f | |||
| b137d8270a | |||
| 6db7757451 | |||
| 43fd42b757 | |||
| 5d1c4d2b9f | |||
| 425acd8bf6 | |||
| 414160e0df | |||
| 117c6aefe8 | |||
| 13d584d39a | |||
| 9bc89c24f5 | |||
| 5a8c4d5a4e | |||
| 98da83a552 | |||
| 5344a30a3b | |||
| d5d6b3673e | |||
| d2a2fe88d1 | |||
| ced44c86ce | |||
| ee402ad444 | |||
| 3d2155eb66 | |||
| bd24b03548 | |||
| 5cb55a0f37 | |||
| 163242f80f | |||
| 266bfcb8bf | |||
| d82fa02669 | |||
| 3a5207a0d2 | |||
| e38f3bb884 | |||
| 751cdd9b3b | |||
| 8df6bdca89 | |||
| f9df7545ad | |||
| 9b7a90afef | |||
| 2ae83b3247 | |||
| 5d907f234e | |||
| 3a005c4f13 | |||
| 6c2f50470a | |||
| d233783942 | |||
| 3d9e4c80a2 | |||
| a7f49015c1 | |||
| 68ed2631dc | |||
| 2814fea67e | |||
| 3388be9db6 | |||
| 9b89319820 | |||
| ad34089df5 | |||
| 7a4c6bc326 | |||
| 6ab386ae35 | |||
| 0abbfde912 | |||
| 0521defb63 | |||
| ea4d96610f | |||
| 4bc56564b4 | |||
| 013f7f09da | |||
| f082de1f92 | |||
| ad39dc8c0c | |||
| 481a76319f | |||
| 27a43d5aea | |||
| df1d5a0680 | |||
| 722109faf0 | |||
| d4dca7736a | |||
| 4e90becd52 | |||
| 26890e94eb | |||
| 55c83f9a59 | |||
| b837d82878 | |||
| cbdcdb1e0f | |||
| 4fea85289e | |||
| ba5f9132c9 | |||
| 991681daa2 | |||
| 2faf53e16b | |||
| 5430ed99de | |||
| fef4dfd05e | |||
| 05943db3b5 | |||
| 682fabd1ef | |||
| ee8ccc6d7e | |||
| 8ee0bcac2a | |||
| 0c4ad74788 | |||
| 7d944e4f1f | |||
| 67b2394c16 | |||
| 269d08a35f | |||
| f626e83e48 | |||
| 8ba18cd587 | |||
| 54c12fea89 | |||
| afb5ce71ce | |||
| 6fef6acf10 | |||
| a27411401b | |||
| 3718fc319b | |||
| c6c9463f8c | |||
| b410685318 | |||
| b742b29259 | |||
| df5d27ab61 | |||
| 2870155c0b | |||
| 9ba1075f48 | |||
| 4ae5b2e050 | |||
| 4369bd8f5e | |||
| 321b24a7b9 | |||
| 22e0c1fb54 | |||
| ba65e3c020 | |||
| c19ab952e3 | |||
| ecc29087b5 | |||
| 87e056de64 | |||
| 761200529f | |||
| 770351916e | |||
| 4b7d957b47 | |||
| a1c03c18a5 | |||
| 5d376b054f | |||
| 277d13c2bb | |||
| 4a9389d80a | |||
| 33593c13ae | |||
| eef82c18c2 | |||
| 7363580095 | |||
| 23a46b0597 | |||
| 51c79f294c | |||
| ce1e0e1873 | |||
| c2775b3b63 | |||
| bcb224d1cb | |||
| 8bc5f22866 | |||
| c3f2ef02c4 | |||
| 08e2c90d9d | |||
| d2bb2ba454 | |||
| ba912318cd | |||
| 3d1f057373 | |||
| 0679807517 | |||
| 7f0e4803e2 | |||
| fa76029a17 | |||
| 376c68957f | |||
| 222ec8d4b9 | |||
| 90715c1944 | |||
| 801e1b6059 | |||
| 14bb659b75 | |||
| eab3c50288 | |||
| 74396e7240 | |||
| 6c2539e886 | |||
| aba25d8521 | |||
| f0c97756de | |||
| f14c57d4c2 | |||
| b6f60cc8ad | |||
| 170516d343 | |||
| c931e91bef | |||
| db9151ae36 | |||
| f2d86b6d69 | |||
| 534cdd091b | |||
| fdf4a48638 | |||
| 58a3c5634e | |||
| f0ddb6e89f | |||
| 2b408db7cb | |||
| 4e4bd23e2b | |||
| 62d0eb606e | |||
| 0e9beeae14 | |||
| 5e4dbdee24 | |||
| 9435dae6cd | |||
| 813210bf47 | |||
| c372dfc544 | |||
| ac77200683 | |||
| f5afbc90a4 | |||
| b24760c819 | |||
| 6732957e42 | |||
| 1fd0006859 | |||
| 5a205346e3 | |||
| e193004659 | |||
| fe3a9c33d0 | |||
| d83116b88f | |||
| 5f56098ae7 | |||
| 0f935f4372 | |||
| df5c5a8c01 | |||
| 57a0c3bad8 | |||
| 2a52326a45 | |||
| 87e4ee1eeb | |||
| 45833eea9a | |||
| baf10e9b15 | |||
| 463a947df1 | |||
| cceebb4fd9 | |||
| afd5465a61 | |||
| fe604733de | |||
| da22f9f39f | |||
| 284ebbf75d | |||
| 2c08ccad87 | |||
| fa4e234bab | |||
| 35c4179ca1 | |||
| c14ba7ce34 | |||
| 601ce3add3 | |||
| 08ff39fd0b | |||
| 82a6ee3875 | |||
| 3bf592f870 | |||
| 241e205717 | |||
| fb2720ea8d | |||
| 14853befda | |||
| e7f2803d11 | |||
| 320015dd8f | |||
| 471c124a98 | |||
| aa44a109c6 | |||
| 41e5ca8422 | |||
| 53af8b2bb6 | |||
| bd885b135f | |||
| 62a6dde81a | |||
| 14b72b344f | |||
| ac03668063 | |||
| 2512e176c9 | |||
| b613393866 | |||
| 607a6e95de | |||
| 871f574ff7 | |||
| 377e470b15 | |||
| e0a3f0cea5 | |||
| 66727b2736 | |||
| 8215ad977f | |||
| a611dffbdf | |||
| 39f378d8cf | |||
| f00da58153 | |||
| 09b038b16d | |||
| cf601d97ad | |||
| 80edad53d4 | |||
| a972b32769 | |||
| efcaae3e60 | |||
| e0ee591638 | |||
| 310a6d909f | |||
| cefd8fc50f | |||
| a4422593f2 | |||
| e2c5d22756 | |||
| 84385d9dc3 | |||
| 6cfa4c8ab7 | |||
| c76ccc53e1 | |||
| d48eafb1a2 | |||
| 302d9b4b91 | |||
| a091a7f68b | |||
| 53621f6de3 | |||
| 288b965db3 | |||
| 578c9dcfc6 | |||
| 64de17b248 | |||
| d699dff872 | |||
| 501843d624 | |||
| 508ce4283e | |||
| 4aa8e66549 | |||
| 917a6f70d8 | |||
| 2f5e53da55 | |||
| c3cdefc90a | |||
| 9c580e4989 | |||
| dbc75f7352 | |||
| db841a8578 | |||
| 50c902c4e4 | |||
| 84b6e0bde6 | |||
| abc29c3fba | |||
| 8356c534f5 | |||
| 78ff2687b4 | |||
| 9b6586fb36 | |||
| ea133219d0 | |||
| c9b5d81a3c | |||
| d895c63211 | |||
| 8c86da67ca | |||
| a9a230dfc3 | |||
| 6d53e52771 | |||
| 52e10b7cfe | |||
| addac85696 | |||
| 13fb949d68 | |||
| f1b593cfbd | |||
| f998e2dec9 | |||
| 2c0bd53a91 | |||
| 6dd7f6162f | |||
| 475b0bb2b3 | |||
| e6343935e3 | |||
| 946883fd4c | |||
| b1b7e3148b | |||
| 32203f6438 | |||
| f2d3c5d2ed | |||
| 7e2f0ed4bc | |||
| a877acf905 | |||
| ac756ddf7e | |||
| 36e2236e6b | |||
| 72df665520 | |||
| 07785528a5 | |||
| bb579dd581 | |||
| a7d3064340 | |||
| 1a60778248 | |||
| cda4bb5bda | |||
| 7543781046 | |||
| 82f3ffad06 | |||
| dc4d2a1731 | |||
| 2523925915 | |||
| d5bbd8475c | |||
| 54d195268a | |||
| a0deb9509f | |||
| b0b1433594 | |||
| 17a2c0a37c | |||
| fd68ea1cc2 | |||
| 784874c776 | |||
| f45c6d3466 | |||
| 98af70902f | |||
| 41a67b5c4c | |||
| 83ee903af4 | |||
| e591b0e485 | |||
| bcc9a34742 | |||
| 6b56c7de7f | |||
| 7b42719699 | |||
| 64b8343f67 | |||
| fcc5089fa6 | |||
| 334f782aa8 | |||
| 1776f2bf77 | |||
| e259412f79 | |||
| 999a02f110 | |||
| 604d0fba65 | |||
| 0e8f7b870b | |||
| 1eebc9a46e | |||
| 0a94c80c44 | |||
| c70bb2fbd8 | |||
| 12c06b384f | |||
| 82a58e7ac3 | |||
| dcb56ef433 | |||
| 8da91de514 | |||
| 4b20685562 | |||
| fff7c5cc3a | |||
| 3065742b73 | |||
| ffd69ad1f2 | |||
| 9004011479 | |||
| 1046bb4133 | |||
| 5578505213 | |||
| a61f56662a | |||
| f42e48be03 | |||
| f640e101ba | |||
| b7da276ae0 | |||
| bf7c0989f5 | |||
| 65fdbe7f55 | |||
| c9af209a93 | |||
| 48ab44a776 | |||
| b2e684af8f | |||
| b38a2c11a4 | |||
| c31acef47a | |||
| e9a573e18a | |||
| c07ddc77f7 | |||
| 303fc992d4 | |||
| 4b7797f61b | |||
| f775d41933 | |||
| 7722e7bdfa | |||
| 346c05f0de | |||
| 73c69923b3 | |||
| afbca4bdf5 | |||
| b61371942b | |||
| 61c07e8876 | |||
| d317741144 | |||
| 275739a778 | |||
| cb3a43ed8a | |||
| ec8d1d8fc9 | |||
| 868a3186dd | |||
| 17b546181c | |||
| 2d1aa15af8 | |||
| 63ee94ff89 | |||
| 7d9dc08a38 | |||
| a836bdedb4 | |||
| 15ebae8cb1 | |||
| 315556310f | |||
| 9c0b26304b | |||
| acdaea9f6c | |||
| e481deb5bb | |||
| 6d3ac6074c | |||
| 5e611bde48 | |||
| 9448562156 | |||
| e7e8fe4d08 | |||
| 8320484b88 | |||
| 0e243e6f23 | |||
| 5cd25b0d21 | |||
| 3218ee7455 | |||
| 0552007b8a | |||
| 50bc89d9d9 | |||
| 743a88f53a | |||
| ee92c6dd99 | |||
| b6c54c17d1 | |||
| 992ef1ab74 | |||
| 960848ba34 | |||
| d9aca7a9df | |||
| 05a0de2d86 | |||
| 19e4f498cf | |||
| 3055139297 | |||
| 3d6b099dea | |||
| dd970e33b8 | |||
| 59ba479465 | |||
| 54c9ecf3c2 | |||
| 8308ae69a2 | |||
| bd6c3287ed | |||
| 24fc36deb1 | |||
| 2f44b61cec | |||
| 45ee503db1 | |||
| dc826da99b | |||
| 3ea659d582 | |||
| 34fc2831e0 | |||
| 1bf68a5aa0 | |||
| d72c397f23 | |||
| 2c69525148 | |||
| ee3a0ba801 | |||
| 7a4179a2a2 | |||
| 1d0083c5f4 | |||
| 33a6111a30 | |||
| a5d7a87e31 | |||
| c7f7c5b5ab | |||
| 55a7b99b4d | |||
| 8bfba604b3 | |||
| 2a5fa1c5fb | |||
| a3e95feb26 | |||
| 145b00f590 | |||
| 5f2785f0a8 | |||
| 412529c548 | |||
| 547ec6ade8 | |||
| eac513cfa3 | |||
| 5ec8a1f18c | |||
| c923a7e01a | |||
| 366e6ed105 | |||
| 52078eb666 | |||
| d9ddbff443 | |||
| 01b160f9a1 | |||
| 23fcb817a4 | |||
| f531a3f984 | |||
| c777023e9f | |||
| 62c99759c1 | |||
| 6951c21d19 | |||
| 3a8289483e | |||
| 4079de9587 | |||
| b86d171082 | |||
| 959b272e65 | |||
| 684440e2d1 | |||
| 4740cd3b06 | |||
| b3131d99d2 | |||
| b0fd2a67ea | |||
| 7c83869869 | |||
| 57d5c23eaf | |||
| 8d92b74e61 | |||
| 4e2cda99cc | |||
| dd250e0339 | |||
| 741b158631 | |||
| 843889303e | |||
| 4ad2b040b4 | |||
| f5916b5c59 | |||
| d9da4e9a08 | |||
| 1d0f6370ad | |||
| 12a7a4c4cf | |||
| e4127d961e | |||
| 8e97655040 | |||
| 9b61b87873 | |||
| 4a99e37b2f | |||
| 752b5e9b7c | |||
| b318f2fe94 | |||
| 01c46030b6 | |||
| 9803b05d8a | |||
| 1337858fe6 | |||
| 925b9e88ad | |||
| 7305011a8b | |||
| 489f23f74e | |||
| 370799ac55 | |||
| 4a9adb9440 | |||
| d8898b7a1f | |||
| bb7e081a37 | |||
| c3ffa5e0ef | |||
| 724bc2b59c | |||
| 178d2e2a48 | |||
| 4d710c129c | |||
| e4dbf62c0f | |||
| b0cd23fd34 | |||
| af5764bc3b | |||
| 6309da1214 | |||
| 38c9bfa357 | |||
| f194cb513c | |||
| 03ff892727 | |||
| 8cc0f64f54 | |||
| 532e8b0388 | |||
| 35b3d50012 | |||
| 72ff9996ce | |||
| 0759c4dd78 | |||
| 82a1a151e4 | |||
| ff6e8387fb | |||
| f71601e8d3 | |||
| 234a37726f | |||
| 65a7979874 | |||
| 6a00bf0fc0 | |||
| 853f3d6482 | |||
| 27de7cd914 | |||
| 2318cae1e6 | |||
| cb313c0fab | |||
| 4f25056017 | |||
| 5baebb8754 | |||
| 1eea994e73 | |||
| 8a597ff3f1 | |||
| 42fd7b12c0 | |||
| fd78a06b11 | |||
| 80efc8e086 | |||
| c0dcb886ef | |||
| df39128894 | |||
| 3ab5b57b4f | |||
| 49174d1731 | |||
| ed3b77b655 | |||
| 55a1aee164 | |||
| d7caf6686e | |||
| 71dad602ec | |||
| 30d8719c4b | |||
| ad81d38d07 | |||
| 6740b1b99c | |||
| f5f2cccbf4 | |||
| f45a1faa63 | |||
| 5a0dbe8cb7 | |||
| 2eb45e4699 | |||
| f7039a174a | |||
| 5690704444 | |||
| 8a8ffb6134 | |||
| 5b23dd8ffd | |||
| 5fc0c6b507 | |||
| c8e72092c7 | |||
| 9172948c18 | |||
| 2bec7c5e10 | |||
| 907ce6dbcd | |||
| 898000a580 | |||
| f95beed58b | |||
| 4baaa41ac9 | |||
| 1f7d349aed | |||
| c0d922560d | |||
| f5ded5e5e1 | |||
| 56d1720aae | |||
| 02d7102c68 | |||
| 592b32b036 | |||
| 1213997341 | |||
| 4e620f34ad | |||
| 534edaceac | |||
| ee13b4bf75 | |||
| 924006d508 | |||
| 350f34561a | |||
| 324fbb2f69 | |||
| 5539ab48a5 | |||
| c25157fc40 | |||
| d1b2950993 | |||
| d8995200e6 | |||
| bc389ab4a1 | |||
| cf12d09092 | |||
| 8e18adbe4c | |||
| f1b5e3de0c | |||
| 0e0a23b794 | |||
| d9329295d6 | |||
| 750fb862d4 | |||
| 131c19dee6 | |||
| 870ca4da0c | |||
| 54e1be1e77 | |||
| ce259eb4ec | |||
| 7424395171 | |||
| 6125df5834 | |||
| 99cd3148ba | |||
| 1a1ace0ae1 | |||
| 22bae559db | |||
| 5cee07ee8c | |||
| 4250f559b0 | |||
| 3293c39450 | |||
| 5b447d030b | |||
| f02680dc73 | |||
| cee7643f00 | |||
| a53ec62e4a | |||
| 795da31af8 | |||
| f70c29fea5 | |||
| decd8dbdc5 | |||
| edc954f2ac | |||
| 93bc86a0fe | |||
| 75b217fc24 | |||
| d6b44cc149 | |||
| 0f0ec4cf3d | |||
| 06ab84abe3 | |||
| bb5761e885 | |||
| d60a9763cd | |||
| e366c05238 | |||
| 690cdbe505 | |||
| fd701fc37c | |||
| 4d38baf7a2 | |||
| 7a999e01d5 | |||
| f3a5464306 | |||
| 2c57a37afb | |||
| 244b0f8efc | |||
| b4dc31e82b | |||
| 1583ede3d7 | |||
| 572994a17e | |||
| 796dd4c13a | |||
| e02f29e763 | |||
| 6805b02c63 | |||
| 21949ccd04 | |||
| 7b766f692b | |||
| c9aca86dcc | |||
| 99d9d49610 | |||
| fd98746c2b | |||
| 2efd234824 | |||
| 8be4304b5c | |||
| c984eba2bc | |||
| 2bb2a2a330 | |||
| f12163534d | |||
| e9d7c71911 | |||
| 59b3b0fadd | |||
| b426aba846 | |||
| 89885e17a5 | |||
| b66e9d2bed | |||
| d0f910d65f | |||
| 8e41aca8a7 | |||
| 4fec7760a1 | |||
| e6cbea9c70 | |||
| 7945f19285 | |||
| 5bd1269268 | |||
| 1fdd8a7611 | |||
| 112782d118 | |||
| b88b4a0578 | |||
| a964e19715 | |||
| c47166d700 | |||
| 77834f8166 | |||
| 0fc34e0a35 | |||
| df16f3d90d | |||
| ccd2f6ecdc | |||
| 19f1d31758 | |||
| ee2420cbcc | |||
| 322cf59a34 | |||
| 66841b1bb7 | |||
| 74ea419c53 | |||
| 0c8513801c | |||
| 90789aa5b9 | |||
| 1d13624d3d | |||
| 9e172549d1 | |||
| 0ba36c6f4e | |||
| c47093e82a | |||
| 57bdc102bc | |||
| be651f0138 | |||
| 974819bafb | |||
| f31a272b1f | |||
| a492c66321 | |||
| 85930161f7 | |||
| 4f9ece1ec1 | |||
| 748f004609 | |||
| cb709930bb | |||
| 98027cb008 | |||
| 3d8db17bc3 | |||
| 3c605ea809 | |||
| bd931c5cbd | |||
| c6e3a27284 | |||
| b5d7e7966f | |||
| be2da0fab1 | |||
| 0da50819d6 | |||
| 9f9265ad76 | |||
| a5ebbc34c7 | |||
| 33e32b20d9 | |||
| 238cd9f7f0 | |||
| bac25cdf29 | |||
| c15399613c | |||
| d6f7f1f4fb | |||
| a67dad8cbe | |||
| b549158483 | |||
| 9a2b03b183 | |||
| 2b2b4f46c2 | |||
| 6344928580 | |||
| 2dbf9b0d4a | |||
| be4d2679a4 | |||
| 70189a5ee2 | |||
| ad233c0d8e | |||
| 41c3db4c04 | |||
| 7f01f4b048 | |||
| 5ed5844490 | |||
| 777963c97c | |||
| 2f3d6f8dff | |||
| 2ae3924365 | |||
| d172aaefee | |||
| f0ea7bc53b | |||
| 793600ab2f | |||
| 354b4afba1 | |||
| 8569a74103 | |||
| b314972195 | |||
| 52179163dd | |||
| 8ed9f645fc | |||
| e1594cde2c | |||
| 60993d3123 | |||
| 39b2aaf489 | |||
| 58b04da60f | |||
| d9c020194d | |||
| ec586dd3cd | |||
| 8043216170 | |||
| 3c7372dff5 | |||
| 2cab018791 | |||
| 9467cda131 | |||
| 3382f1b084 | |||
| ae52ef5b78 | |||
| f88951546d | |||
| 7d90cd2a9e | |||
| 94a9db3d54 | |||
| 3f36d83bfb | |||
| c7e3370ac0 | |||
| bcb34dcd79 | |||
| 71905aa0c8 | |||
| dcbf115f25 | |||
| 668f2f9e2c | |||
| 530975b4fb | |||
| d35ce31af2 | |||
| e5f17cd694 | |||
| b50dea9c70 | |||
| 6b76032bb1 | |||
| 85b09eda56 | |||
| c4be78a81f | |||
| e7309f71d2 | |||
| 6c979c9419 | |||
| 7fd7732345 | |||
| 960ef4d945 | |||
| 92523fb4b5 | |||
| 66bb46df22 | |||
| 0454710d3b | |||
| c9a31cc987 | |||
| f03c316274 | |||
| 001a4f91be | |||
| 44a3bfe296 | |||
| a9ce6f808d | |||
| e5c667e0fa | |||
| e36f274dbe | |||
| 2a88427e74 | |||
| ed48f5f3ee | |||
| 7b4accb117 | |||
| d6437d31d4 | |||
| 3dd33f1f3c | |||
| 3a0f00411b | |||
| 5b655bb29a | |||
| faf10605e8 | |||
| c52aecdbd5 | |||
| 5c98b3350b | |||
| 6f4e1d10c1 | |||
| 870886599a | |||
| 1b9801b8a4 | |||
| 897463b22e | |||
| aa4894e94c | |||
| 8a0180ae6b | |||
| d6776b98d3 | |||
| 6a04ba89a5 | |||
| 05eaeeb0d0 | |||
| 77043464b2 | |||
| b90f74a821 | |||
| f804eb42ac | |||
| 74fd8c159b | |||
| a741ec1350 | |||
| 4b26c31b3b | |||
| dfd487692a | |||
| 195374ecee | |||
| 1659778a77 | |||
| 40c4035afb | |||
| 1502d65286 | |||
| 0feb672d70 | |||
| 2a4ef5bbf4 | |||
| c4540332a7 | |||
| 2104404cb3 | |||
| 002d685ebb | |||
| 9da10e2b25 | |||
| 1e4632080b | |||
| 5191106396 | |||
| 6ab5cafaf3 | |||
| d1c0cb9c71 | |||
| 38c750101c | |||
| ba0f379a89 | |||
| 1d9509b3b6 | |||
| 3c8de4a8ab | |||
| 591d8fc9ee | |||
| d480e9cea4 | |||
| 32a71869da | |||
| fdbfda64a6 | |||
| a6f48be39e | |||
| ce50b893e9 | |||
| 225ff27dd1 | |||
| 52e8361846 | |||
| 49e3bbc3d6 | |||
| c9ec911d0e | |||
| 84d7662fd8 | |||
| 676b2287ee | |||
| 32a64be407 | |||
| 138cddf3d6 | |||
| d730a3aac6 | |||
| ffb0b12012 | |||
| 78e25f8252 | |||
| 09f42f57e1 | |||
| 950ad1d060 | |||
| ed6b29c1a4 | |||
| 36785120b1 | |||
| 26fad5b888 | |||
| f049576575 | |||
| a7ecbb87e4 | |||
| 1da341741b | |||
| 2dd6192576 | |||
| 52c9347b9c | |||
| e2295591ed | |||
| 0c1cb724d7 | |||
| 7cee248426 | |||
| 6ea5b2b539 | |||
| a56b559d43 | |||
| df1a82e0e4 | |||
| f15a1efe71 | |||
| b8379fc6fa | |||
| d69cc74647 | |||
| f83874a9ca | |||
| 1968bb79c2 | |||
| 60c721db40 | |||
| 11b299653f | |||
| c8c07fe8ce | |||
| be0a4f08e9 | |||
| 4da4e28d07 | |||
| 9dc19026c6 | |||
| 31ca9f7fcb | |||
| 6925d39e8d | |||
| a24cafd975 | |||
| e3fdf8b404 | |||
| c861223378 | |||
| f5c6d8df71 | |||
| 452c846e90 | |||
| aedd875ab7 | |||
| d2ec2f8f02 | |||
| 5af0df93c3 | |||
| 5b4b5e1af7 | |||
| 21704c4ac2 | |||
| 71aff10092 | |||
| 4b390667e5 | |||
| 14dda3148d | |||
| 511dc9f805 | |||
| d0a14dcbcc | |||
| ec8dc2cdb0 | |||
| 6f1ef585be | |||
| d84acd0b82 | |||
| e1723ad3d5 | |||
| f77404afe1 | |||
| fbd7522748 | |||
| 90320fd26c | |||
| 4f9b474fdd | |||
| 4c921bdc09 | |||
| 93e0864063 | |||
| 80e2f23714 | |||
| 00496dbd09 | |||
| 54fb9a58d7 | |||
| 6b0ad22b19 | |||
| 17f40540ae | |||
| d337a500dc | |||
| cbe4e9edec | |||
| 402e88f866 | |||
| e0aed828e0 | |||
| 323facbdc8 | |||
| 2a61c858e4 | |||
| d216661f27 | |||
| 50dfee99b6 | |||
| 9e8ed9ac68 | |||
| 3a54554713 | |||
| fc113ce0c3 | |||
| f605f0b6c8 | |||
| 08788edfd3 | |||
| 4a0e19935f | |||
| a3454bb7a8 | |||
| 7245fa8ad7 | |||
| d771ff341d | |||
| 8171241666 | |||
| 1125e89b49 | |||
| 67fd5a060b | |||
| 4f60eda3ee | |||
| 6c62d75eae | |||
| bcfcf3d979 | |||
| b4497029db | |||
| 23ac4b846d | |||
| 691d04e994 | |||
| a54959ee4f | |||
| 76ebca8c55 | |||
| 786c4f147d | |||
| 7028fc7118 | |||
| 1c3210e789 | |||
| c28b804352 | |||
| 6d841c909b | |||
| e917fd28e0 | |||
| ab88459a56 | |||
| fe95c361be | |||
| 7e78546516 | |||
| d07b9450b1 | |||
| c30b431b7b | |||
| 0fe54fbd57 | |||
| 1bec19029f | |||
| 21ccf7757e | |||
| ceb766a124 | |||
| 046b789fa8 | |||
| cd50a1402f | |||
| 1b0ae5a827 | |||
| 01b6ca76e8 | |||
| 06b9c345c9 | |||
| 152276c1d7 | |||
| 275eedf076 | |||
| 5e959d65a2 | |||
| 66c1b89da2 | |||
| 78c68c7b9e | |||
| d914eae40a | |||
| 74f95f4d0d | |||
| d803052461 | |||
| 633e52c4be | |||
| 1512bcf808 | |||
| 4e46d088ca | |||
| 388c7ffd32 | |||
| 7ba8653935 | |||
| a4403aad1e | |||
| b629b78dba | |||
| f62c218735 | |||
| 725510028f | |||
| ad7927242d | |||
| 5692bdd229 | |||
| 3402746719 | |||
| 30a8414b06 | |||
| 9d46899ea7 | |||
| 58f14fd9ca | |||
| b6af14b13e |
@@ -0,0 +1,10 @@
|
|||||||
|
# editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
docs/**/*
|
||||||
|
_book/**/*
|
||||||
|
node_modules/**/*
|
||||||
|
test/**/*
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"browser": true,
|
||||||
|
"mocha": true
|
||||||
|
},
|
||||||
|
"globals": {
|
||||||
|
"expect": true
|
||||||
|
},
|
||||||
|
"extends": "gitbook"
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<!--
|
||||||
|
IMPORTANT NOTICE
|
||||||
|
Only post things related to the gitbook CLI
|
||||||
|
For GitBook.com, the Editor, or anything else
|
||||||
|
please go to
|
||||||
|
https://github.com/GitbookIO/feedback/issues
|
||||||
|
|
||||||
|
Please open separate issues for each bug report.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
### What is the current behavior?
|
||||||
|
|
||||||
|
<!--
|
||||||
|
- For bugs, provide the steps to reproduce
|
||||||
|
- Provide the GitBook version being used (`gitbook -V`)
|
||||||
|
- Provide system informations (OS and version)
|
||||||
|
- Provide your username and the URL of the book
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### What is the expected behavior?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Thank you for giving us your feedback!
|
||||||
|
-- The GitBook Team
|
||||||
|
-->
|
||||||
+10
-2
@@ -24,7 +24,15 @@ build/Release
|
|||||||
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
|
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
theme/javascript/vendors
|
|
||||||
|
|
||||||
# vim swapfile
|
# vim swapfile
|
||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
|
# GitBook with babel
|
||||||
|
/packages/gitbook-core/lib
|
||||||
|
/packages/gitbook-plugin/lib
|
||||||
|
|
||||||
|
# Output of documentation
|
||||||
|
_book
|
||||||
|
book.pdf
|
||||||
|
book.epub
|
||||||
|
book.mobi
|
||||||
|
|||||||
+12
-2
@@ -1,4 +1,14 @@
|
|||||||
|
sudo: false
|
||||||
language: node_js
|
language: node_js
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
node_js:
|
node_js:
|
||||||
- "0.11"
|
- "stable"
|
||||||
- "0.10"
|
- "4.1"
|
||||||
|
before_install:
|
||||||
|
- npm install svgexport -g
|
||||||
|
before_script:
|
||||||
|
- npm run bootstrap
|
||||||
|
after_success:
|
||||||
|
- npm run lint
|
||||||
|
|||||||
+55
-5
@@ -7,12 +7,62 @@ Names below are ordered by first contribution.
|
|||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
|
||||||
- Samy Pessé <samypesse@gmail.com>
|
- Samy Pessé <samy@gitbook.com> (@SamyPesse)
|
||||||
- Aaron O'Mullan <aaron.omullan@gmail.com>
|
- Aaron O'Mullan <aaron@gitbook.com> (@AaronO)
|
||||||
|
- Johan Preynat <johan@gitbook.com> (@jpreynat)
|
||||||
|
- Nicolas Gaborit <nicolas@gitbook.com> (@soreine)
|
||||||
|
|
||||||
Contributors
|
Contributors
|
||||||
------------
|
------------
|
||||||
|
|
||||||
- Nijiko Yonskai
|
- Nijiko Yonskai (@Nijikokun)
|
||||||
- Herman Starikov
|
- Herman Starikov (@Hermanya)
|
||||||
|
|
||||||
|
Translators
|
||||||
|
------------
|
||||||
|
|
||||||
|
- German
|
||||||
|
- Winnie (@winniehell)
|
||||||
|
- Italian
|
||||||
|
- Giulio Bonanome (@gbonanome)
|
||||||
|
- Russian
|
||||||
|
- Andrey Akinshin (@AndreyAkinshin)
|
||||||
|
- Norwegian
|
||||||
|
- Knut Melvær (@kmelve)
|
||||||
|
- Persian (Farsi)
|
||||||
|
- Mohammad Hossein Mojtahedi (@mhm5000)
|
||||||
|
- Polish
|
||||||
|
- Łukasz Szeremeta (@lszeremeta)
|
||||||
|
- Portuguese
|
||||||
|
- Ryan O'Mullan (@RyanOM)
|
||||||
|
- Spanish
|
||||||
|
- Ryan O'Mullan (@RyanOM)
|
||||||
|
- Simplifiled Chinese
|
||||||
|
- Hu Hao (@howiehu)
|
||||||
|
- Traditional Chinese
|
||||||
|
- Hu Hao (@howiehu)
|
||||||
|
- French
|
||||||
|
- Samy Pessé (@SamyPesse)
|
||||||
|
- Romanian
|
||||||
|
- Iancu Aurel (@awrelll)
|
||||||
|
- Finnish
|
||||||
|
- Tommi Savikko (@savikko)
|
||||||
|
- Japanese
|
||||||
|
- Iancu Aurel (@awrelll)
|
||||||
|
- Korean
|
||||||
|
- Iancu Aurel (@awrelll)
|
||||||
|
- SangYeob Yu (@deminoth)
|
||||||
|
- Vietnamese
|
||||||
|
- Hong Nguyen (@nghong)
|
||||||
|
- Hebrew
|
||||||
|
- @a-moses
|
||||||
|
- Ukrainian
|
||||||
|
- @Karnaukhov
|
||||||
|
- Czech
|
||||||
|
- @mjanda
|
||||||
|
- Swedish
|
||||||
|
- Jacob Burenstam (@buren)
|
||||||
|
- Turkish
|
||||||
|
- Turan Konan (@turankonan)
|
||||||
|
- Catalan
|
||||||
|
- Esaú García Sánchez-Torija (@egasato)
|
||||||
|
|||||||
+387
@@ -1,4 +1,391 @@
|
|||||||
# Release notes
|
# Release notes
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## 4.0.0
|
||||||
|
- **Breaking Changes:** Most plugins and themes should be incompatible with this version
|
||||||
|
- GitBook rendering is now done using React, which brings better APIs for plugins and a more interactive website.
|
||||||
|
- *Performances*: Installation of plugins is much faster thanks to `ied`
|
||||||
|
- *Performances*: Git conrefs are faster over large books
|
||||||
|
- *Website Feature:* new default plugin `copy-code` to copy code blocks content in one click
|
||||||
|
- *Website Feature:* new default plugin `heading-anchors` to have clickable headings
|
||||||
|
- *Website Feature:* `fontsettings` is now only controlling the font size, and can work on multiple themes
|
||||||
|
- *Plugin API*: hook `page` can no longer modify the content, only the page's attributes
|
||||||
|
- *Plugin API*: plugins can no longer export resources, instead use the `_assets` folder
|
||||||
|
- [ ] *Plugin API*: testing framework
|
||||||
|
- [ ] `gitbook init` creates `.gitignore` if not found
|
||||||
|
- [ ] Ignore files are no longer copied to the output
|
||||||
|
|
||||||
|
## 3.2.2
|
||||||
|
- Fix catching parsing errors leading to possible missing pages in generated book
|
||||||
|
- Rollback markdown parser to `kramed` until `markup-it` is stable enough
|
||||||
|
|
||||||
|
## 3.2.1
|
||||||
|
- Fix bug on Firefox when navigating to an url containing an hash
|
||||||
|
- Update nunjucks to fix JS error when page contains a lot of templating blocks
|
||||||
|
|
||||||
|
## 3.2.0
|
||||||
|
- Switch markdown parser from `kramed` to `markup-it`
|
||||||
|
- Fix support of `|` in tables
|
||||||
|
- Fix access to `output.name` in templating
|
||||||
|
- Fix i18n for website and PDF
|
||||||
|
- Fix minor scrolling issues on website
|
||||||
|
- Improve options of default search indexer (keywords, disabling per pages)
|
||||||
|
- Improve pertinence of search results
|
||||||
|
|
||||||
|
## 3.1.1
|
||||||
|
- Fix order of plugins during loading
|
||||||
|
- Fix error when using math and conrefs
|
||||||
|
- Fix target attribute for external links
|
||||||
|
- Fix serve command
|
||||||
|
|
||||||
|
## 3.1.0
|
||||||
|
- Always load themes after plugins
|
||||||
|
- README/Introduction doesn't require to be the first entry in the summary
|
||||||
|
- Highlight active entry in summary when scrolling a page with anchors
|
||||||
|
- Support empty parts in summary
|
||||||
|
|
||||||
|
## 3.0.3
|
||||||
|
- Fix redirection in `gitbook serve` when accessing a folder without trailing slash
|
||||||
|
- Fix links/annotations for glossary not being correctly resolved
|
||||||
|
- Fix regression for supporting uppercase filenames in structure files
|
||||||
|
- Fix `gitbook install` when using Git URLs for plugins
|
||||||
|
|
||||||
|
## 3.0.2
|
||||||
|
- Fix crash for anchor links
|
||||||
|
|
||||||
|
## 3.0.1
|
||||||
|
- Fix regression in link resolution when contain anchor
|
||||||
|
- Fix `structure.<name>` configuration not supporting filenames with dots
|
||||||
|
|
||||||
|
## 3.0.0
|
||||||
|
- Summary can contain external links and anchors (Fix [#776](https://github.com/GitbookIO/gitbook/issues/776))
|
||||||
|
- Summary can contain differents entitled sections
|
||||||
|
- Glossary is generated as a normal page
|
||||||
|
- Headings are no longer annotated with glossary terms
|
||||||
|
- Themes are now published as a plugin, with ability to extend it from the book source
|
||||||
|
- `links.sidebar` configuration is no longer supported, use summary sections instead
|
||||||
|
- `pdf.headerTemplate` and `pdf.footerTemplate` have been replaced by a template in theme/book: `_layout/ebook/pdf_header.html` and `_layout/ebook/pdf_footer.html`
|
||||||
|
- Markdown parser is now using CommonMark
|
||||||
|
- Root folder for the book can be specified in the `"root"` property of the `book.json` file
|
||||||
|
- Multi-lingual books share assets folder
|
||||||
|
- YAML front matter is parsed and can extend page's properties
|
||||||
|
- Fix `uk` translation
|
||||||
|
- Fix heading ID including dashes
|
||||||
|
- Fix error in code highlighting for unknown languages
|
||||||
|
- Fix data-uri images being handled as external images
|
||||||
|
- Accept SSH url as plugin version
|
||||||
|
- Add templating blocks `markdown`, `asciidoc` and `markup`
|
||||||
|
- Better search experience
|
||||||
|
- Better default theme, more responsive and cleaner
|
||||||
|
|
||||||
|
## 2.6.7
|
||||||
|
- Fix bug with filenames including spaces
|
||||||
|
- Add Turkish and Catalan translations
|
||||||
|
|
||||||
|
## 2.6.6
|
||||||
|
- Fix custom CSS that are generated by plugins for PDF output
|
||||||
|
|
||||||
|
## 2.6.5
|
||||||
|
- Fix support for plugins generating custom stylesheets (`styles-less` and `styles-sass`)
|
||||||
|
- Fix glossary terms being replaced in script (ex: math)
|
||||||
|
|
||||||
|
## 2.6.4
|
||||||
|
- Fix regression introduced by `2.6.3` of single HTML tags in markdown
|
||||||
|
|
||||||
|
## 2.6.3
|
||||||
|
- Fix parsing bug with inline HTML in Markdown
|
||||||
|
|
||||||
|
## 2.6.2
|
||||||
|
- Fix `gitbook.state.bookRoot`, `gitbook.state.root` now has a trailing slash
|
||||||
|
- Update nunjucks to 2.2.0
|
||||||
|
|
||||||
|
## 2.6.1
|
||||||
|
- Use CamelCase for `gitbook.state.innerLanguage`
|
||||||
|
|
||||||
|
## 2.6.0
|
||||||
|
- Close sidebar after clicking a link on mobile
|
||||||
|
- Add root for multilingual books: `gitbook.state.bookRoot`
|
||||||
|
- Fix color of h6 headings
|
||||||
|
- Fix bottom margin of lists and blockquotes
|
||||||
|
- Add Swedish translation (`sv`)
|
||||||
|
- Add Czech translation (`cs`)
|
||||||
|
- Fix locale names for `zh-hans` and `jp`
|
||||||
|
- Update plugin `search` to fix crashes
|
||||||
|
- Aceept case-incensitive structure files (README, GLOSSARY, etc)
|
||||||
|
|
||||||
|
## 2.5.2
|
||||||
|
- Fix custom stylesheets for ebook generation
|
||||||
|
- Trigger event `start` before `page.change`
|
||||||
|
|
||||||
|
## 2.5.1
|
||||||
|
- Fix calcul of `gitbook.state.root` when serving HTML index as `/`
|
||||||
|
|
||||||
|
## 2.5.0
|
||||||
|
- Font settings, sharing and search are externalized as default plugins
|
||||||
|
- Plugins can define a configuration schema in the manifest, this schema will be used to validate configuration during build
|
||||||
|
- New Node.js API for plugin: `book.formatString(type, content)`
|
||||||
|
- New client side API for website plugins: `gitbook.toolbar.createButton(opts)`
|
||||||
|
- Better header/footer for PDF, CSS wil be inlined to easily style the header/footer
|
||||||
|
- Cleaner table of contents for ebooks
|
||||||
|
- Support for RTL in ebook's table of contents
|
||||||
|
- Better colors for mobi (links and code blocks)
|
||||||
|
- Fix installation of plugins when using a pre-release
|
||||||
|
- Fix support for pre-releases
|
||||||
|
- Update asciidoc parser to remove git dependency
|
||||||
|
- Fix templating in imported content
|
||||||
|
- Fix querystring in image urls
|
||||||
|
- Normalize heading IDs like GitHub
|
||||||
|
- Use Arial as default font for PDFs
|
||||||
|
- Add `root`, `chapterTitle` and `filepath` to `gitbook.state` JS API
|
||||||
|
|
||||||
|
## 2.4.3
|
||||||
|
- Add ukrainian translation (`uk`)
|
||||||
|
- Add `book.json` configuration for maximum size of search index
|
||||||
|
- Improve reliability of summary parser
|
||||||
|
|
||||||
|
## 2.4.2
|
||||||
|
- Default plugins should not be installed by `gitbook install`
|
||||||
|
- Limit search index size to avoid crash during generation
|
||||||
|
- Fix code highlighting for html without language specified
|
||||||
|
- Fix warning message for gitbook version when building a multilingual book
|
||||||
|
|
||||||
|
## 2.4.1
|
||||||
|
- Fix disabling of default plugins, ex: `-highlight`
|
||||||
|
|
||||||
|
## 2.4.0
|
||||||
|
- Fix page being updated when user wants to open a link in a new tab
|
||||||
|
- Plugins can now replaced default code highlighter
|
||||||
|
- Add semantic information for screen readers (web version)
|
||||||
|
- Content references accept absolute paths, resolved to book folder
|
||||||
|
- Improve overall reliability
|
||||||
|
|
||||||
|
## 2.3.3
|
||||||
|
- Fix bug in SUMMARY parsing preventing multiple entries without filenames
|
||||||
|
|
||||||
|
## 2.3.2
|
||||||
|
- Fix blocks (like maths) in Asciidoc
|
||||||
|
- Fix error when checking gitbook version
|
||||||
|
|
||||||
|
## 2.3.1
|
||||||
|
- Fix black font color for ebooks (mobi, pdf and epub)
|
||||||
|
- Fix ISO code for korean language
|
||||||
|
- Fix korean translation
|
||||||
|
- Fix syntax highlighting for asciidoc
|
||||||
|
- Fix inline html escaping in markdown
|
||||||
|
- Add warning for file outside SUMMARY
|
||||||
|
- Force SUMMARY entries to be unique by filename
|
||||||
|
|
||||||
|
## 2.3.0
|
||||||
|
- Fix nunjucks issue with multiple `{% raw %}` blocks
|
||||||
|
- Fix crash when git conref failed
|
||||||
|
- Fix crash when failed to download remote image (better error message)
|
||||||
|
- Fix flicking effect when changing page (big UX improvement)
|
||||||
|
- Add Hebrew translation (`he`)
|
||||||
|
- Add utility method `book.config.get` for plugins
|
||||||
|
- Hooks `page:before` and `page` are no longer deprecated
|
||||||
|
- Remove webfonts to make website lighter
|
||||||
|
- Make glossary's order case insensitive
|
||||||
|
|
||||||
|
## 2.2.0
|
||||||
|
- Fix direction in code blocks (always LTR)
|
||||||
|
- Add options `chapterMark` and `pageBreaksBefore` for PDF
|
||||||
|
- Update code highlighting library
|
||||||
|
- `book.json` accessible as `config` in templating syntax
|
||||||
|
- Add Vietnamese translation (`vi`)
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
- Fix error in calcul of `levels` in table of contents, error introduced a few versions ago
|
||||||
|
- Add optional `styles/print.css` to replace `print.css` used in ebook
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
- Fix `{% raw %}`, got confused with "fake" variable declarations
|
||||||
|
- Fix title of language chooser
|
||||||
|
- Fix the X-UA-Compatible meta tag
|
||||||
|
- Move style sheets to the <head> section
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
- Fix `gitbook init` for SUMMARY with empty entries
|
||||||
|
- Fix escaping of code blocks in markdown
|
||||||
|
|
||||||
|
## 2.0.2
|
||||||
|
- Fix relative links in windows
|
||||||
|
- Improve watcher in serve command (switch to chokidar)
|
||||||
|
- Add Romanian translation (`ro`)
|
||||||
|
- Add Finish translation (`fi`)
|
||||||
|
- Add Japanese translation (`jp`)
|
||||||
|
- Add Korean translation (`kr`)
|
||||||
|
|
||||||
|
## 2.0.1
|
||||||
|
- Improve error logging (display file, line and column)
|
||||||
|
- Add back support for `options.originalInput`
|
||||||
|
- Don't process math in markdown parser (delegated to `mathjax` plugin)
|
||||||
|
- Fix some cases of code blocks escaping
|
||||||
|
- Fix i18n for introduction title in json format
|
||||||
|
- Fix reload when book configuration is updated
|
||||||
|
- Fix backslashes in url when building on windows
|
||||||
|
|
||||||
|
## 2.0.0
|
||||||
|
- Fix page title of introduction
|
||||||
|
- Ignore codeblocks when replacing glossary terms
|
||||||
|
- Improve Unit Tests
|
||||||
|
- Fix scrolling position in website when preparing page
|
||||||
|
|
||||||
|
## 2.0.0-beta.5
|
||||||
|
- Fix progress order in json format
|
||||||
|
|
||||||
|
## 2.0.0-beta.4
|
||||||
|
- Fix default generator for use programmatically
|
||||||
|
- Add option "author" for html meta tags
|
||||||
|
- Fix links normalization (content and hash)
|
||||||
|
|
||||||
|
## 2.0.0-beta.3
|
||||||
|
- Fix odd cases with code blocks escaping
|
||||||
|
|
||||||
|
## 2.0.0-beta.2
|
||||||
|
- Fix definition of entry point title using SUMMARY.md
|
||||||
|
|
||||||
|
## 2.0.0-beta.1
|
||||||
|
- Fix windows incompatibility
|
||||||
|
- Add support for rtl (enabled by default for `ar` and `fa`)
|
||||||
|
- Escape code blocks in markdown parser
|
||||||
|
- Add Persian/Farsi translation (`fa`)
|
||||||
|
- Add Arabic translation (`ar`)
|
||||||
|
- Add Bengali translation (`bn`)
|
||||||
|
- Provide generator name in template context
|
||||||
|
|
||||||
|
## 2.0.0-alpha.9
|
||||||
|
- Fix links in sidebar
|
||||||
|
- Fix normalization of html link (README to index)
|
||||||
|
- Fix html snippets escaping
|
||||||
|
|
||||||
|
## 2.0.0-alpha.8
|
||||||
|
- Improve locale detection for i18n
|
||||||
|
- Fix chapter name for Glossary in pdf
|
||||||
|
- Don't escape html in glossary items
|
||||||
|
- Fix generation of multilingual book as ebook
|
||||||
|
- Add "post" block attribute to post-process
|
||||||
|
|
||||||
|
## 2.0.0-alpha.7
|
||||||
|
- Fix display of glossary in ebook formats
|
||||||
|
- Add default footer and header to pdf
|
||||||
|
- Fix generation of json format compatible with 1.x.x
|
||||||
|
- Add Simplifiled Chinese and Traditional Chinese translations
|
||||||
|
|
||||||
|
## 2.0.0-alpha.6
|
||||||
|
- Add es and pt translations
|
||||||
|
- Fix replacement of glossary terms
|
||||||
|
|
||||||
|
## 2.0.0-alpha.5
|
||||||
|
- Fix copy of files/covers
|
||||||
|
- Add back `finish:before` hook
|
||||||
|
|
||||||
|
## 2.0.0-alpha.4
|
||||||
|
- Fix copy of cover for multilingal books
|
||||||
|
|
||||||
|
## 2.0.0-alpha.3
|
||||||
|
- Norwegian translation
|
||||||
|
- Load plugins from book in priority
|
||||||
|
|
||||||
|
## 2.0.0-alpha.3
|
||||||
|
- Fix init command
|
||||||
|
- Update parsers to fix spaces in summary (`gitbook-parsers@0.3.1`)
|
||||||
|
|
||||||
|
## 2.0.0-alpha.1
|
||||||
|
- Externalize parsing into `gitbook-parsers` module
|
||||||
|
- Supports AsciiDoc and reStructuredText
|
||||||
|
- Hooks for page (`page:*`) are now deprecated, plugins should extend filters and blocks instead
|
||||||
|
- Hooks `summary` and `glossary` (after and before) have been removed
|
||||||
|
- Exercises and Quizzes are no longer parsed in the markdown parser
|
||||||
|
- Support for more markdown extensions: `.markdown`, `.mdown`
|
||||||
|
- Templates are rendered with nunjucks instead of swig, syntax is almost compatible, there is some changes with contexts and filters. `{{ super() }}` should be use instead of `{% parent %}`
|
||||||
|
- Clean output folder on build without removing `.git` and `.svn`
|
||||||
|
- MathJAX is no longer a default plugin
|
||||||
|
- SVG images are converted to PNG during generation of ebooks
|
||||||
|
- i18n in website and ebook (ru, it, de, fr)
|
||||||
|
- New templating syntax
|
||||||
|
- Content references (both internal and external)
|
||||||
|
- Glossary terms are handled during generation (also in ebook format)
|
||||||
|
|
||||||
|
## 1.5.0
|
||||||
|
- Fix `serve` command, broken by `1.4.2`
|
||||||
|
- Add nicer `dark` theme :)
|
||||||
|
|
||||||
|
## 1.4.2
|
||||||
|
- Force `process.exit` after builds, to prevent (possibly) lingering plugins
|
||||||
|
|
||||||
|
## 1.4.1
|
||||||
|
- Fix command 'install' without arguments
|
||||||
|
|
||||||
|
## 1.4.0
|
||||||
|
- Add command `gitbook install` to install plugins from book.json
|
||||||
|
- `package.json` is no longer necessary
|
||||||
|
|
||||||
|
## 1.3.4
|
||||||
|
- Add glossary to ebooks
|
||||||
|
- Fix autocover with new hook "finish:before"
|
||||||
|
- Add X-UA-Compatible meta tag for IE
|
||||||
|
|
||||||
|
## 1.3.3
|
||||||
|
- Fix parsing of lexed content using the client library
|
||||||
|
|
||||||
|
## 1.3.2
|
||||||
|
- ePub files are now passing validation from epubcheck
|
||||||
|
- Fix replacement of multiple glossary terms in a single sentence
|
||||||
|
- Fix on windows deep relative links
|
||||||
|
- Fix search indexer
|
||||||
|
|
||||||
|
## 1.3.1
|
||||||
|
- Fix error with links in markdown
|
||||||
|
|
||||||
|
## 1.3.0
|
||||||
|
- Bundle gitbook parsing library as a client side library in `gitbook.js` and `gitbook.min.js`
|
||||||
|
|
||||||
|
## 1.2.0
|
||||||
|
- Improvements on ebook generation
|
||||||
|
- Fix incorrect follow of links in ebook generation
|
||||||
|
- Move Table of Contents at the beginning of the ebook
|
||||||
|
- Update to last highlight.js (includes Swift)
|
||||||
|
- Includes of templates and variables (from book.json)
|
||||||
|
|
||||||
|
## 1.1.1
|
||||||
|
- Rewrite quiz logic to be more robust
|
||||||
|
- Improve integration of glossary
|
||||||
|
- Improve generation of ebook by using a multiple HTML pages input source
|
||||||
|
- Fix incorrect page breaks after h1 and h2 divs
|
||||||
|
- New options to set header and footer in PDF generation
|
||||||
|
|
||||||
|
## 1.1.0
|
||||||
|
- Plugins can now extend the ebook generation (pdf, epub, mobi)
|
||||||
|
- Update `kramed` to version 0.4.3
|
||||||
|
|
||||||
|
## 1.0.3
|
||||||
|
- Update `mathjax` plugin and MathJAx to version 2.4
|
||||||
|
- Update `highlight.js` to 8.2.0
|
||||||
|
|
||||||
|
## 1.0.2
|
||||||
|
- Update `mathjax` plugin, fixes issues with inline math rendering (no longer wanted)
|
||||||
|
|
||||||
|
## 1.0.1
|
||||||
|
- New inline math convention (kramdown's), using `$$` rather than `$` as delimiters
|
||||||
|
- Fix instapaper sharing
|
||||||
|
- The `exercises` & `quizzes` plugins are now by default
|
||||||
|
|
||||||
|
## 1.0.0
|
||||||
|
- New design
|
||||||
|
- Support for glossary
|
||||||
|
- Support for sharing to instapaper
|
||||||
|
- Support for footnotes
|
||||||
|
|
||||||
|
## 0.7.1
|
||||||
|
- Update `fs-extra` to `0.10.0` (fixes potential race conditions)
|
||||||
|
|
||||||
|
## 0.7.0
|
||||||
|
- Add page break in ebook (pdf, epub, mobi) between chapters/articles
|
||||||
|
- Start using kramed instead of marked
|
||||||
|
- Fix display of inline math
|
||||||
|
- Switch to graceful-fs to fix EMFILE errors
|
||||||
|
- Add sharing to weibo.com
|
||||||
|
|
||||||
## 0.6.2
|
## 0.6.2
|
||||||
- Support generating a plugin's book info dynamically
|
- Support generating a plugin's book info dynamically
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Want to contribute to GitBook? That would be awesome!
|
||||||
|
|
||||||
|
- [Send feedback](#send-feedback)
|
||||||
|
- [Reporting Bugs](#reporting-bugs)
|
||||||
|
- [Asking Questions](#asking-questions)
|
||||||
|
- [Submitting Pull Requests](#submitting-pull-requests)
|
||||||
|
- [Running Tests](#running-tests)
|
||||||
|
|
||||||
|
## Send feedback
|
||||||
|
|
||||||
|
We’ve done our best to test but your feedback is really important. If you encounter problems or have feedback about GitBook products (GitBook.com, GitBook Editor, or the Toolchain), please log an issue in the [GitbookIO/feedback](https://github.com/GitbookIO/feedback/issues) repository.
|
||||||
|
|
||||||
|
|
||||||
|
## Reporting Bugs
|
||||||
|
|
||||||
|
If you run into any weird behavior while using GitBook, feel free to open a new issue in this repository! To be most helpful, please include the steps to reproduce the bug as best you can, including the output of command `gitbook -V`.
|
||||||
|
|
||||||
|
## Asking Questions
|
||||||
|
|
||||||
|
Questions are very welcome :smile:! Previous questions that folks have asked are tagged with a [`question`](https://github.com/GitBookIO/gitbook/issues?q=is%3Aissue+is%3Aclosed+label%3Aquestion) label, so before opening a new issue double-check that someone hasn't asked it before. But if you don't see anything, or if you're not sure if it's the same, err on the side of asking!
|
||||||
|
|
||||||
|
We've also got a [GitBook Community Slack](https://slack.gitbook.com/) where you can ask questions and get answers from other people using GitBook.
|
||||||
|
|
||||||
|
## Submitting Pull Requests
|
||||||
|
|
||||||
|
All pull requests are super welcomed and greatly appreciated! Easy issues are marked with an [`easy-one`](https://github.com/GitBookIO/gitbook/issues?q=is%3Aopen+is%3Aissue+label%3Aeasy-one) label if you're looking for a simple place to get familiar with the code base.
|
||||||
|
|
||||||
|
Please include tests and docs with every pull request!
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
To run the examples, you need to have the GitBook repository cloned to your computer. After that, you need to `cd` into the directory where you cloned it, and install the dependencies from `npm` using `yarn`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you'll need to bootstrap it:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm run bootstrap
|
||||||
|
```
|
||||||
|
|
||||||
|
Which will also compile the source files. Then run the tests with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm test
|
||||||
|
```
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
module.exports = function (grunt) {
|
|
||||||
var path = require("path");
|
|
||||||
|
|
||||||
// Load NPM tasks
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-less');
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-requirejs');
|
|
||||||
grunt.loadNpmTasks("grunt-bower-install-simple");
|
|
||||||
|
|
||||||
// Init GRUNT configuraton
|
|
||||||
grunt.initConfig({
|
|
||||||
pkg: grunt.file.readJSON('package.json'),
|
|
||||||
'bower-install-simple': {
|
|
||||||
options: {
|
|
||||||
color: true,
|
|
||||||
production: false,
|
|
||||||
directory: "theme/javascript/vendors"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
less: {
|
|
||||||
development: {
|
|
||||||
options: {
|
|
||||||
compress: true,
|
|
||||||
yuicompress: true,
|
|
||||||
optimization: 2
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
"theme/assets/style.css": "theme/stylesheets/website.less",
|
|
||||||
"theme/assets/print.css": "theme/stylesheets/ebook.less"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
requirejs: {
|
|
||||||
compile: {
|
|
||||||
options: {
|
|
||||||
name: "gitbook",
|
|
||||||
baseUrl: "theme/javascript/",
|
|
||||||
out: "theme/assets/app.js",
|
|
||||||
preserveLicenseComments: false,
|
|
||||||
optimize: "uglify", //"uglify",
|
|
||||||
include: ["requireLib"],
|
|
||||||
paths: {
|
|
||||||
"jQuery": 'vendors/jquery/dist/jquery',
|
|
||||||
"lodash": 'vendors/lodash/dist/lodash',
|
|
||||||
"requireLib": 'vendors/requirejs/require',
|
|
||||||
"Mousetrap": 'vendors/mousetrap/mousetrap',
|
|
||||||
"lunr": 'vendors/lunr.js/lunr',
|
|
||||||
"URI": 'vendors/URIjs/src/URI',
|
|
||||||
"ace": 'vendors/ace-builds/src-noconflict/'
|
|
||||||
},
|
|
||||||
shim: {
|
|
||||||
'jQuery': {
|
|
||||||
exports: '$'
|
|
||||||
},
|
|
||||||
'lodash': {
|
|
||||||
exports: '_'
|
|
||||||
},
|
|
||||||
'Mousetrap': {
|
|
||||||
exports: 'Mousetrap'
|
|
||||||
},
|
|
||||||
'lunr': {
|
|
||||||
exports: 'lunr'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
grunt.registerTask("bower-install", [ "bower-install-simple" ]);
|
|
||||||
|
|
||||||
// Build
|
|
||||||
grunt.registerTask('build', [
|
|
||||||
'bower-install',
|
|
||||||
'less',
|
|
||||||
'requirejs'
|
|
||||||
]);
|
|
||||||
|
|
||||||
grunt.registerTask('default', [
|
|
||||||
'build'
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
@@ -1,271 +1,59 @@
|
|||||||
GitBook
|
[](https://www.gitbook.com)
|
||||||
=======
|
|
||||||
|
|
||||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
<p align="center">A <em>modern</em> customizable documentation format and toolchain</p>
|
||||||
|
|
||||||
GitBook is a command line tool (and Node.js library) for building beautiful books and exercises using GitHub/Git and Markdown. Here is an example: [Learn Javascript](https://www.gitbook.io/book/GitBookIO/javascript). You can publish book easily online using [gitbook.io](https://www.gitbook.io) and an [editor](https://github.com/GitbookIO/editor) is available for Windows, Mac and Linux. You can follow [@GitBookIO](https://twitter.com/GitBookIO) on Twitter. Complete documentation is available at [help.gitbook.io](http://help.gitbook.io/).
|
|
||||||
|
|
||||||

|
<p align="center"><a href="#features"><strong>Features</strong></a> · <a href="https://www.gitbook.com"><strong>Hosting</strong></a> · <a href="http://redux.js.org/"><strong>Example</strong></a> · <a href="https://www.gitbook.com/editor"><strong>Editor</strong></a> · <a href="https://toolchain.gitbook.com/"><strong>Documentation</strong></a> · <a href="./CONTRIBUTING.md"><strong>Contributing!</strong></a> · <a href="https://twitter.com/GitBookIO"><strong>Twitter</strong></a></p>
|
||||||
|
<br/>
|
||||||
|
|
||||||
## How to use it:
|

|
||||||
|
|
||||||
GitBook can be installed from **NPM** using:
|
|
||||||
|
|
||||||
```
|
<p align="center">
|
||||||
$ npm install gitbook -g
|
<img src="https://badge.fury.io/js/gitbook.svg" />
|
||||||
```
|
<a href="https://travis-ci.org/GitbookIO/gitbook"><img src="https://travis-ci.org/GitbookIO/gitbook.png?branch=master" /></a>
|
||||||
|
<a href="https://ci.appveyor.com/project/GitBook/gitbook"><img src="https://ci.appveyor.com/api/projects/status/63nlflxcwmb2pue6?svg=true" /></a>
|
||||||
|
<a href="https://ci.appveyor.com/project/GitBook/gitbook"><img src="https://slack.gitbook.com/badge.svg" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
You can serve a repository as a book using:
|
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). Here is an example: [ReduxJS documentation](http://redux.js.org/).
|
||||||
|
|
||||||
```
|
You can publish and host books easily online using [gitbook.com](https://www.gitbook.com). A desktop editor is [also available](https://www.gitbook.com/editor).
|
||||||
$ gitbook serve ./repository
|
|
||||||
```
|
|
||||||
|
|
||||||
Or simply build the static website using:
|
Check out the [GitBook Community Slack Channel](https://slack.gitbook.com), Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
|
||||||
|
|
||||||
```
|
Complete documentation is available at [toolchain.gitbook.com](http://toolchain.gitbook.com/).
|
||||||
$ gitbook build ./repository --output=./outputFolder
|
|
||||||
```
|
|
||||||
|
|
||||||
Options for commands `build` and `serve` are:
|
## Getting started
|
||||||
|
|
||||||
```
|
GitBook can be used either on your computer for building local books or on GitBook.com for hosting them. To get started, check out [the installation instructions in the documentation](docs/setup.md).
|
||||||
-o, --output <directory> Path to output directory, defaults to ./_book
|
|
||||||
-f, --format <name> Change generation format, defaults to site, availables are: site, page, ebook, json
|
|
||||||
--config <config file> Configuration file to use, defaults to book.js or book.json
|
|
||||||
```
|
|
||||||
|
|
||||||
GitBook loads the default configuration from a `book.json` file in the repository if it exists.
|
## Usage examples
|
||||||
|
|
||||||
Here are the options that can be stored in this file:
|
GitBook can be used to create book, public documentation, enterprise manual, thesis, research papers, etc.
|
||||||
|
|
||||||
```js
|
You can find a [list of real-world examples](docs/examples.md) in the documentation.
|
||||||
{
|
|
||||||
// Folders to use for output
|
|
||||||
// Caution: it overrides the value from the command line
|
|
||||||
// It's not advised this option in the book.json
|
|
||||||
"output": null,
|
|
||||||
|
|
||||||
// Generator to use for building
|
## Help and Support
|
||||||
// Caution: it overrides the value from the command line
|
|
||||||
// It's not advised this option in the book.json
|
|
||||||
"generator": "site",
|
|
||||||
|
|
||||||
// Book title and description (defaults are extracted from the README)
|
We're always happy to help out with your books or any other questions you might have. You can ask a question on the following contact form at [gitbook.com/contact](https://www.gitbook.com/contact) or signal an issue on [GitHub](https://github.com/GitbookIO/gitbook).
|
||||||
"title": null,
|
|
||||||
"description": null,
|
|
||||||
|
|
||||||
// For ebook format, the extension to use for generation (default is detected from output extension)
|
## Features
|
||||||
// "epub", "pdf", "mobi"
|
|
||||||
// Caution: it overrides the value from the command line
|
|
||||||
// It's not advised this option in the book.json
|
|
||||||
"extension": null,
|
|
||||||
|
|
||||||
// GitHub information (defaults are extracted using git)
|
* Write using [Markdown](http://toolchain.gitbook.com/syntax/markdown.html) or [AsciiDoc](http://toolchain.gitbook.com/syntax/asciidoc.html)
|
||||||
"github": null,
|
* Output as a website or [ebook (pdf, epub, mobi)](http://toolchain.gitbook.com/ebook.html)
|
||||||
"githubHost": "https://github.com/",
|
* [Multi-Languages](http://toolchain.gitbook.com/languages.html)
|
||||||
|
* [Lexicon / Glossary](http://toolchain.gitbook.com/lexicon.html)
|
||||||
|
* [Cover](http://toolchain.gitbook.com/ebook.html)
|
||||||
|
* [Variables and Templating](http://toolchain.gitbook.com/templating/)
|
||||||
|
* [Content References](http://toolchain.gitbook.com/templating/conrefs.html)
|
||||||
|
* [Plugins](http://toolchain.gitbook.com/plugins/)
|
||||||
|
* [Beautiful default theme](https://github.com/GitbookIO/theme-default)
|
||||||
|
|
||||||
// Plugins list, can contain "-name" for removing default plugins
|
## Publish your book
|
||||||
"plugins": [],
|
|
||||||
|
|
||||||
// Global configuration for plugins
|
The platform [GitBook.com](https://www.gitbook.com/) is like an "Heroku for books": you can create a book on it (public, or private) and update it using **git push**.
|
||||||
"pluginsConfig": {
|
|
||||||
"fontSettings": {
|
|
||||||
"theme": "sepia", "night" or "white",
|
|
||||||
"family": "serif" or "sans",
|
|
||||||
"size": 1 to 4
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Set another theme with your own layout
|
## Licensing
|
||||||
// It's recommended to use plugins or add more options for default theme, though
|
|
||||||
// See https://github.com/GitbookIO/gitbook/issues/209
|
|
||||||
"theme": "./localtheme",
|
|
||||||
|
|
||||||
// Links in template (null: default, false: remove, string: new value)
|
GitBook is licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full license text.
|
||||||
"links": {
|
|
||||||
// Link to home in the top-left corner
|
|
||||||
"home": null,
|
|
||||||
|
|
||||||
// Links in top of sidebar
|
|
||||||
"about": null,
|
|
||||||
"issues": null,
|
|
||||||
"contribute": null,
|
|
||||||
|
|
||||||
// Custom links at top of sidebar
|
|
||||||
"custom": {
|
|
||||||
"Custom link name": "https://customlink.com"
|
|
||||||
},
|
|
||||||
|
|
||||||
// Sharing links
|
|
||||||
"sharing": {
|
|
||||||
"google": null,
|
|
||||||
"facebook": null,
|
|
||||||
"twitter": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
// Options for PDF generation
|
|
||||||
"pdf": {
|
|
||||||
// Add toc at the end of the file
|
|
||||||
"toc": true,
|
|
||||||
|
|
||||||
// Add page numbers to the bottom of every page
|
|
||||||
"pageNumbers": false,
|
|
||||||
|
|
||||||
// Font size for the fiel content
|
|
||||||
"fontSize": 12,
|
|
||||||
|
|
||||||
// Paper size for the pdf
|
|
||||||
// Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’]
|
|
||||||
"paperSize": "a4",
|
|
||||||
|
|
||||||
// Margin (in pts)
|
|
||||||
// Note: 72 pts equals 1 inch
|
|
||||||
"margin": {
|
|
||||||
"right": 62,
|
|
||||||
"left": 62,
|
|
||||||
"top": 36,
|
|
||||||
"bottom": 36
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can publish your books to our index by visiting [GitBook.io](http://www.gitbook.io)
|
|
||||||
|
|
||||||
## Output Formats
|
|
||||||
|
|
||||||
GitBook can generate your book in the following formats:
|
|
||||||
|
|
||||||
* **Static Website**: This is the default format. It generates a complete interactive static website that can be, for example, hosted on GitHub Pages.
|
|
||||||
* **eBook**: A complete eBook with exercise solutions at the end of the book. Generate this format using: ```gitbook ebook ./myrepo```. You need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed. The output format could be **PDF**, **ePub** or **MOBI**.
|
|
||||||
* **Single Page**: The book will be stored in a single printable HTML page. This format is used for conversion to PDF or eBook. Generate this format using: ```gitbook build ./myrepo -f page```.
|
|
||||||
* **JSON**: This format is used for debugging or extracting metadata from a book. Generate this format using: ```gitbook build ./myrepo -f json```.
|
|
||||||
|
|
||||||
## Book Format
|
|
||||||
|
|
||||||
A book is a Git repository containing at least 2 files: `README.md` and `SUMMARY.md`.
|
|
||||||
|
|
||||||
#### README.md
|
|
||||||
|
|
||||||
Typically, this should be the introduction for your book. It will be automatically added to the final summary.
|
|
||||||
|
|
||||||
#### SUMMARY.md
|
|
||||||
|
|
||||||
The `SUMMARY.md` defines your book's structure. It should contain a list of chapters, linking to their respective pages.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Summary
|
|
||||||
|
|
||||||
This is the summary of my book.
|
|
||||||
|
|
||||||
* [section 1](section1/README.md)
|
|
||||||
* [example 1](section1/example1.md)
|
|
||||||
* [example 2](section1/example2.md)
|
|
||||||
* [section 2](section2/README.md)
|
|
||||||
* [example 1](section2/example1.md)
|
|
||||||
```
|
|
||||||
|
|
||||||
Files that are not included in `SUMMARY.md` will not be processed by `gitbook`.
|
|
||||||
|
|
||||||
#### Exercises
|
|
||||||
|
|
||||||
A book can contain interactive exercises (currently only in Javascript but Python and Ruby are coming soon ;) ). An exercise is a code challenge provided to the reader, who is given a code editor to write a solution which is checked against the book author's validation code.
|
|
||||||
|
|
||||||
An exercise is defined by 4 simple parts:
|
|
||||||
|
|
||||||
* Exercise **Message**/Goals (in markdown/text)
|
|
||||||
* **Initial** code to show to the user, providing a starting point
|
|
||||||
* **Solution** code, being a correct solution to the exercise
|
|
||||||
* **Validation** code that tests the correctness of the user's input
|
|
||||||
|
|
||||||
Exercises need to start and finish with a separation bar (```---``` or ```***```). It should contain 3 code elements (**base**, **solution** and **validation**). It can contain a 4th element that provides **context** code (functions, imports of libraries, etc which shouldn't be displayed to the user).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Define a variable `x` equal to 10.
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x =
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
var x = 10;
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
assert(x == 10);
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
// This is context code available everywhere
|
|
||||||
// The user will be able to call magicFunc in his code
|
|
||||||
function magicFunc() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Multi-Languages
|
|
||||||
|
|
||||||
GitBook supports building books written in multiple languages. Each language should be a sub-directory following the normal GitBook format, and a file named `LANGS.md` should be present at the root of the repository with the following format:
|
|
||||||
|
|
||||||
```
|
|
||||||
* [English](en/)
|
|
||||||
* [French](fr/)
|
|
||||||
* [Español](es/)
|
|
||||||
```
|
|
||||||
|
|
||||||
You can see a complete example with the [Learn Git](https://github.com/GitbookIO/git) book.
|
|
||||||
|
|
||||||
#### Ignoring files & folders
|
|
||||||
|
|
||||||
GitBook will read the `.gitignore`, `.bookignore` and `.ignore` files to get a list of files and folders to skip. (The format inside those files follows the same convention as `.gitignore`)
|
|
||||||
|
|
||||||
#### Cover
|
|
||||||
|
|
||||||
A cover image can be set by creating a file: **/cover.jpg**.
|
|
||||||
The best resolution is **1800x2360**. The generation of the cover can be done automatically using the plugin [autocover](https://github.com/GitbookIO/plugin-autocover).
|
|
||||||
|
|
||||||
A small version of the cover can also be set by creating a file: **/cover_small.jpg**.
|
|
||||||
|
|
||||||
#### Publish your book
|
|
||||||
|
|
||||||
The platform [GitBook.io](https://www.gitbook.io/) is like an "Heroku for books": you can create a book on it (public, paid, or private) and update it using **git push**.
|
|
||||||
|
|
||||||
#### Plugins
|
|
||||||
|
|
||||||
Plugins can used to extend your book's functionality. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more information about how to build a plugin for GitBook.
|
|
||||||
|
|
||||||
##### Default plugins:
|
|
||||||
|
|
||||||
* [mathjax](https://github.com/GitbookIO/plugin-mathjax): displays mathematical notation in the book.
|
|
||||||
* [mixpanel](https://github.com/GitbookIO/plugin-mixpanel): Mixpanel tracking for your book
|
|
||||||
|
|
||||||
##### Other plugins:
|
|
||||||
|
|
||||||
* [Google Analytics](https://github.com/GitbookIO/plugin-ga): Google Analytics tracking for your book
|
|
||||||
* [Disqus](https://github.com/GitbookIO/plugin-disqus): Disqus comments integration in your book
|
|
||||||
* [Autocover](https://github.com/GitbookIO/plugin-autocover): Generate a cover for your book
|
|
||||||
* [Transform annoted quotes to notes](https://github.com/erixtekila/gitbook-plugin-richquotes): Allow extra markdown markup to render blockquotes as nice notes
|
|
||||||
* [Send code to console](https://github.com/erixtekila/gitbook-plugin-toconsole): Evaluate javascript block in the browser inspector's console
|
|
||||||
* [Revealable sections](https://github.com/mrpotes/gitbook-plugin-reveal): Reveal sections of the page using buttons made from the first title in each section
|
|
||||||
* [Markdown within HTML](https://github.com/mrpotes/gitbook-plugin-nestedmd): Process markdown within HTML blocks - allows custom layout options for individual pages
|
|
||||||
* [Bootstrap JavaScript plugins](https://github.com/mrpotes/gitbook-plugin-bootstrapjs): Use the [Bootstrap JavaScript plugins](http://getbootstrap.com/javascript) in your online GitBook
|
|
||||||
* [Piwik Open Analytics](https://github.com/emmanuel-keller/gitbook-plugin-piwik): Piwik Open Analytics tracking for your book
|
|
||||||
* [Heading Anchors](https://github.com/rlmv/gitbook-plugin-anchors): Add linkable Github-style anchors to headings
|
|
||||||
* [JSBin](https://github.com/jcouyang/gitbook-plugin-jsbin): Ebedded jsbin frame into your book
|
|
||||||
|
|
||||||
#### Debugging
|
|
||||||
|
|
||||||
You can use the environment variable `DEBUG=true` to get better error messages (with stack trace). For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ export DEBUG=true
|
|
||||||
$ gitbook build ./
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Fix line endings in Windows. (runs before repo cloning)
|
||||||
|
init:
|
||||||
|
- git config --global core.autocrlf input
|
||||||
|
|
||||||
|
# Test against these versions of Node.js.
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- nodejs_version: "6"
|
||||||
|
- nodejs_version: "5"
|
||||||
|
- nodejs_version: "4"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
# Install scripts. (runs after repo cloning)
|
||||||
|
install:
|
||||||
|
# Get the latest stable version of Node.js or io.js
|
||||||
|
- ps: Install-Product node $env:nodejs_version
|
||||||
|
- set CI=true
|
||||||
|
# install svgexport
|
||||||
|
- npm install svgexport -g
|
||||||
|
# install modules
|
||||||
|
- npm install
|
||||||
|
|
||||||
|
# Post-install test scripts.
|
||||||
|
test_script:
|
||||||
|
# Output useful info for debugging.
|
||||||
|
- node --version
|
||||||
|
- npm --version
|
||||||
|
# run tests
|
||||||
|
- npm test
|
||||||
|
|
||||||
|
# Don't actually build.
|
||||||
|
build: off
|
||||||
|
|
||||||
|
# Clone only last commit
|
||||||
|
shallow_clone: true
|
||||||
|
clone_depth: 1
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
var path = require('path');
|
|
||||||
var Q = require('q');
|
|
||||||
var _ = require('lodash');
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
var utils = require('./utils');
|
|
||||||
var generate = require("../lib/generate");
|
|
||||||
var parse = require("../lib/parse");
|
|
||||||
var generators = require("../lib/generate").generators;
|
|
||||||
|
|
||||||
var buildCommand = function(command) {
|
|
||||||
return command
|
|
||||||
.option('-v, --verbose', 'Activate verbose mode, useful for debugging errors')
|
|
||||||
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
|
|
||||||
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
|
|
||||||
.option('--config <config file>', 'Configuration file to use, defaults to book.js or book.json');
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var buildEbookCommand = function(command) {
|
|
||||||
return buildCommand(command)
|
|
||||||
.option('-c, --cover <path>', 'Cover image, default is cover.jpg if exists');
|
|
||||||
};
|
|
||||||
|
|
||||||
var makeBuildFunc = function(converter) {
|
|
||||||
return function(dir, options) {
|
|
||||||
dir = dir || process.cwd();
|
|
||||||
outputDir = options.output;
|
|
||||||
|
|
||||||
// Set debugging
|
|
||||||
if(options.verbose) {
|
|
||||||
process.env.DEBUG = "true";
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Starting build ...');
|
|
||||||
return converter(
|
|
||||||
_.extend({}, options || {}, {
|
|
||||||
input: dir,
|
|
||||||
output: outputDir,
|
|
||||||
generator: options.format,
|
|
||||||
configFile: options.config
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(function(output) {
|
|
||||||
console.log("Successfully built!");
|
|
||||||
return output;
|
|
||||||
})
|
|
||||||
.fail(function(err) {
|
|
||||||
// Log error
|
|
||||||
utils.logError(err);
|
|
||||||
|
|
||||||
// Exit process with failure code
|
|
||||||
process.exit(-1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
folder: makeBuildFunc(generate.folder),
|
|
||||||
file: makeBuildFunc(generate.file),
|
|
||||||
command: buildCommand,
|
|
||||||
commandEbook: buildEbookCommand
|
|
||||||
};
|
|
||||||
-138
@@ -1,138 +0,0 @@
|
|||||||
#! /usr/bin/env node
|
|
||||||
|
|
||||||
var Q = require('q');
|
|
||||||
var _ = require('lodash');
|
|
||||||
var path = require('path');
|
|
||||||
var prog = require('commander');
|
|
||||||
var tinylr = require('tiny-lr-fork');
|
|
||||||
|
|
||||||
var pkg = require('../package.json');
|
|
||||||
var generators = require("../lib/generate").generators;
|
|
||||||
var initDir = require("../lib/generate/init");
|
|
||||||
var fs = require('../lib/generate/fs');
|
|
||||||
|
|
||||||
var utils = require('./utils');
|
|
||||||
var build = require('./build');
|
|
||||||
var Server = require('./server');
|
|
||||||
var platform = require("./platform");
|
|
||||||
|
|
||||||
// General options
|
|
||||||
prog
|
|
||||||
.version(pkg.version);
|
|
||||||
|
|
||||||
build.command(prog.command('build [source_dir]'))
|
|
||||||
.description('Build a gitbook from a directory')
|
|
||||||
.action(build.folder);
|
|
||||||
|
|
||||||
build.command(prog.command('serve [source_dir]'))
|
|
||||||
.description('Build then serve a gitbook from a directory')
|
|
||||||
.option('-p, --port <port>', 'Port for server to listen on', 4000)
|
|
||||||
.option('--no-watch', 'Disable restart with file watching')
|
|
||||||
.action(function(dir, options) {
|
|
||||||
var server = new Server();
|
|
||||||
|
|
||||||
// init livereload server
|
|
||||||
var lrOptions = {port: 35729};
|
|
||||||
var lrServer = tinylr(lrOptions);
|
|
||||||
var lrPath = undefined;
|
|
||||||
lrServer.listen(lrOptions.port, function(err) {
|
|
||||||
if (err) { return console.log(err); }
|
|
||||||
console.log('Live reload server started on port: ' + lrOptions.port);
|
|
||||||
});
|
|
||||||
|
|
||||||
var generate = function() {
|
|
||||||
if (server.isRunning()) console.log("Stopping server");
|
|
||||||
|
|
||||||
server.stop()
|
|
||||||
.then(function() {
|
|
||||||
return build.folder(dir, _.extend(options || {}, {
|
|
||||||
cache: false,
|
|
||||||
defaultsPlugins: ["livereload"]
|
|
||||||
}));
|
|
||||||
})
|
|
||||||
.then(function(_options) {
|
|
||||||
console.log();
|
|
||||||
console.log('Starting server ...');
|
|
||||||
return server.start(_options.output, options.port)
|
|
||||||
.then(function() {
|
|
||||||
console.log('Serving book on http://localhost:'+options.port);
|
|
||||||
|
|
||||||
if (lrPath) {
|
|
||||||
// trigger livereload
|
|
||||||
lrServer.changed({body:{files:[lrPath]}})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.watch) return;
|
|
||||||
return utils.watch(_options.input)
|
|
||||||
.then(function(filepath) {
|
|
||||||
// set livereload path
|
|
||||||
lrPath = filepath;
|
|
||||||
console.log("Restart after change in files");
|
|
||||||
console.log('');
|
|
||||||
return generate();
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.fail(utils.logError);
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Press CTRL+C to quit ...');
|
|
||||||
console.log('')
|
|
||||||
generate();
|
|
||||||
});
|
|
||||||
|
|
||||||
build.commandEbook(prog.command('pdf [source_dir]'))
|
|
||||||
.description('Build a gitbook as a PDF')
|
|
||||||
.action(function(dir, options) {
|
|
||||||
build.file(dir, _.extend(options, {
|
|
||||||
extension: "pdf",
|
|
||||||
format: "ebook"
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
build.commandEbook(prog.command('epub [source_dir]'))
|
|
||||||
.description('Build a gitbook as a ePub book')
|
|
||||||
.action(function(dir, options) {
|
|
||||||
build.file(dir, _.extend(options, {
|
|
||||||
extension: "epub",
|
|
||||||
format: "ebook"
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
build.commandEbook(prog.command('mobi [source_dir]'))
|
|
||||||
.description('Build a gitbook as a Mobi book')
|
|
||||||
.action(function(dir, options) {
|
|
||||||
build.file(dir, _.extend(options, {
|
|
||||||
extension: "mobi",
|
|
||||||
format: "ebook"
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
prog
|
|
||||||
.command('init [source_dir]')
|
|
||||||
.description('Create files and folders based on contents of SUMMARY.md')
|
|
||||||
.action(function(dir) {
|
|
||||||
dir = dir || process.cwd();
|
|
||||||
return initDir(dir);
|
|
||||||
});
|
|
||||||
|
|
||||||
prog
|
|
||||||
.command('publish [source_dir]')
|
|
||||||
.description('Publish content to the associated gitbook.io book')
|
|
||||||
.action(function(dir) {
|
|
||||||
dir = dir || process.cwd();
|
|
||||||
return platform.publish(dir);
|
|
||||||
});
|
|
||||||
|
|
||||||
prog
|
|
||||||
.command('git:remote [source_dir] [book_id]')
|
|
||||||
.description('Adds a git remote to a book repository')
|
|
||||||
.action(function(dir, bookId) {
|
|
||||||
dir = dir || process.cwd();
|
|
||||||
return platform.remote(dir, bookId);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Parse and fallback to help if no args
|
|
||||||
if(_.isEmpty(prog.parse(process.argv).args) && process.argv.length === 2) {
|
|
||||||
prog.help();
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
var Q = require("q");
|
|
||||||
var utils = require("./utils");
|
|
||||||
|
|
||||||
var publish = function(folder) {
|
|
||||||
if (!folder) {
|
|
||||||
console.log("Need a repository folder");
|
|
||||||
return process.exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
utils.gitCmd("push", ["gitbook", "master"])
|
|
||||||
.then(function(out) {
|
|
||||||
console.log(out.stdout);
|
|
||||||
}, function(err) {
|
|
||||||
if (err.code == 128) {
|
|
||||||
console.log("No book on gitbook.io is configured with this git repository.");
|
|
||||||
console.log("Run 'gitbook git:remote username/book' to intialize this repository.");
|
|
||||||
} else {
|
|
||||||
console.log(err.message);
|
|
||||||
}
|
|
||||||
process.exit(-1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var remote = function(folder, bookId) {
|
|
||||||
if (!folder || !bookId) {
|
|
||||||
console.log("Need a repository folder and a book id");
|
|
||||||
return process.exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
var url = "https://push.gitbook.io/"+bookId+".git";
|
|
||||||
var addRemote = function() {
|
|
||||||
return utils.gitCmd("remote", ["add", "gitbook", url]);
|
|
||||||
}
|
|
||||||
|
|
||||||
addRemote()
|
|
||||||
.fail(function(err) {
|
|
||||||
if (err.code == 128) {
|
|
||||||
return utils.gitCmd("remote", ["rm", "gitbook"]).then(addRemote);
|
|
||||||
}
|
|
||||||
return Q.reject(err);
|
|
||||||
})
|
|
||||||
.then(function(out) {
|
|
||||||
console.log("Book remote '"+url+"' added to the folder");
|
|
||||||
}, function(err) {
|
|
||||||
console.log(err.message);
|
|
||||||
process.exit(-1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
publish: publish,
|
|
||||||
remote: remote
|
|
||||||
};
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
var Q = require('q');
|
|
||||||
var _ = require('lodash');
|
|
||||||
|
|
||||||
var events = require('events');
|
|
||||||
var http = require('http');
|
|
||||||
var send = require('send');
|
|
||||||
var util = require('util');
|
|
||||||
var url = require('url');
|
|
||||||
|
|
||||||
var Server = function() {
|
|
||||||
this.running = null;
|
|
||||||
this.dir = null;
|
|
||||||
this.port = 0;
|
|
||||||
this.sockets = [];
|
|
||||||
};
|
|
||||||
util.inherits(Server, events.EventEmitter);
|
|
||||||
|
|
||||||
// Return true if the server is running
|
|
||||||
Server.prototype.isRunning = function() {
|
|
||||||
return this.running != null;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Stop the server
|
|
||||||
Server.prototype.stop = function() {
|
|
||||||
var that = this;
|
|
||||||
if (!this.isRunning()) return Q();
|
|
||||||
|
|
||||||
var d = Q.defer();
|
|
||||||
this.running.close(function(err) {
|
|
||||||
that.running = null;
|
|
||||||
that.emit("state", false);
|
|
||||||
|
|
||||||
if (err) d.reject(err);
|
|
||||||
else d.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var i = 0; i < this.sockets.length; i++) {
|
|
||||||
this.sockets[i].destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
Server.prototype.start = function(dir, port) {
|
|
||||||
var that = this, pre = Q();
|
|
||||||
port = port || 8004;
|
|
||||||
|
|
||||||
if (that.isRunning()) pre = this.stop();
|
|
||||||
return pre
|
|
||||||
.then(function() {
|
|
||||||
var d = Q.defer();
|
|
||||||
|
|
||||||
that.running = http.createServer(function(req, res){
|
|
||||||
// Render error
|
|
||||||
function error(err) {
|
|
||||||
res.statusCode = err.status || 500;
|
|
||||||
res.end(err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect to directory's index.html
|
|
||||||
function redirect() {
|
|
||||||
res.statusCode = 301;
|
|
||||||
res.setHeader('Location', req.url + '/');
|
|
||||||
res.end('Redirecting to ' + req.url + '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send file
|
|
||||||
send(req, url.parse(req.url).pathname)
|
|
||||||
.root(dir)
|
|
||||||
.on('error', error)
|
|
||||||
.on('directory', redirect)
|
|
||||||
.pipe(res);
|
|
||||||
});
|
|
||||||
|
|
||||||
that.running.on('connection', function (socket) {
|
|
||||||
that.sockets.push(socket);
|
|
||||||
socket.setTimeout(4000);
|
|
||||||
socket.on('close', function () {
|
|
||||||
that.sockets.splice(that.sockets.indexOf(socket), 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
that.running.listen(port, function(err) {
|
|
||||||
if (err) return d.reject(err);
|
|
||||||
|
|
||||||
that.port = port;
|
|
||||||
that.dir = dir;
|
|
||||||
that.emit("state", true);
|
|
||||||
d.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
return d.promise;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Server;
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
var Q = require('q');
|
|
||||||
var _ = require('lodash');
|
|
||||||
|
|
||||||
var exec = require('child_process').exec;
|
|
||||||
var http = require('http');
|
|
||||||
var send = require('send');
|
|
||||||
|
|
||||||
var path = require('path');
|
|
||||||
var Gaze = require('gaze').Gaze;
|
|
||||||
|
|
||||||
function watch(dir) {
|
|
||||||
var d = Q.defer();
|
|
||||||
dir = path.resolve(dir);
|
|
||||||
|
|
||||||
var gaze = new Gaze("**/*.md", {
|
|
||||||
cwd: dir
|
|
||||||
});
|
|
||||||
|
|
||||||
gaze.once("all", function(e, filepath) {
|
|
||||||
gaze.close();
|
|
||||||
|
|
||||||
d.resolve(filepath);
|
|
||||||
});
|
|
||||||
gaze.once("error", function(err) {
|
|
||||||
gaze.close();
|
|
||||||
|
|
||||||
d.reject(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
return d.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function logError(err) {
|
|
||||||
var message = err.message || err;
|
|
||||||
if (process.env.DEBUG != null) message = err.stack || message;
|
|
||||||
console.log(message);
|
|
||||||
return Q.reject(err);
|
|
||||||
};
|
|
||||||
|
|
||||||
function runGitCommand(command, args) {
|
|
||||||
var d = Q.defer(), child;
|
|
||||||
args = ["git", command].concat(args).join(" ");
|
|
||||||
|
|
||||||
child = exec(args, function (error, stdout, stderr) {
|
|
||||||
if (error !== null) {
|
|
||||||
error.stdout = stdout;
|
|
||||||
error.stderr = stderr;
|
|
||||||
d.reject(error);
|
|
||||||
} else {
|
|
||||||
d.resolve({
|
|
||||||
stdout: stdout,
|
|
||||||
stderr: stderr
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return d.promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = {
|
|
||||||
watch: watch,
|
|
||||||
logError: logError,
|
|
||||||
gitCmd: runGitCommand
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
var pkg = require('./package.json');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Documentation for GitBook is stored under "docs"
|
||||||
|
root: './docs',
|
||||||
|
title: 'GitBook Toolchain Documentation',
|
||||||
|
|
||||||
|
// Use the "official" theme
|
||||||
|
plugins: ['sitemap'],
|
||||||
|
|
||||||
|
variables: {
|
||||||
|
version: pkg.version
|
||||||
|
},
|
||||||
|
|
||||||
|
pluginsConfig: {
|
||||||
|
sitemap: {
|
||||||
|
hostname: 'https://toolchain.gitbook.com'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
-13
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "GitBook",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"dependencies": {
|
|
||||||
"jquery": "2.1.1",
|
|
||||||
"lodash": "2.4.1",
|
|
||||||
"requirejs": "2.1.11",
|
|
||||||
"URIjs": "1.13.1",
|
|
||||||
"mousetrap": "1.4.6",
|
|
||||||
"lunr.js": "0.5.2",
|
|
||||||
"ace-builds": "1.1.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# GitBook Toolchain Documentation
|
||||||
|
|
||||||
|
This document aims to be a comprehensive guide to GitBook. It contains the full documentation for version **{{ book.version }}**. Help for GitBook.com specific questions can be found at [help.gitbook.com](https://help.gitbook.com).
|
||||||
|
|
||||||
|
### What is GitBook?
|
||||||
|
|
||||||
|
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). This documentation has been generated using GitBook.
|
||||||
|
|
||||||
|
GitBook can output your content as a website ([customizable](themes/README.md) and [extensibles](plugins/README.md)) or as an ebook (PDF, ePub or Mobi).
|
||||||
|
|
||||||
|
[GitBook.com](https://www.gitbook.com) is the online platform to create and host books built using the GitBook format. It offers hosting, collaboration features and an [easy-to-use editor](https://www.gitbook.com/editor).
|
||||||
|
|
||||||
|
### Help and Support
|
||||||
|
|
||||||
|
We're always happy to help out with your books or any other questions you might have. You can ask a question on the following contact form at [gitbook.com/contact](https://www.gitbook.com/contact) or signal an issue on [GitHub](https://github.com/GitbookIO/gitbook).
|
||||||
|
|
||||||
|
Check out the [GitBook Community Slack Channel](https://slack.gitbook.com), Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
|
||||||
|
|
||||||
|
### FAQ
|
||||||
|
|
||||||
|
Some questions are frequently asked. If you have a problem you should [check this out](faq.md) first.
|
||||||
|
|
||||||
|
### Contribute to this documentation
|
||||||
|
|
||||||
|
You can contribute to improve this documentation on [GitHub](https://github.com/GitbookIO/gitbook) by signaling issues or proposing changes.
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Summary
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
|
||||||
|
* [About this documentation](README.md)
|
||||||
|
* [Installation and Setup](setup.md)
|
||||||
|
|
||||||
|
### Your Content
|
||||||
|
|
||||||
|
* [Directory structure](structure.md)
|
||||||
|
* [Pages and Summary](pages.md)
|
||||||
|
* [Configuration](config.md)
|
||||||
|
* [Glossary](lexicon.md)
|
||||||
|
* [Multi-Lingual](languages.md)
|
||||||
|
* [Markdown](syntax/markdown.md)
|
||||||
|
* [Headings](syntax/markdown.md#headings)
|
||||||
|
* [Paragraphs](syntax/markdown.md#paragraphs)
|
||||||
|
* [Emphasis](syntax/markdown.md#emphasis)
|
||||||
|
* [Lists](syntax/markdown.md#lists)
|
||||||
|
* [Links](syntax/markdown.md#links)
|
||||||
|
* [Images](syntax/markdown.md#images)
|
||||||
|
* [Blockquotes](syntax/markdown.md#blockquotes)
|
||||||
|
* [Tables](syntax/markdown.md#tables)
|
||||||
|
* [Code](syntax/markdown.md#code)
|
||||||
|
* [HTML](syntax/markdown.md#html)
|
||||||
|
* [Footnotes](syntax/markdown.md#footnotes)
|
||||||
|
* [AsciiDoc](syntax/asciidoc.md)
|
||||||
|
* [eBook and PDF](ebook.md)
|
||||||
|
|
||||||
|
### Customization
|
||||||
|
|
||||||
|
* [Templating](templating/README.md)
|
||||||
|
* [Content References](templating/conrefs.md)
|
||||||
|
* [Variables](templating/variables.md)
|
||||||
|
* [Builtin](templating/builtin.md)
|
||||||
|
* [Plugins](plugins/README.md)
|
||||||
|
* [Create a plugin](plugins/create.md)
|
||||||
|
* [Hooks](plugins/hooks.md)
|
||||||
|
* [Blocks](plugins/blocks.md)
|
||||||
|
* [Filters](plugins/filters.md)
|
||||||
|
* [API & Context](plugins/api.md)
|
||||||
|
* [Test your plugin](plugins/testing.md)
|
||||||
|
* [Theming](themes/README.md)
|
||||||
|
|
||||||
|
### Plugin Development
|
||||||
|
|
||||||
|
* [Introduction](./api/README.md)
|
||||||
|
* [Node](./api/node.md)
|
||||||
|
* [Connect to the context](./api/connect.md)
|
||||||
|
* [Components](./api/components.md)
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
* [FAQ](faq.md)
|
||||||
|
* [Examples](examples.md)
|
||||||
|
* [Release notes](https://github.com/GitbookIO/gitbook/blob/master/CHANGES.md)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Plugin Architecture
|
||||||
|
|
||||||
|
A GitBook plugin is a NPM package that follows a defined convention.
|
||||||
|
|
||||||
|
`gitbook-plugin` is a command line utility to help you create, test and release plugins.
|
||||||
|
|
||||||
|
### Bootstrap your first plugin
|
||||||
|
|
||||||
|
Install `gitbook-plugin` from NPM:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install gitbook-plugin -g
|
||||||
|
```
|
||||||
|
|
||||||
|
Then create your plugin:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gitbook-plugin create
|
||||||
|
```
|
||||||
|
|
||||||
|
You will be asked for a plugin name, and a few other things to complete the creation process.
|
||||||
|
|
||||||
|
|
||||||
|
### Publish your plugin
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# Components
|
||||||
|
|
||||||
|
|
||||||
|
## Injection
|
||||||
|
|
||||||
|
Plugins can inject components by registering React components to some roles.
|
||||||
|
|
||||||
|
#### Register a components
|
||||||
|
|
||||||
|
During the initialization phase of your plugin, dispatch the `GitBook.registerComponent` action:
|
||||||
|
|
||||||
|
```js
|
||||||
|
dispatch(GitBook.registerComponent(MyCustomButton, { role: 'toolbar:buttons:left' }));
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Roles
|
||||||
|
|
||||||
|
Custom roles can be use for interopability with other plugins, but GitBook and the default theme set a convention for common roles:
|
||||||
|
|
||||||
|
| Role | Description | Props |
|
||||||
|
| ---- | ----------- | ----- |
|
||||||
|
| `page:container` | DIV container for the page's content | `{ page: Page }` |
|
||||||
|
| `summary:container` | DIV container for the whole summary | `{ summary: Summary }` |
|
||||||
|
| `summary:parts` | DIV container for summary's parts | `{ parts: List<SummaryPart> }` |
|
||||||
|
| `summary:part` | DIV for a specific part | `{ part: SummaryPart }` |
|
||||||
|
| `summary:articles` | UL container for a part's articles | `{ articles: List<SummaryArticle> }` |
|
||||||
|
| `summary:article` | LI for a specific article | `{ article: SummaryArticle }` |
|
||||||
|
|
||||||
|
## Default Components
|
||||||
|
|
||||||
|
#### `GitBook.Head`
|
||||||
|
|
||||||
|
Extends the meta tags of the page. This is an alias for [react-helmet](https://github.com/nfl/react-helmet).
|
||||||
|
|
||||||
|
```js
|
||||||
|
<GitBook.Head
|
||||||
|
title="My page"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `GitBook.ImportCSS`
|
||||||
|
|
||||||
|
Import a CSS file by resolving the path correctly according to the current page:
|
||||||
|
|
||||||
|
```js
|
||||||
|
<GitBook.ImportCSS href="myfile.css" />
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `GitBook.ImportJS`
|
||||||
|
|
||||||
|
Import a JS file by resolving the path correctly according to the current page:
|
||||||
|
|
||||||
|
```js
|
||||||
|
<GitBook.ImportJS src="mylib.js" />
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `GitBook.InjectedComponent`
|
||||||
|
|
||||||
|
Inject a component matching a specific role:
|
||||||
|
|
||||||
|
```js
|
||||||
|
<GitBook.InjectedComponent matching={{ role: 'mycustomrole' }} props={{ someProp: 1 }}>
|
||||||
|
<b>Inner content</b>
|
||||||
|
</GitBook.InjectedComponent>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `GitBook.InjectedComponentSet`
|
||||||
|
|
||||||
|
Same API as `InjectedComponentSet` but render the matching components in chain instead of composed:
|
||||||
|
|
||||||
|
```js
|
||||||
|
<GitBook.InjectedComponentSet matching={{ role: 'mytoolbar' }} />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Warning:** Children are discarded.
|
||||||
|
|
||||||
|
#### `GitBook.FlexLayout` and `GitBook.FlexBox`
|
||||||
|
|
||||||
|
A simple wrapper that provides a Flexbox layout with the given direction and style. Any additional props you set on the Flexbox are rendered.
|
||||||
|
|
||||||
|
```js
|
||||||
|
<GitBook.FlexLayout column>
|
||||||
|
<GitBook.FlexBox>First column</GitBook.FlexBox>
|
||||||
|
<GitBook.FlexBox>Second column</GitBook.FlexBox>
|
||||||
|
</GitBook.FlexLayout>
|
||||||
|
```
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Connect to the context
|
||||||
|
|
||||||
|
`GitBook.connect(Component, [mapStateToProps], [mapActionsToProps])` connects a react component to the GitBook context.
|
||||||
|
|
||||||
|
It does not modify the component class passed to it.
|
||||||
|
Instead, it returns a new, connected component class, for you to use.
|
||||||
|
|
||||||
|
### `mapStateToProps(state, [ownProps]): stateProps`
|
||||||
|
|
||||||
|
If specified, the component will subscribe to GitBook store updates. Any time it updates, `mapStateToProps` will be called. Its result must be a plain object, and it will be merged into the component’s props.
|
||||||
|
|
||||||
|
If you omit it, the component will not be subscribed to the GitBook store. If `ownProps` is specified as a second argument, its value will be the props passed to your component, and `mapStateToProps` will be additionally re-invoked whenever the component receives new props (e.g. if props received from a parent component have shallowly changed, and you use the `ownProps` argument, `mapStateToProps` is re-evaluated).
|
||||||
|
|
||||||
|
For example to render the title of the current page:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const GitBook = require('gitbook-core');
|
||||||
|
|
||||||
|
let PageTitle = React.createClass({
|
||||||
|
render() {
|
||||||
|
const { page } = this.props;
|
||||||
|
return <h1>{page.title}</h1>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return { page: state.page };
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTitle = GitBook.connect(PageTitle, mapStateToProps);
|
||||||
|
```
|
||||||
|
|
||||||
|
### `mapActionsToProps(actions, [dispatch])`
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Internationalize your plugin
|
||||||
|
|
||||||
|
GitBook has built-in support for internationalization. Plugins can register new languages and provide the right messages for different languages.
|
||||||
|
|
||||||
|
### Register locale and messages
|
||||||
|
|
||||||
|
The first step is to register messages for a language:
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = GitBook.createPlugin({
|
||||||
|
init: (dispatch, getState, { I18n }) => {
|
||||||
|
dispatch(I18n.registerLocale('en-US', {
|
||||||
|
MY_PLUGIN_MESSAGE: 'Hello World'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Render a message in a component
|
||||||
|
|
||||||
|
`GitBook.connect` adds a `i18n` prop to access the internationalization:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const GitBook = require('gitbook-core');
|
||||||
|
const { React } = GitBook;
|
||||||
|
|
||||||
|
const MyButton = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
i18n: GitBook.Shapes.i18n
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { i18n } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GitBook.Button>
|
||||||
|
{i18.t('MY_PLUGIN_MESSAGE')}
|
||||||
|
</GitBook.Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = GitBook.connect(MyButton);
|
||||||
|
```
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Navigation
|
||||||
|
|
||||||
|
### Listen to url change
|
||||||
|
|
||||||
|
Listen for changes to the current location:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const onLocationChanged = (location) => {
|
||||||
|
console.log(location.pathname);
|
||||||
|
console.log(location.query);
|
||||||
|
console.log(location.hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = GitBook.createPlugin({
|
||||||
|
init: (dispatch, getState, { Navigation }) => {
|
||||||
|
dispatch(Navigation.listen(onLocationChanged));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The `onLocationChanged` will be triggered for initial state.
|
||||||
|
|
||||||
|
### Changing the url
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# Node APIs
|
||||||
|
|
||||||
|
GitBooks provides different Node APIs and contexts to plugins. These APIs can vary according to the GitBook version being used, your plugin should specify the `engines.gitbook` field in `package.json` accordingly.
|
||||||
|
|
||||||
|
#### Book instance
|
||||||
|
|
||||||
|
The `Book` interface is the central point of GitBook, it centralize all access read methods.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Read configuration from book.json
|
||||||
|
var value = book.config.get('title', 'Default Value');
|
||||||
|
|
||||||
|
// Resolve a filename to an absolute path
|
||||||
|
var filepath = book.resolve('README.md');
|
||||||
|
|
||||||
|
// Render an inline markup string
|
||||||
|
book.renderInline('markdown', 'This is **Markdown**')
|
||||||
|
.then(function(str) { ... })
|
||||||
|
|
||||||
|
// Render a markup string (block mode)
|
||||||
|
book.renderBlock('markdown', '* This is **Markdown**')
|
||||||
|
.then(function(str) { ... })
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output instance
|
||||||
|
|
||||||
|
The `Output` class represent the output/write process.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Return root folder for the output
|
||||||
|
var root = output.root();
|
||||||
|
|
||||||
|
// Resolve a file in the output folder
|
||||||
|
var filepath = output.resolve('myimage.png');
|
||||||
|
|
||||||
|
// Convert a filename to an URL (returns a path to an html file)
|
||||||
|
var fileurl = output.toURL('mychapter/README.md');
|
||||||
|
|
||||||
|
// Write a file in the output folder
|
||||||
|
output.writeFile('hello.txt', 'Hello World')
|
||||||
|
.then(function() { ... });
|
||||||
|
|
||||||
|
// Copy a file to the output folder
|
||||||
|
output.copyFile('./myfile.jpg', 'cover.jpg')
|
||||||
|
.then(function() { ... });
|
||||||
|
|
||||||
|
// Verify that a file exists
|
||||||
|
output.hasFile('hello.txt')
|
||||||
|
.then(function(exists) { ... });
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Page instance
|
||||||
|
|
||||||
|
A page instance represent the current parsed page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Title of the page (from SUMMARY)
|
||||||
|
page.title
|
||||||
|
|
||||||
|
// Content of the page (Markdown/Asciidoc/HTML according to the stage)
|
||||||
|
page.content
|
||||||
|
|
||||||
|
// Relative path in the book
|
||||||
|
page.path
|
||||||
|
|
||||||
|
// Absolute path to the file
|
||||||
|
page.rawPath
|
||||||
|
|
||||||
|
// Type of parser used for this file
|
||||||
|
page.type ('markdown' or 'asciidoc')
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Context for Blocks and Filters
|
||||||
|
|
||||||
|
Blocks and filters have access to the same context, this context is bind to the template engine execution:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
// Current templating syntax
|
||||||
|
"ctx": {
|
||||||
|
// For example, after a {% set message = "hello" %}
|
||||||
|
"message": "hello"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Book instance
|
||||||
|
"book" <Book>,
|
||||||
|
|
||||||
|
// Output instance
|
||||||
|
"output": <Output>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For example a filter or block function can access the current book using: `this.book`.
|
||||||
|
|
||||||
|
#### Context for Hooks
|
||||||
|
|
||||||
|
Hooks only have access to the `<Book>` instance using `this.book`.
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# Configuration
|
||||||
|
|
||||||
|
GitBook allows you to customize your book using a flexible configuration. These options are specified in a `book.json` file. For authors unfamiliar with the JSON syntax, you can validate the syntax using tools such as [JSONlint](http://jsonlint.com).
|
||||||
|
|
||||||
|
### General Settings
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `root` | Path to the root folder containing all the book's files, except `book.json`|
|
||||||
|
| `structure` | To specify paths for Readme, Summary, Glossary etc. See [Structure paragraph](#structure). |
|
||||||
|
| `title` | Title of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
|
||||||
|
| `description` | Description of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
|
||||||
|
| `author` | Name of the author. On GitBook.com this field is pre-filled. |
|
||||||
|
| `isbn` | ISBN of the book |
|
||||||
|
| `language` | [ISO code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) of the book's language, default value is `en` |
|
||||||
|
| `direction` | Text's direction. Can be `rtl` or `ltr`, the default value depends on the value of `language` |
|
||||||
|
| `gitbook` | Version of GitBook that should be used. Uses the [SemVer](http://semver.org) specification and accepts conditions like `">= 3.0.0"` |
|
||||||
|
|
||||||
|
### Plugins
|
||||||
|
|
||||||
|
Plugins and their configurations are specified in the `book.json`. See [the plugins section](plugins/README.md) for more details.
|
||||||
|
|
||||||
|
Since version 3.0.0, GitBook can use themes. See [the theming section](themes/README.md) for more details.
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `plugins` | List of plugins to load |
|
||||||
|
| `pluginsConfig` |Configuration for plugins |
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
|
||||||
|
In addition to the `root` variable, you can tell Gitbook the name of the files for Readme, Summary, Glossary, Languages (instead of using the default names such as `README.md`).
|
||||||
|
These files must be at the root of your book (or the root of every language book). Paths such as `dir/MY_README.md` are not accepted.
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `structure.readme` | Readme file name (defaults to `README.md`) |
|
||||||
|
| `structure.summary` | Summary file name (defaults to `SUMMARY.md`) |
|
||||||
|
| `structure.glossary` | Glossary file name (defaults to `GLOSSARY.md`) |
|
||||||
|
| `structure.languages` | Languages file name (defaults to `LANGS.md`) |
|
||||||
|
|
||||||
|
### PDF Options
|
||||||
|
|
||||||
|
PDF Output can be customized using a set of options in the `book.json`:
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `pdf.pageNumbers` | Add page numbers to the bottom of every page (default is `true`) |
|
||||||
|
| `pdf.fontSize` | Base font size (default is `12`) |
|
||||||
|
| `pdf.fontFamily` | Base font family (default is `Arial`) |
|
||||||
|
| `pdf.paperSize` | Paper size, options are `'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'legal', 'letter'` (default is `a4`) |
|
||||||
|
| `pdf.margin.top` | Top margin (default is `56`) |
|
||||||
|
| `pdf.margin.bottom` | Bottom margin (default is `56`) |
|
||||||
|
| `pdf.margin.right` | Right margin (default is `62`) |
|
||||||
|
| `pdf.margin.left` | Left margin (default is `62`) |
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# Generating eBooks and PDFs
|
||||||
|
|
||||||
|
GitBook can generates a website, but can also output content as ebook (ePub, Mobi, PDF).
|
||||||
|
|
||||||
|
```
|
||||||
|
# Generate a PDF file
|
||||||
|
$ gitbook pdf ./ ./mybook.pdf
|
||||||
|
|
||||||
|
# Generate an ePub file
|
||||||
|
$ gitbook epub ./ ./mybook.epub
|
||||||
|
|
||||||
|
# Generate a Mobi file
|
||||||
|
$ gitbook mobi ./ ./mybook.mobi
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installing ebook-convert
|
||||||
|
|
||||||
|
`ebook-convert` is required to generate ebooks (epub, mobi, pdf).
|
||||||
|
|
||||||
|
##### GNU/Linux
|
||||||
|
|
||||||
|
Install the [Calibre application](https://calibre-ebook.com/download).
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo aptitude install calibre
|
||||||
|
```
|
||||||
|
|
||||||
|
In some GNU/Linux distributions node is installed as nodejs, you need to manually create a symlink:
|
||||||
|
|
||||||
|
```
|
||||||
|
$sudo ln -s /usr/bin/nodejs /usr/bin/node
|
||||||
|
```
|
||||||
|
|
||||||
|
##### OS X
|
||||||
|
|
||||||
|
Download the [Calibre application](https://calibre-ebook.com/download). After moving the `calibre.app` to your Applications folder create a symbolic link to the ebook-convert tool:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo ln -s ~/Applications/calibre.app/Contents/MacOS/ebook-convert /usr/bin
|
||||||
|
```
|
||||||
|
|
||||||
|
You can replace `/usr/bin` with any directory that is in your $PATH.
|
||||||
|
|
||||||
|
### Cover
|
||||||
|
|
||||||
|
Covers are used for all the ebook formats. You can either provide one yourself, or generate one using the [autocover plugin](https://plugins.gitbook.com/plugin/autocover).
|
||||||
|
|
||||||
|
To provide a cover, place a **`cover.jpg`** file at the root directory of your book. Adding a **`cover_small.jpg`** will specify a smaller version of the cover. The cover should be a **JPEG** file.
|
||||||
|
|
||||||
|
A good cover should respect the following guidelines:
|
||||||
|
|
||||||
|
* Size of 1800x2360 pixels for `cover.jpg`, 200x262 for `cover_small.jpg`
|
||||||
|
* No border
|
||||||
|
* Clearly visible book title
|
||||||
|
* Any important text should be visible in the small version
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
description: Real world examples of content published using GitBook.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
More than 50,000 books have been published on [GitBook.com](https://www.gitbook.com/explore).
|
||||||
|
|
||||||
|
### Books
|
||||||
|
|
||||||
|
- [Front-end Handbook](https://www.gitbook.com/book/frontendmasters/front-end-handbook/details) by [Cody Lindley](http://codylindley.com)
|
||||||
|
- [How to make an Operating System](https://www.gitbook.com/book/samypesse/how-to-create-an-operating-system/details) by [@SamyPesse](https://github.com/SamyPesse)
|
||||||
|
- [Building Web Apps with Go](https://www.gitbook.com/book/codegangsta/building-web-apps-with-go/details) by [@codegangsta](https://github.com/codegangsta)
|
||||||
|
- [Django Girls Tutorial](http://tutorial.djangogirls.org/en/index.html) by [Django Girls](https://djangogirls.org)
|
||||||
|
- [Linux Inside](https://www.gitbook.com/book/0xax/linux-insides/details) by [0xAX](https://twitter.com/0xAX)
|
||||||
|
- [Learn Javascript](https://www.gitbook.com/book/gitbookio/javascript/details) by [GitBook](https://twitter.com/GitbookIO)
|
||||||
|
|
||||||
|
### Research Papers
|
||||||
|
|
||||||
|
- [TowCenter Collection](https://www.gitbook.com/@towcenter) by [Columbia Journalism School](http://www.journalism.columbia.edu/)
|
||||||
|
- [Block Relaxation Algorithms in Statistics](https://www.gitbook.com/@jandeleeuw) by Jan de Leeuw
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- [DuckDuckHack Documentation](http://docs.duckduckhack.com) by [DuckDuckGo](https://duckduckgo.com/about)
|
||||||
|
- [Loomio Handbook](http://loomio.coop/) and [guide to using Loomio](https://loomio.gitbooks.io/manual/content/en/index.html) both by [Loomio](https://www.loomio.org/)
|
||||||
|
- [Enspiral Handbook](http://handbook.enspiral.com/) by [Enspiral](http://enspiral.com/)
|
||||||
|
- This documentation
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
# GitBook FAQ
|
||||||
|
|
||||||
|
This page gathers common questions and answers concerning the GitBook format and toolchain.
|
||||||
|
|
||||||
|
Questions about GitBook.com and the Editor are gather into the [help.gitbook.com's FAQ](http://help.gitbook.com/faq.html).
|
||||||
|
|
||||||
|
#### How can I host/publish my book?
|
||||||
|
|
||||||
|
Books can easily be published and hosted on [GitBook.com](https://www.gitbook.com). But GitBook output can be hosted on any static file hosting solution.
|
||||||
|
|
||||||
|
#### What can I use to edit my content?
|
||||||
|
|
||||||
|
Any text editor should work! But we advise using the [GitBook Editor](https://www.gitbook.com/editor). [GitBook.com](https://www.gitbook.com) also provides a web version of this editor.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Does GitBook supports RTL/bi-directional text ?
|
||||||
|
|
||||||
|
The GitBook format supports right to left, and bi-directional writing. To enable it, you either need to specify a language (ex: `ar`), or force GitBook to use RTL in your `book.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"language": "ar",
|
||||||
|
"direction": "rtl"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
With version 3.0 of GitBook, it's automatically detected according to the content.
|
||||||
|
_Note that, while the output book will indeed respect RTL, the Editor doesn't support RTL writing yet_.
|
||||||
|
|
||||||
|
#### Should I use an `.html` or `.md` extensions in my links?
|
||||||
|
|
||||||
|
You should always use paths and the `.md` extensions when linking to your files, GitBook will automatically replace these paths by the appropriate link when the pointing file is referenced in the Table of Contents.
|
||||||
|
|
||||||
|
#### Can I create a GitBook in a sub-directory of my repository?
|
||||||
|
|
||||||
|
Yes, GitBooks can be created in [sub-directories](structure.md#subdirectory). GitBook.com and the CLI also looks by default in a series of [folders](structure.md).
|
||||||
|
|
||||||
|
#### Does GitBook supports RTL languages?
|
||||||
|
|
||||||
|
Yes, GitBook automatically detect the direction in your pages (`rtl` or `ltr`) and adjust the layout accordingly. The direction can also be specified globally in the [book.json](config.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Does GitBook support Math equations?
|
||||||
|
|
||||||
|
GitBook supports math equations and TeX thanks to plugins. There are currently 2 official plugins to display math: [mathjax](https://plugins.gitbook.com/plugin/mathjax) and [katex](https://plugins.gitbook.com/plugin/katex).
|
||||||
|
|
||||||
|
#### Can I customize/theme the output?
|
||||||
|
|
||||||
|
Yes, both the website and ebook outputs can be customized using [themes](themes/README.md).
|
||||||
|
|
||||||
|
#### Can I add interactive content (videos, etc)?
|
||||||
|
|
||||||
|
GitBook is very [extensible](plugins/README.md). You can use [existing plugins](https://plugins.gitbook.com) or create your own!
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 227 KiB |
@@ -0,0 +1,17 @@
|
|||||||
|
# Multi-Languages
|
||||||
|
|
||||||
|
GitBook supports building books written in multiple languages. Each language should be a sub-directory following the normal GitBook format, and a file named `LANGS.md` should be present at the root of the repository with the following format:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Languages
|
||||||
|
|
||||||
|
* [English](en/)
|
||||||
|
* [French](fr/)
|
||||||
|
* [Español](es/)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration for each language
|
||||||
|
|
||||||
|
When a language book (ex: `en`) has a `book.json`, its configuration will extend the main configuration.
|
||||||
|
|
||||||
|
The only exception is plugins, plugins are specified globally, and language specific plugins cannot be specified.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Glossary
|
||||||
|
|
||||||
|
Allows you to specify terms and their respective definitions to be displayed as annotations. Based on those terms, GitBook will automatically build an index and highlight those terms in pages.
|
||||||
|
|
||||||
|
The `GLOSSARY.md` format is a list of `h2` headings, along with a description paragraph:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Term
|
||||||
|
Definition for this term
|
||||||
|
|
||||||
|
## Another term
|
||||||
|
With it's definition, this can contain bold text
|
||||||
|
and all other kinds of inline markup ...
|
||||||
|
```
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
# Pages and Summary
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
GitBook uses a `SUMMARY.md` file to define the structure of chapters and subchapters of the book. The `SUMMARY.md` file is used to generate the book's table of contents.
|
||||||
|
|
||||||
|
The format of `SUMMARY.md` is just a list of links. The link's title is used as the chapter's title, and the link's target is a path to that chapter's file.
|
||||||
|
|
||||||
|
Adding a nested list to a parent chapter will create subchapters.
|
||||||
|
|
||||||
|
##### Simple example
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
* [Part I](part1/README.md)
|
||||||
|
* [Writing is nice](part1/writing.md)
|
||||||
|
* [GitBook is nice](part1/gitbook.md)
|
||||||
|
* [Part II](part2/README.md)
|
||||||
|
* [We love feedback](part2/feedback_please.md)
|
||||||
|
* [Better tools for authors](part2/better_tools.md)
|
||||||
|
```
|
||||||
|
|
||||||
|
Each chapter has a dedicated page (`part#/README.md`) and is split into subchapters.
|
||||||
|
|
||||||
|
##### Anchors
|
||||||
|
|
||||||
|
Chapters in the Table of Contents can be pointing to specific part of a file using anchor.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
### Part I
|
||||||
|
|
||||||
|
* [Part I](part1/README.md)
|
||||||
|
* [Writing is nice](part1/README.md#writing)
|
||||||
|
* [GitBook is nice](part1/README.md#gitbook)
|
||||||
|
* [Part II](part2/README.md)
|
||||||
|
* [We love feedback](part2/README.md#feedback)
|
||||||
|
* [Better tools for authors](part2/README.md#tools)
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Parts
|
||||||
|
|
||||||
|
The Table of Contents can be divided into parts separated by headings or horizontal lines:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
### Part I
|
||||||
|
|
||||||
|
* [Writing is nice](part1/writing.md)
|
||||||
|
* [GitBook is nice](part1/gitbook.md)
|
||||||
|
|
||||||
|
### Part II
|
||||||
|
|
||||||
|
* [We love feedback](part2/feedback_please.md)
|
||||||
|
* [Better tools for authors](part2/better_tools.md)
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
* [Last part without title](part3/title.md)
|
||||||
|
```
|
||||||
|
|
||||||
|
Parts are just groups of chapters and do not have dedicated pages, but according to the theme, it will show in the navigation.
|
||||||
|
|
||||||
|
### Pages
|
||||||
|
|
||||||
|
#### Markdown syntax
|
||||||
|
|
||||||
|
Most of the files for GitBook use the Markdown syntax by default. GitBook infers your pages's structure from it. The syntax used is similar to the [GitHub Flavored Markdown syntax](https://guides.github.com/features/mastering-markdown/). One can also opt for the [AsciiDoc syntax](asciidoc.md).
|
||||||
|
|
||||||
|
##### Example of a chapter file
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Title of the chapter
|
||||||
|
|
||||||
|
This is a great introduction.
|
||||||
|
|
||||||
|
## Section 1
|
||||||
|
|
||||||
|
Markdown will dictates _most_ of your **book's structure**
|
||||||
|
|
||||||
|
## Section 2
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Front Matter
|
||||||
|
|
||||||
|
Pages can contain an optional front matter. It can be used to define the page's description. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
description: This is a short description of my page
|
||||||
|
---
|
||||||
|
|
||||||
|
# The content of my page
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
The front matter can define variables of your own, they will be added to the [page variable](templating/variables.md) so you can use them in your templating.
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Plugins
|
||||||
|
|
||||||
|
Plugins are the best way to extend GitBook functionalities (ebook and website). There exist plugins to do a lot of things: bring math formulas display support, track visits using Google Analytics, etc.
|
||||||
|
|
||||||
|
### How to find plugins?
|
||||||
|
|
||||||
|
Plugins can be easily searched on [plugins.gitbook.com](https://plugins.gitbook.com).
|
||||||
|
|
||||||
|
|
||||||
|
### How to install a plugin?
|
||||||
|
|
||||||
|
Once you find a plugin that you want to install, you need to add it to your `book.json`:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"plugins": ["myPlugin", "anotherPlugin"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also specify a specific version using: `"myPlugin@0.3.1"`. By default GitBook will resolve the latest version of the plugin compatbile with the current GitBook version.
|
||||||
|
|
||||||
|
### GitBook.com
|
||||||
|
|
||||||
|
Plugins are automatically installed on [GitBook.com](https://www.gitbook.com). Locally, run `gitbook install` to install and prepare all plugins for your books.
|
||||||
|
|
||||||
|
### Configuring plugins
|
||||||
|
|
||||||
|
Plugins specific configurations are stored in `pluginsConfig`. You have to refer to the documentation of the plugin itself for details about the available options.
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# Context and APIs
|
||||||
|
|
||||||
|
GitBooks provides different APIs and contexts to plugins. These APIs can vary according to the GitBook version being used, your plugin should specify the `engines.gitbook` field in `package.json` accordingly.
|
||||||
|
|
||||||
|
#### Book instance
|
||||||
|
|
||||||
|
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https://github.com/GitbookIO/gitbook/blob/master/book.js).
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Read configuration from book.json
|
||||||
|
var value = book.config.get('title', 'Default Value');
|
||||||
|
|
||||||
|
// Resolve a filename to an absolute path
|
||||||
|
var filepath = book.resolve('README.md');
|
||||||
|
|
||||||
|
// Render an inline markup string
|
||||||
|
book.renderInline('markdown', 'This is **Markdown**')
|
||||||
|
.then(function(str) { ... })
|
||||||
|
|
||||||
|
// Render a markup string (block mode)
|
||||||
|
book.renderBlock('markdown', '* This is **Markdown**')
|
||||||
|
.then(function(str) { ... })
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output instance
|
||||||
|
|
||||||
|
The `Output` class represent the output/write process.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Return root folder for the output
|
||||||
|
var root = output.root();
|
||||||
|
|
||||||
|
// Resolve a file in the output folder
|
||||||
|
var filepath = output.resolve('myimage.png');
|
||||||
|
|
||||||
|
// Convert a filename to an URL (returns a path to an html file)
|
||||||
|
var fileurl = output.toURL('mychapter/README.md');
|
||||||
|
|
||||||
|
// Write a file in the output folder
|
||||||
|
output.writeFile('hello.txt', 'Hello World')
|
||||||
|
.then(function() { ... });
|
||||||
|
|
||||||
|
// Copy a file to the output folder
|
||||||
|
output.copyFile('./myfile.jpg', 'cover.jpg')
|
||||||
|
.then(function() { ... });
|
||||||
|
|
||||||
|
// Verify that a file exists
|
||||||
|
output.hasFile('hello.txt')
|
||||||
|
.then(function(exists) { ... });
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Page instance
|
||||||
|
|
||||||
|
A page instance represent the current parsed page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Title of the page (from SUMMARY)
|
||||||
|
page.title
|
||||||
|
|
||||||
|
// Content of the page (Markdown/Asciidoc/HTML according to the stage)
|
||||||
|
page.content
|
||||||
|
|
||||||
|
// Relative path in the book
|
||||||
|
page.path
|
||||||
|
|
||||||
|
// Absolute path to the file
|
||||||
|
page.rawPath
|
||||||
|
|
||||||
|
// Type of parser used for this file
|
||||||
|
page.type ('markdown' or 'asciidoc')
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Context for Blocks and Filters
|
||||||
|
|
||||||
|
Blocks and filters have access to the same context, this context is bind to the template engine execution:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
// Current templating syntax
|
||||||
|
"ctx": {
|
||||||
|
// For example, after a {% set message = "hello" %}
|
||||||
|
"message": "hello"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Book instance
|
||||||
|
"book" <Book>,
|
||||||
|
|
||||||
|
// Output instance
|
||||||
|
"output": <Output>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For example a filter or block function can access the current book using: `this.book`.
|
||||||
|
|
||||||
|
#### Context for Hooks
|
||||||
|
|
||||||
|
Hooks only have access to the `<Book>` instance using `this.book`.
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# Extend Blocks
|
||||||
|
|
||||||
|
Extending templating blocks is the best way to provide extra functionalities to authors.
|
||||||
|
|
||||||
|
The most common usage is to process the content within some tags at runtime. It's like [filters](./filters.md), but on steroids because you aren't confined to a single expression.
|
||||||
|
|
||||||
|
### Defining a new block
|
||||||
|
|
||||||
|
Blocks are defined by the plugin, blocks is a map of name associated with a block descriptor. The block descriptor needs to contain at least a `process` method.
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
blocks: {
|
||||||
|
tag1: {
|
||||||
|
process: function(block) {
|
||||||
|
return "Hello "+block.body+", How are you?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The `process` should return the html content that will replace the tag. Refer to [Context and APIs](./api.md) to learn more about `this` and GitBook API.
|
||||||
|
|
||||||
|
### Handling block arguments
|
||||||
|
|
||||||
|
Arguments can be passed to blocks:
|
||||||
|
|
||||||
|
```
|
||||||
|
{% tag1 "argument 1", "argument 2", name="Test" %}
|
||||||
|
This is the body of the block.
|
||||||
|
{% endtag1 %}
|
||||||
|
```
|
||||||
|
|
||||||
|
And arguments are easily accessible in the `process` method:
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
blocks: {
|
||||||
|
tag1: {
|
||||||
|
process: function(block) {
|
||||||
|
// block.args equals ["argument 1", "argument 2"]
|
||||||
|
// block.kwargs equals { "name": "Test" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handling sub-blocks
|
||||||
|
|
||||||
|
A defined block can be parsed into different sub-blocks, for example let's consider the source:
|
||||||
|
|
||||||
|
```
|
||||||
|
{% myTag %}
|
||||||
|
Main body
|
||||||
|
{% subblock1 %}
|
||||||
|
Body of sub-block 1
|
||||||
|
{% subblock 2 %}
|
||||||
|
Body of sub-block 1
|
||||||
|
{% endmyTag %}
|
||||||
|
```
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# Create and publish a plugin
|
||||||
|
|
||||||
|
A GitBook plugin is a node package published on NPM that follow a defined convention.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
#### package.json
|
||||||
|
|
||||||
|
The `package.json` is a manifest format for describing **Node.js modules**. GitBook plugins are built on top of Node modules. It declares dependencies, version, ownership, and other information required to run a plugin in GitBook. This document describes the schema in detail.
|
||||||
|
|
||||||
|
A plugin manifest `package.json` can also contain details about the required configuration. The configuration schema is defined in the `gitbook` field of the `package.json` (This field follow the [JSON-Schema](http://json-schema.org) guidelines):
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"name": "gitbook-plugin-mytest",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "This is my first GitBook plugin",
|
||||||
|
"engines": {
|
||||||
|
"gitbook": ">1.x.x"
|
||||||
|
},
|
||||||
|
"gitbook": {
|
||||||
|
"properties": {
|
||||||
|
"myConfigKey": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "it's the default value",
|
||||||
|
"description": "It defines my awesome config!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can learn more about `package.json` from the [NPM documentation](https://docs.npmjs.com/files/package.json).
|
||||||
|
|
||||||
|
The **package name** must begin with `gitbook-plugin-` and the **package engines** should contains `gitbook`.
|
||||||
|
|
||||||
|
#### index.js
|
||||||
|
|
||||||
|
The `index.js` is main entry point of your plugin runtime:
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
// Map of hooks
|
||||||
|
hooks: {},
|
||||||
|
|
||||||
|
// Map of new blocks
|
||||||
|
blocks: {},
|
||||||
|
|
||||||
|
// Map of new filters
|
||||||
|
filters: {}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Publish your plugin
|
||||||
|
|
||||||
|
GitBook plugins can be published on [NPM](https://www.npmjs.com).
|
||||||
|
|
||||||
|
To publish a new plugin, you need to create an account on [npmjs.com](https://www.npmjs.com) then publish it from the command line:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm publish
|
||||||
|
```
|
||||||
|
|
||||||
|
## Private plugins
|
||||||
|
|
||||||
|
Private plugins can be hosted on GitHub and included using `git` urls:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"myplugin@git+https://github.com/MyCompany/mygitbookplugin.git#1.0.0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# Extend Filters
|
||||||
|
|
||||||
|
Filters are essentially functions that can be applied to variables. They are called with a pipe operator (`|`) and can take arguments.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{ foo | title }}
|
||||||
|
{{ foo | join(",") }}
|
||||||
|
{{ foo | replace("foo", "bar") | capitalize }}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Defining a new filter
|
||||||
|
|
||||||
|
Plugins can extend filters by defining custom functions in their entry point under the `filters` scope.
|
||||||
|
|
||||||
|
A filter function takes as first argument the content to filter, and should return the new content.
|
||||||
|
Refer to [Context and APIs](./api.md) to learn more about `this` and GitBook API.
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
filters: {
|
||||||
|
hello: function(name) {
|
||||||
|
return 'Hello '+name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The filter `hello` can then be used in the book:
|
||||||
|
|
||||||
|
```
|
||||||
|
{{ "Aaron"|hello }}, how are you?
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handling block arguments
|
||||||
|
|
||||||
|
Arguments can be passed to filters:
|
||||||
|
|
||||||
|
```
|
||||||
|
Hello {{ "Samy"|fullName("Pesse", man=true}} }}
|
||||||
|
```
|
||||||
|
|
||||||
|
Arguments are passed to the function, named-arguments are passed as a last argument (object).
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
filters: {
|
||||||
|
fullName: function(firstName, lastName, kwargs) {
|
||||||
|
var name = firstName + ' ' + lastName;
|
||||||
|
|
||||||
|
if (kwargs.man) name = "Mr" + name;
|
||||||
|
else name = "Mrs" + name;
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# Hooks
|
||||||
|
|
||||||
|
Hooks is a method of augmenting or altering the behavior of the process, with custom callbacks.
|
||||||
|
|
||||||
|
### List of hooks
|
||||||
|
|
||||||
|
### Relative to the global pipeline
|
||||||
|
|
||||||
|
| Name | Description | Arguments |
|
||||||
|
| ---- | ----------- | --------- |
|
||||||
|
| `init` | Called after parsing the book, before generating output and pages. | None |
|
||||||
|
| `finish:before` | Called after generating the pages, before copying assets, cover, ... | None |
|
||||||
|
| `finish` | Called after everything else. | None |
|
||||||
|
|
||||||
|
### Relative to the page pipeline
|
||||||
|
|
||||||
|
> It is recommended using [templating](./templating.md) to extend page parsing.
|
||||||
|
|
||||||
|
| Name | Description | Arguments |
|
||||||
|
| ---- | ----------- | --------- |
|
||||||
|
| `page:before` | Called before running the templating engine on the page | Page Object |
|
||||||
|
| `page` | Called before outputting and indexing the page. | Page Object |
|
||||||
|
|
||||||
|
##### Page Object
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
// Parser named
|
||||||
|
"type": "markdown",
|
||||||
|
|
||||||
|
// File Path relative to book root
|
||||||
|
"path": "page.md",
|
||||||
|
|
||||||
|
// Absolute file path
|
||||||
|
"rawpath": "/usr/...",
|
||||||
|
|
||||||
|
// Title of the page in the SUMMARY
|
||||||
|
"title": "",
|
||||||
|
|
||||||
|
// Content of the page
|
||||||
|
// Markdown/Asciidoc in "page:before"
|
||||||
|
// HTML in "page"
|
||||||
|
"content": "# Hello"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Example to add a title
|
||||||
|
|
||||||
|
In the `page:before` hook, `page.content` is the markdown/asciidoc content.
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"page:before": function(page) {
|
||||||
|
page.content = "# Title\n" +page.content;
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Example to replace some html
|
||||||
|
|
||||||
|
In the `page` hook, `page.content` is the HTML generated from the markdown/asciidoc conversion.
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"page": function(page) {
|
||||||
|
page.content = page.content.replace("<b>", "<strong>")
|
||||||
|
.replace("</b>", "</strong>");
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Asynchronous Operations
|
||||||
|
|
||||||
|
Hooks callbacks can be asynchronous and return promises.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"init": function() {
|
||||||
|
return writeSomeFile()
|
||||||
|
.then(function() {
|
||||||
|
return writeAnotherFile();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Testing your plugin
|
||||||
|
|
||||||
|
### Testing your plugin locally
|
||||||
|
|
||||||
|
Testing your plugin on your book before publishing it is possible using [npm link](https://docs.npmjs.com/cli/link).
|
||||||
|
|
||||||
|
In the plugin's folder, run:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm link
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in your book's folder:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm link gitbook-plugin-<plugin's name>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unit testing on Travis
|
||||||
|
|
||||||
|
[gitbook-tester](https://github.com/todvora/gitbook-tester) makes it easy to write **Node.js/Mocha** unit tests for your plugins. Using [Travis.org](https://travis.org), tests can be run on each commits/tags.
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# Setup and Installation of GitBook
|
||||||
|
|
||||||
|
Getting GitBook installed and ready-to-go should only take a few minutes.
|
||||||
|
|
||||||
|
### GitBook.com
|
||||||
|
|
||||||
|
[GitBook.com](https://www.gitbook.com) is an easy to use solution to write, publish and host books. It is the easiest solution for publishing your content and collaborating on it.
|
||||||
|
|
||||||
|
It integrates well with the [GitBook Editor](https://www.gitbook.com/editor).
|
||||||
|
|
||||||
|
### Local Installation
|
||||||
|
|
||||||
|
##### Requirements
|
||||||
|
|
||||||
|
Installing GitBook is easy and straightforward. Your system just needs to meet these two requirements:
|
||||||
|
|
||||||
|
* NodeJS (v4.0.0 and above is recommended)
|
||||||
|
* Windows, Linux, Unix, or Mac OS X
|
||||||
|
|
||||||
|
##### Install with NPM
|
||||||
|
|
||||||
|
The best way to install GitBook is via **NPM**. At the terminal prompt, simply run the following command to install GitBook:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install gitbook-cli -g
|
||||||
|
```
|
||||||
|
|
||||||
|
`gitbook-cli` is an utility to install and use multiple versions of GitBook on the same system. It will automatically install the required version of GitBook to build a book.
|
||||||
|
|
||||||
|
##### Create a book
|
||||||
|
|
||||||
|
GitBook can setup a boilerplate book:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gitbook init
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish to create the book into a new directory, you can do so by running `gitbook init ./directory`
|
||||||
|
|
||||||
|
Preview and serve your book using:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gitbook serve
|
||||||
|
```
|
||||||
|
|
||||||
|
Or build the static website using:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gitbook build
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Install pre-releases
|
||||||
|
|
||||||
|
`gitbook-cli` makes it easy to download and install other versions of GitBook to test with your book:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gitbook fetch beta
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `gitbook ls-remote` to list remote versions available for install.
|
||||||
|
|
||||||
|
##### Debugging
|
||||||
|
|
||||||
|
You can use the options `--log=debug` and `--debug` to get better error messages (with stack trace). For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gitbook build ./ --log=debug --debug
|
||||||
|
```
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# Directory Structure
|
||||||
|
|
||||||
|
GitBook uses a simple directory structure. All Markdown/Asciidoc files listed in the [SUMMARY](pages.md) will be transformed as HTML. Multi-Lingual books have a slightly [different structure](languages.md).
|
||||||
|
|
||||||
|
A basic GitBook usually looks something like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── book.json
|
||||||
|
├── README.md
|
||||||
|
├── SUMMARY.md
|
||||||
|
├── chapter-1/
|
||||||
|
| ├── README.md
|
||||||
|
| └── something.md
|
||||||
|
└── chapter-2/
|
||||||
|
├── README.md
|
||||||
|
└── something.md
|
||||||
|
```
|
||||||
|
|
||||||
|
An overview of what each of these does:
|
||||||
|
|
||||||
|
| File | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `book.json` | Stores [configuration](config.md) data (__optional__) |
|
||||||
|
| `README.md` | Preface / Introduction for your book (**required**) |
|
||||||
|
| `SUMMARY.md` | Table of Contents (See [Pages](pages.md)) (__optional__) |
|
||||||
|
| `GLOSSARY.md` | Lexicon / List of terms to annotate (See [Glossary](lexicon.md)) (__optional__) |
|
||||||
|
|
||||||
|
### Static files and Images
|
||||||
|
|
||||||
|
A static file is a file that is not listed in the `SUMMARY.md`. All static files, unless [ignored](#ignore), are copied to the output.
|
||||||
|
|
||||||
|
### Ignoring files & folders {#ignore}
|
||||||
|
|
||||||
|
GitBook will read the `.gitignore`, `.bookignore` and `.ignore` files to get a list of files and folders to skip.
|
||||||
|
The format inside those files, follows the same convention as `.gitignore`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# This is a comment
|
||||||
|
|
||||||
|
# Ignore the file test.md
|
||||||
|
test.md
|
||||||
|
|
||||||
|
# Ignore everything in the directory "bin"
|
||||||
|
bin/*
|
||||||
|
```
|
||||||
|
|
||||||
|
### Project integration with subdirectory {#subdirectory}
|
||||||
|
|
||||||
|
For software projects, you can use a subdirectory (like `docs/`) to store the book for the project's documentation. You can configure the [`root` option](config.md) to indicate the folder where GitBook can find the book's files:
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── book.json
|
||||||
|
└── docs/
|
||||||
|
├── README.md
|
||||||
|
└── SUMMARY.md
|
||||||
|
```
|
||||||
|
|
||||||
|
With `book.json` containing:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"root": "./docs"
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
/* Reduce size of logo to allow long versions like 3.0.0-pre.1 */
|
||||||
|
.gb-page-header .container .logo h1 {
|
||||||
|
font-size: 24px ;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# AsciiDoc
|
||||||
|
|
||||||
|
Since version `2.0.0`, GitBook can also accept AsciiDoc as an input format.
|
||||||
|
|
||||||
|
Please refer to the [AsciiDoc Syntax Quick Reference](http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/) for more informations about the format.
|
||||||
|
|
||||||
|
Just like for markdown, GitBook is using some special files to extract structures: `README.adoc`, `SUMMARY.adoc`, `LANGS.adoc` and `GLOSSARY.adoc`.
|
||||||
|
|
||||||
|
### README.adoc
|
||||||
|
|
||||||
|
This is the main entry of your book: the introduction. This file is **required**.
|
||||||
|
|
||||||
|
### SUMMARY.adoc
|
||||||
|
|
||||||
|
This file defines the list of chapters and subchapters. Just like in Markdown, the `SUMMARY.adoc`'s format is simply a list of links, the name of the link is used as the chapter's name, and the target is a path to that chapter's file.
|
||||||
|
|
||||||
|
Subchapters are defined simply by adding a nested list to a parent chapter.
|
||||||
|
|
||||||
|
```asciidoc
|
||||||
|
= Summary
|
||||||
|
|
||||||
|
. link:chapter-1/README.adoc[Chapter 1]
|
||||||
|
.. link:chapter-1/ARTICLE1.adoc[Article 1]
|
||||||
|
.. link:chapter-1/ARTICLE2.adoc[Article 2]
|
||||||
|
... link:chapter-1/ARTICLE-1-2-1.adoc[Article 1.2.1]
|
||||||
|
. link:chapter-2/README.adoc[Chapter 2]
|
||||||
|
. link:chapter-3/README.adoc[Chapter 3]
|
||||||
|
. link:chapter-4/README.adoc[Chapter 4]
|
||||||
|
.. Unfinished article
|
||||||
|
. Unfinished Chapter
|
||||||
|
```
|
||||||
|
|
||||||
|
### LANGS.adoc
|
||||||
|
|
||||||
|
For [Multi-Languages](./languages.md) books, this file is used to define the different supported languages and translations.
|
||||||
|
|
||||||
|
This file is following the same syntax as the `SUMMARY.adoc`:
|
||||||
|
|
||||||
|
```asciidoc
|
||||||
|
= Languages
|
||||||
|
|
||||||
|
. link:en/[English]
|
||||||
|
. link:fr/[French]
|
||||||
|
```
|
||||||
|
|
||||||
|
### GLOSSARY.adoc
|
||||||
|
|
||||||
|
This file is used to define terms. [See the glossary section](./lexicon.md).
|
||||||
|
|
||||||
|
```asciidoc
|
||||||
|
= Glossary
|
||||||
|
|
||||||
|
== Magic
|
||||||
|
|
||||||
|
Sufficiently advanced technology, beyond the understanding of the
|
||||||
|
observer producing a sense of wonder.
|
||||||
|
|
||||||
|
== PHP
|
||||||
|
|
||||||
|
A popular web programming language, used by many large websites such
|
||||||
|
as Facebook. Rasmus Lerdorf originally created PHP in 1994 to power
|
||||||
|
his personal homepage (PHP originally stood for "Personal Home Page"
|
||||||
|
but now stands for "PHP: Hypertext Preprocessor").
|
||||||
|
```
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
# Markdown
|
||||||
|
|
||||||
|
Most of the examples from this documentation are in Markdown. Markdown is default parser for GitBook, but one can also opt for the [AsciiDoc syntax](asciidoc.md).
|
||||||
|
|
||||||
|
Here’s an overview of Markdown syntax that you can use with GitBook (same as GitHub with some additions).
|
||||||
|
|
||||||
|
### Headings
|
||||||
|
|
||||||
|
To create a heading, add one to six `#` symbols before your heading text. The number of # you use will determine the size of the heading.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# This is an <h1> tag
|
||||||
|
## This is an <h2> tag
|
||||||
|
###### This is an <h6> tag
|
||||||
|
```
|
||||||
|
|
||||||
|
GitBook supports a nice way for explicitly setting the header ID. If you follow the header text with an opening curly bracket (separated from the text with a least one space), a hash, the ID and a closing curly bracket, the ID is set on the header. If you use the trailing hash feature of atx style headers, the header ID has to go after the trailing hashes. For example:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
Hello {#id}
|
||||||
|
-----
|
||||||
|
|
||||||
|
# Hello {#id}
|
||||||
|
|
||||||
|
# Hello # {#id}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Paragraphs and Line Breaks {#paragraphs}
|
||||||
|
|
||||||
|
A paragraph is simply one or more consecutive lines of text, separated by one or more blank lines. (A blank line is any line that looks like a blank line — a line containing nothing but spaces or tabs is considered blank.) Normal paragraphs should not be indented with spaces or tabs.
|
||||||
|
|
||||||
|
```
|
||||||
|
Here's a line for us to start with.
|
||||||
|
|
||||||
|
This line is separated from the one above by two newlines, so it will be a *separate paragraph*.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Emphasis {#emphasis}
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
*This text will be italic*
|
||||||
|
_This will also be italic_
|
||||||
|
|
||||||
|
**This text will be bold**
|
||||||
|
__This will also be bold__
|
||||||
|
|
||||||
|
~~This text will be crossed out.~~
|
||||||
|
|
||||||
|
_You **can** combine them_
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lists {#lists}
|
||||||
|
|
||||||
|
Markdown supports ordered (numbered) and unordered (bulleted) lists.
|
||||||
|
|
||||||
|
##### Unordered
|
||||||
|
|
||||||
|
Unordered lists use asterisks, pluses, and hyphens — interchangably — as list markers:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
* Item 1
|
||||||
|
* Item 2
|
||||||
|
* Item 2a
|
||||||
|
* Item 2b
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Ordered
|
||||||
|
|
||||||
|
Ordered lists use numbers followed by periods:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
1. Item 1
|
||||||
|
2. Item 2
|
||||||
|
3. Item 3
|
||||||
|
* Item 3a
|
||||||
|
* Item 3b
|
||||||
|
```
|
||||||
|
|
||||||
|
### Links {#links}
|
||||||
|
|
||||||
|
Markdown supports two style of links: inline and reference.
|
||||||
|
|
||||||
|
A simple link can be created by surrounding the text with square brackets and the link URL with parentheses:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
This is [an example](http://example.com/ "Title") inline link with a title.
|
||||||
|
|
||||||
|
[This link](http://example.net/) has no title attribute.
|
||||||
|
```
|
||||||
|
|
||||||
|
Links can point to relative paths, anchors or absolute urls.
|
||||||
|
|
||||||
|
|
||||||
|
### References
|
||||||
|
|
||||||
|
There is another way to create links which does not interrupt the text flow. The URL and title are defined using a reference name and this reference name is then used in square brackets instead of the link URL:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
This is [an example][id] reference-style link.
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, anywhere in the document, you define your link label like this, on a line by itself:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
[id]: http://example.com/ "Optional Title Here"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Images {#images}
|
||||||
|
|
||||||
|
Images can be created in a similar way than links: just use an exclamation mark before the square brackets. The link text will become the alternative text of the image and the link URL specifies the image source:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
An image: 
|
||||||
|
```
|
||||||
|
|
||||||
|
### Blockquotes {#blockquotes}
|
||||||
|
|
||||||
|
A blockquote is started using the `>` marker followed by an optional space; all following lines that are also started with the blockquote marker belong to the blockquote. You can use any block-level elements inside a blockquote:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
As Kanye West said:
|
||||||
|
|
||||||
|
> We're living the future so
|
||||||
|
> the present is our past.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tables {#tables}
|
||||||
|
|
||||||
|
You can create tables by assembling a list of words and dividing them with hyphens `-` (for the first row), and then separating each column with a pipe `|`:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
| First Header | Second Header |
|
||||||
|
| ------------- | ------------- |
|
||||||
|
| Content Cell | Content Cell |
|
||||||
|
| Content Cell | Content Cell |
|
||||||
|
```
|
||||||
|
|
||||||
|
The pipes on either end of the table are optional. Cells can vary in width and do not need to be perfectly aligned within columns. There must be at least three hyphens in each column of the header row.
|
||||||
|
|
||||||
|
### Code {#code}
|
||||||
|
|
||||||
|
Markdown supports two different code block styles. One uses lines indented with either four spaces or one tab whereas the other uses lines with tilde characters as delimiters – therefore the content does not need to be indented:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
This is a sample code block.
|
||||||
|
|
||||||
|
Continued here.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Fenced code blocks
|
||||||
|
|
||||||
|
You can create fenced code blocks by placing triple backticks ` ``` ` before and after the code block. We recommend placing a blank line before and after code blocks to make the raw formatting easier to read.
|
||||||
|
|
||||||
|
```
|
||||||
|
function test() {
|
||||||
|
console.log("notice the blank line before this function?");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Syntax highlighting
|
||||||
|
|
||||||
|
You can add an optional language identifier to enable syntax highlighting in your fenced code block.
|
||||||
|
|
||||||
|
For example, to syntax highlight Ruby code:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
require 'redcarpet'
|
||||||
|
markdown = Redcarpet.new("Hello World!")
|
||||||
|
puts markdown.to_html
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Inline code
|
||||||
|
|
||||||
|
Text phrases can be marked up as code by surrounding them with backticks:
|
||||||
|
|
||||||
|
Use `gitbook` to convert the `text` in markdown
|
||||||
|
syntax to HTML.
|
||||||
|
|
||||||
|
### Footnotes
|
||||||
|
|
||||||
|
GitBook supports a simple syntax for such footnotes. Footnotes are relative to each pages.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
Text prior to footnote reference.[^2]
|
||||||
|
|
||||||
|
[^2]: Comment to include in footnote.
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTML
|
||||||
|
|
||||||
|
GitBook supports use of raw HTML in your text, Markdown syntax in HTML is not processed:
|
||||||
|
|
||||||
|
```
|
||||||
|
<div>
|
||||||
|
Markdown here will not be **parsed**
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Horizontal Rule
|
||||||
|
|
||||||
|
Horizontal Rules can be inserted using three or more asterisks, dashes or underscores, optionally separated by spaces or tabs, on an otherwise blank line:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
Three or more...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Hyphens
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
Asterisks
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ignoring Markdown formatting
|
||||||
|
|
||||||
|
You can tell GitBook to ignore (or escape) Markdown formatting by using `\` before the Markdown character.
|
||||||
|
|
||||||
|
```
|
||||||
|
Let's rename \*our-new-project\* to \*our-old-project\*.
|
||||||
|
```
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# Templating
|
||||||
|
|
||||||
|
GitBook uses the [Nunjucks templating language](https://mozilla.github.io/nunjucks/) to process pages and theme's templates.
|
||||||
|
|
||||||
|
The Nunjucks syntax is very similar to **Jinja2** or **Liquid**. Its syntax uses surrounding braces `{ }` to mark content that needs to be processed.
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
|
||||||
|
A variable looks up a value from the template context. If you wanted to simply display a variable, you would use the `{{ variable }}` syntax. For example :
|
||||||
|
|
||||||
|
```twig
|
||||||
|
My name is {{ name }}, nice to meet you
|
||||||
|
```
|
||||||
|
|
||||||
|
This looks up username from the context and displays it. Variable names can have dots in them which lookup properties, just like JavaScript. You can also use the square bracket syntax.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{{ foo.bar }}
|
||||||
|
{{ foo["bar"] }}
|
||||||
|
```
|
||||||
|
|
||||||
|
If a value is undefined, nothing is displayed. The following all output nothing if foo is undefined: `{{ foo }}`, `{{ foo.bar }}`, `{{ foo.bar.baz }}`.
|
||||||
|
|
||||||
|
GitBook provides a set of [predefined variables](variables.md) from the context.
|
||||||
|
|
||||||
|
### Filters
|
||||||
|
|
||||||
|
Filters are essentially functions that can be applied to variables. They are called with a pipe operator (`|`) and can take arguments.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{{ foo | title }}
|
||||||
|
{{ foo | join(",") }}
|
||||||
|
{{ foo | replace("foo", "bar") | capitalize }}
|
||||||
|
```
|
||||||
|
|
||||||
|
The third example shows how you can chain filters. It would display "Bar", by first replacing "foo" with "bar" and then capitalizing it.
|
||||||
|
|
||||||
|
### Tags
|
||||||
|
|
||||||
|
##### if
|
||||||
|
|
||||||
|
`if` tests a condition and lets you selectively display content. It behaves exactly as JavaScript's `if` behaves.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% if variable %}
|
||||||
|
It is true
|
||||||
|
{% endif %}
|
||||||
|
```
|
||||||
|
|
||||||
|
If variable is defined and evaluates to true, "It is true" will be displayed. Otherwise, nothing will be.
|
||||||
|
|
||||||
|
You can specify alternate conditions with `elif` and `else`:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% if hungry %}
|
||||||
|
I am hungry
|
||||||
|
{% elif tired %}
|
||||||
|
I am tired
|
||||||
|
{% else %}
|
||||||
|
I am good!
|
||||||
|
{% endif %}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### for
|
||||||
|
|
||||||
|
`for` iterates over arrays and dictionaries.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
# Chapters about GitBook
|
||||||
|
|
||||||
|
{% for article in glossary.terms['gitbook'].articles %}
|
||||||
|
* [{{ article.title }}]({{ article.path }})
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### set
|
||||||
|
|
||||||
|
`set` lets you create/modify a variable.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% set softwareVersion = "1.0.0" %}
|
||||||
|
|
||||||
|
Current version is {{ softwareVersion }}.
|
||||||
|
[Download it](website.com/download/{{ softwareVersion }})
|
||||||
|
```
|
||||||
|
|
||||||
|
##### include and block
|
||||||
|
|
||||||
|
Inclusion and inheritance is detailled in the [Content References](conrefs.md) section.
|
||||||
|
|
||||||
|
### Escaping
|
||||||
|
|
||||||
|
If you want GitBook to ignore any of the special templating tags, you can use raw and anything inside of it will be output as plain text.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% raw %}
|
||||||
|
this will {{ not be processed }}
|
||||||
|
{% endraw %}
|
||||||
|
```
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Builtin Templating Helpers
|
||||||
|
|
||||||
|
GitBook provides a serie of builtin filters and blocks to help you write templates.
|
||||||
|
|
||||||
|
### Filters
|
||||||
|
|
||||||
|
`value|default(default, [boolean])`
|
||||||
|
If value is strictly undefined, return default, otherwise value. If boolean is true, any JavaScript falsy value will return default (false, "", etc)
|
||||||
|
|
||||||
|
`arr|sort(reverse, caseSens, attr)`
|
||||||
|
Sort arr with JavaScript's arr.sort function. If reverse is true, result will be reversed. Sort is case-insensitive by default, but setting caseSens to true makes it case-sensitive. If attr is passed, will compare attr from each item.
|
||||||
|
|
||||||
|
### Blocks
|
||||||
|
|
||||||
|
`{% markdown %}Markdown string{% endmarkdown %}`
|
||||||
|
Render inline markdown
|
||||||
|
|
||||||
|
`{% asciidoc %}AsciiDoc string{% endasciidoc %}`
|
||||||
|
Render inline asciidoc
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# Content References
|
||||||
|
|
||||||
|
Content referencing (conref) is a convenient mechanism to reuse content from other files or books.
|
||||||
|
|
||||||
|
### Importing local files
|
||||||
|
|
||||||
|
Importing an other file's content is easy using the `include` tag:
|
||||||
|
|
||||||
|
```
|
||||||
|
{% include "./test.md" %}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Importing file from another book
|
||||||
|
|
||||||
|
GitBook can also resolve the include path by using git:
|
||||||
|
|
||||||
|
```
|
||||||
|
{% include "git+https://github.com/GitbookIO/documentation.git/README.md#0.0.1" %}
|
||||||
|
```
|
||||||
|
|
||||||
|
The format of git url is:
|
||||||
|
|
||||||
|
```
|
||||||
|
git+https://user@hostname/owner/project.git/file#commit-ish
|
||||||
|
```
|
||||||
|
|
||||||
|
The real git url part should finish with `.git`, the filename to import is extracted after the `.git` till the fragment of the url.
|
||||||
|
|
||||||
|
The `commit-ish` can be any tag, sha, or branch which can be supplied as an argument to `git checkout`. The default is `master`.
|
||||||
|
|
||||||
|
### Inheritance
|
||||||
|
|
||||||
|
Template inheritance is a way to make it easy to reuse templates. When writing a template, you can define "blocks" that child templates can override. The inheritance chain can be as long as you like.
|
||||||
|
|
||||||
|
`block` defines a section on the template and identifies it with a name. Base templates can specify blocks and child templates can override them with new content.
|
||||||
|
|
||||||
|
```
|
||||||
|
{% extends "./mypage.md" %}
|
||||||
|
|
||||||
|
{% block pageContent %}
|
||||||
|
# This is my page content
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the file `mypage.md`, you should specify the blocks that can be extended:
|
||||||
|
|
||||||
|
```
|
||||||
|
{% block pageContent %}
|
||||||
|
This is the default content
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
{% include "./LICENSE" %}
|
||||||
|
```
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# Variables
|
||||||
|
|
||||||
|
The following is a reference of the available data during book's parsing and theme generation.
|
||||||
|
|
||||||
|
### Global Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `book` | Book-wide information + configuration settings from `book.json`. See below for details. |
|
||||||
|
| `gitbook` | GitBook specific information |
|
||||||
|
| `page` | Current page specific information |
|
||||||
|
| `file` | File associated with the current page specific information |
|
||||||
|
| `readme` | Information about the Readme |
|
||||||
|
| `glossary` | Information about the Glossary |
|
||||||
|
| `summary` | Information about the table of contents |
|
||||||
|
| `languages` | List of languages for multi-lingual books |
|
||||||
|
| `output` | Information about the output generator |
|
||||||
|
| `config` | Dump of the `book.json` |
|
||||||
|
|
||||||
|
### Book Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `book.language` | Current language for a multilingual book |
|
||||||
|
| `book.[value]` | All other values under `variables` in the `book.json` are accessible here |
|
||||||
|
|
||||||
|
For example, with this `book.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
variables: {
|
||||||
|
hello: "everyone"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
... the following text `{{ book.hello }}` will expand to `everyone`.
|
||||||
|
|
||||||
|
### GitBook Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `gitbook.time` | The current time (when you run the `gitbook` command). |
|
||||||
|
| `gitbook.version` | Version of GitBook used to generate the book |
|
||||||
|
|
||||||
|
### File Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `file.path` | The path to the raw page |
|
||||||
|
| `file.mtime` | Modified Time. Last time the file was modified |
|
||||||
|
| `file.type` | The name of the parser used to compile this file (ex: `markdown`, `asciidoc`, etc) |
|
||||||
|
|
||||||
|
#### Page Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `page.title` | Title of the page |
|
||||||
|
| `page.previous` | Previous page in the Table of Contents (can be `null`) |
|
||||||
|
| `page.next` | Next page in the Table of Contents (can be `null`) |
|
||||||
|
| `page.dir` | Text direction, based on configuration or detected from content (`rtl` or `ltr`) |
|
||||||
|
|
||||||
|
#### Table of Contents Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `summary.parts` | List of sections in the Table of Contents |
|
||||||
|
|
||||||
|
The whole table of contents (`SUMMARY.md`) can be accessed:
|
||||||
|
|
||||||
|
`summary.parts[0].articles[0].title` will return the title of the first article.
|
||||||
|
|
||||||
|
#### Multi-lingual book Variable
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `languages.list` | List of languages for this book |
|
||||||
|
|
||||||
|
Languages are defined by `{ id: 'en', title: 'English' }`.
|
||||||
|
|
||||||
|
### Output Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `output.name` | Name of the output generator, possible values are `website`, `json`, `ebook` |
|
||||||
|
| `output.format` | When `output.name == "ebook"`, `format` defines the ebook format that will be generated, possible values are `pdf`, `epub` or `mobi` |
|
||||||
|
|
||||||
|
### Readme Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `readme.path` | Path to the Readme in the book |
|
||||||
|
|
||||||
|
### Glossary Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `glossary.path` | Path to the Glossary in the book |
|
||||||
Vendored
+39
@@ -0,0 +1,39 @@
|
|||||||
|
# Theming
|
||||||
|
|
||||||
|
Since version 3.0.0, GitBook can be easily themed. Books use the [theme-default](https://github.com/GitbookIO/theme-default) theme by default.
|
||||||
|
|
||||||
|
> **Caution**: Custom theming can block some plugins from working correctly.
|
||||||
|
|
||||||
|
### Structure of a theme
|
||||||
|
|
||||||
|
A theme is a plugin containing templates and assets. Overriding any individual template is optional, since themes always extend the default theme.
|
||||||
|
|
||||||
|
| Folder | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `_layouts` | Main folder containing all the templates |
|
||||||
|
| `_layouts/website/page.html` | Template for a normal page |
|
||||||
|
| `_layouts/ebook/page.html` | Template for a normal page during ebook generation (PDF, ePub, Mobi) |
|
||||||
|
|
||||||
|
|
||||||
|
### Extend/Customize theme in a book
|
||||||
|
|
||||||
|
Authors can extend the templates of a theme directly from their book's source (without creating an external theme). Templates will be resolved in the `_layouts` folder of the book first, then in the installed plugins/themes.
|
||||||
|
|
||||||
|
### Extend instead of Forking
|
||||||
|
|
||||||
|
When you want to make your theme changes available to multiple books, instead of forking the default theme, you can extend it using the [templating syntax](../templating/README.md):
|
||||||
|
|
||||||
|
```html
|
||||||
|
{% extends template.self %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{{ super() }}
|
||||||
|
... This will be added to the "body" block
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Take a look at the [API](https://github.com/GitbookIO/theme-api) theme for a more complete example.
|
||||||
|
|
||||||
|
### Publish a theme
|
||||||
|
|
||||||
|
Themes are published as plugins ([see related docs](../plugins/README.md)) with a `theme-` prefix. For example the theme `awesome` will be loaded from the `theme-awesome` plugin, and then from the `gitbook-plugin-theme-awesome` NPM package.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"lerna": "2.0.0-beta.31",
|
||||||
|
"version": "4.0.0-alpha.3"
|
||||||
|
}
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
var util = require("util");
|
|
||||||
var path = require("path");
|
|
||||||
var Q = require("q");
|
|
||||||
var _ = require("lodash");
|
|
||||||
var exec = require('child_process').exec;
|
|
||||||
|
|
||||||
var fs = require("fs");
|
|
||||||
var parse = require("../../parse");
|
|
||||||
var BaseGenerator = require("../page");
|
|
||||||
var stringUtils = require("../../utils/string");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This generator inherits from the single page generator
|
|
||||||
* and convert the page output to ebook
|
|
||||||
*/
|
|
||||||
var Generator = function() {
|
|
||||||
BaseGenerator.apply(this, arguments);
|
|
||||||
};
|
|
||||||
util.inherits(Generator, BaseGenerator);
|
|
||||||
|
|
||||||
Generator.prototype.finish = function() {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
return BaseGenerator.prototype.finish.apply(this)
|
|
||||||
.then(function() {
|
|
||||||
var d = Q.defer();
|
|
||||||
var format = that.options.extension || path.extname(that.options.output).replace("\.", "") || "pdf";
|
|
||||||
|
|
||||||
if (!that.options.cover && fs.existsSync(path.join(that.options.output, "cover.jpg"))) {
|
|
||||||
that.options.cover = path.join(that.options.output, "cover.jpg");
|
|
||||||
}
|
|
||||||
|
|
||||||
var _options = {
|
|
||||||
"--cover": that.options.cover,
|
|
||||||
"--title": that.options.title,
|
|
||||||
"--comments": that.options.description,
|
|
||||||
"--authors": that.options.author,
|
|
||||||
"--level1-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-1 ')]",
|
|
||||||
"--level2-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-2 ')]",
|
|
||||||
"--level3-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-3 ')]"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (format == "pdf") {
|
|
||||||
var pdfOptions = _.defaults(that.options.pdf || {}, {
|
|
||||||
"fontSize": 12,
|
|
||||||
"toc": true,
|
|
||||||
"pageNumbers": false,
|
|
||||||
"paperSize": "a4",
|
|
||||||
"margin": {
|
|
||||||
"right": 62,
|
|
||||||
"left": 62,
|
|
||||||
"top": 36,
|
|
||||||
"bottom": 36
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
_.extend(_options, {
|
|
||||||
"--margin-left": String(pdfOptions.margin.left),
|
|
||||||
"--margin-right": String(pdfOptions.margin.right),
|
|
||||||
"--margin-top": String(pdfOptions.margin.top),
|
|
||||||
"--margin-bottom": String(pdfOptions.margin.bottom),
|
|
||||||
"--pdf-add-toc": Boolean(pdfOptions.toc),
|
|
||||||
"--pdf-default-font-size": String(pdfOptions.fontSize),
|
|
||||||
"--pdf-mono-font-size": String(pdfOptions.fontSize),
|
|
||||||
"--paper-size": String(pdfOptions.paperSize),
|
|
||||||
"--pdf-page-numbers": Boolean(pdfOptions.pageNumbers)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var command = [
|
|
||||||
"ebook-convert",
|
|
||||||
path.join(that.options.output, "index.html"),
|
|
||||||
path.join(that.options.output, "index."+format),
|
|
||||||
stringUtils.optionsToShellArgs(_options)
|
|
||||||
].join(" ");
|
|
||||||
|
|
||||||
exec(command, function (error, stdout, stderr) {
|
|
||||||
if (error) {
|
|
||||||
if (error.code == 127) {
|
|
||||||
error.message = "Need to install ebook-convert from Calibre";
|
|
||||||
} else {
|
|
||||||
error.message = error.message + " "+stdout;
|
|
||||||
}
|
|
||||||
return d.reject(error);
|
|
||||||
}
|
|
||||||
d.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
return d.promise;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Generator;
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
var Q = require("q");
|
|
||||||
var fs = require("fs");
|
|
||||||
var fsExtra = require("fs-extra");
|
|
||||||
var Ignore = require("fstream-ignore");
|
|
||||||
|
|
||||||
var getFiles = function(path) {
|
|
||||||
var d = Q.defer();
|
|
||||||
|
|
||||||
// Our list of files
|
|
||||||
var files = [];
|
|
||||||
|
|
||||||
var ig = Ignore({
|
|
||||||
path: path,
|
|
||||||
ignoreFiles: ['.ignore', '.gitignore', '.bookignore']
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add extra rules to ignore common folders
|
|
||||||
ig.addIgnoreRules([
|
|
||||||
// Skip Git stuff
|
|
||||||
'.git/',
|
|
||||||
'.gitignore',
|
|
||||||
|
|
||||||
// Skip OS X meta data
|
|
||||||
'.DS_Store',
|
|
||||||
|
|
||||||
// Skip stuff installed by plugins
|
|
||||||
'node_modules',
|
|
||||||
|
|
||||||
// Skip book outputs
|
|
||||||
'*.pdf',
|
|
||||||
'*.epub',
|
|
||||||
'*.mobi',
|
|
||||||
|
|
||||||
// Skip config files
|
|
||||||
'.ignore',
|
|
||||||
'.bookignore',
|
|
||||||
'book.json',
|
|
||||||
], '__custom_stuff');
|
|
||||||
|
|
||||||
// Push each file to our list
|
|
||||||
ig.on('child', function (c) {
|
|
||||||
files.push(
|
|
||||||
c.path.substr(c.root.path.length + 1) + (c.props.Directory === true ? '/' : '')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
ig.on('end', function() {
|
|
||||||
// Normalize paths on Windows
|
|
||||||
if(process.platform === 'win32') {
|
|
||||||
return d.resolve(files.map(function(file) {
|
|
||||||
return file.replace(/\\/g, '/');
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simply return paths otherwise
|
|
||||||
return d.resolve(files);
|
|
||||||
});
|
|
||||||
|
|
||||||
ig.on('error', d.reject);
|
|
||||||
|
|
||||||
return d.promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
list: getFiles,
|
|
||||||
readFile: Q.denodeify(fs.readFile),
|
|
||||||
writeFile: Q.denodeify(fs.writeFile),
|
|
||||||
mkdirp: Q.denodeify(fsExtra.mkdirp),
|
|
||||||
copy: Q.denodeify(fsExtra.copy),
|
|
||||||
remove: Q.denodeify(fsExtra.remove),
|
|
||||||
symlink: Q.denodeify(fsExtra.symlink),
|
|
||||||
exists: function(path) {
|
|
||||||
var d = Q.defer();
|
|
||||||
fs.exists(path, d.resolve);
|
|
||||||
return d.promise;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
var _ = require("lodash");
|
|
||||||
var path = require("path");
|
|
||||||
var Q = require("q");
|
|
||||||
var fs = require("./fs");
|
|
||||||
|
|
||||||
var Plugin = require("./plugin");
|
|
||||||
|
|
||||||
var BaseGenerator = function(options) {
|
|
||||||
this.options = options;
|
|
||||||
|
|
||||||
this.options.plugins = Plugin.normalizeNames(this.options.plugins);
|
|
||||||
this.options.plugins = _.union(this.options.plugins, this.options.defaultsPlugins);
|
|
||||||
this.plugins = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseGenerator.prototype.callHook = function(name, data) {
|
|
||||||
return this.plugins.hook(name, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseGenerator.prototype.loadPlugins = function() {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
return Plugin.fromList(this.options.plugins, this.options.input, this)
|
|
||||||
.then(function(_plugins) {
|
|
||||||
that.plugins = _plugins;
|
|
||||||
|
|
||||||
return that.callHook("init");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseGenerator.prototype.convertFile = function(content, input) {
|
|
||||||
return Q.reject(new Error("Could not convert "+input));
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseGenerator.prototype.transferFile = function(input) {
|
|
||||||
return fs.copy(
|
|
||||||
path.join(this.options.input, input),
|
|
||||||
path.join(this.options.output, input)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseGenerator.prototype.transferFolder = function(input) {
|
|
||||||
return fs.mkdirp(
|
|
||||||
path.join(this.options.output, input)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseGenerator.prototype.copyCover = function() {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
return Q.all([
|
|
||||||
fs.copy(path.join(this.options.input, "cover.jpg"), path.join(this.options.output, "cover.jpg")),
|
|
||||||
fs.copy(path.join(this.options.input, "cover_small.jpg"), path.join(this.options.output, "cover_small.jpg"))
|
|
||||||
])
|
|
||||||
.fail(function() {
|
|
||||||
// If orignally from multi-lang, try copy from originalInput
|
|
||||||
if (!that.options.originalInput) return;
|
|
||||||
|
|
||||||
return Q.all([
|
|
||||||
fs.copy(path.join(that.options.originalInput, "cover.jpg"), path.join(that.options.output, "cover.jpg")),
|
|
||||||
fs.copy(path.join(that.options.originalInput, "cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
|
|
||||||
]);
|
|
||||||
})
|
|
||||||
.fail(function(err) {
|
|
||||||
return Q();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseGenerator.prototype.langsIndex = function(langs) {
|
|
||||||
return Q.reject(new Error("Langs index is not supported in this generator"));
|
|
||||||
};
|
|
||||||
|
|
||||||
BaseGenerator.prototype.finish = function() {
|
|
||||||
return Q.reject(new Error("Could not finish generation"));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = BaseGenerator;
|
|
||||||
@@ -1,411 +0,0 @@
|
|||||||
var Q = require("q");
|
|
||||||
var _ = require("lodash");
|
|
||||||
var path = require("path");
|
|
||||||
var tmp = require('tmp');
|
|
||||||
|
|
||||||
var swig = require('./template');
|
|
||||||
var fs = require("./fs");
|
|
||||||
var parse = require("../parse");
|
|
||||||
var Plugin = require("./plugin");
|
|
||||||
|
|
||||||
var generators = {
|
|
||||||
"site": require("./site"),
|
|
||||||
"page": require("./page"),
|
|
||||||
"ebook": require("./ebook"),
|
|
||||||
"json": require("./json")
|
|
||||||
};
|
|
||||||
|
|
||||||
var defaultDescription = "Book generated using GitBook";
|
|
||||||
|
|
||||||
|
|
||||||
var containsFiles = function(dir, files) {
|
|
||||||
return Q.all(_.map(files, function(file) {
|
|
||||||
return fs.exists(path.join(dir, file));
|
|
||||||
}))
|
|
||||||
.then(_.all);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TEst if generator exists
|
|
||||||
var checkGenerator = function(options) {
|
|
||||||
if (!generators[options.generator]) {
|
|
||||||
return Q.reject(new Error("Invalid generator (availables are: "+_.keys(generators).join(", ")+")"));
|
|
||||||
}
|
|
||||||
return Q();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the generator and load plugins
|
|
||||||
var loadGenerator = function(options) {
|
|
||||||
return checkGenerator(options)
|
|
||||||
.then(function() {
|
|
||||||
var generator = new generators[options.generator](options);
|
|
||||||
|
|
||||||
return generator.loadPlugins()
|
|
||||||
.then(_.constant(generator));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var generate = function(options) {
|
|
||||||
// Set defaults to options
|
|
||||||
options = _.defaults(options || {}, {
|
|
||||||
// Folders to use
|
|
||||||
"input": null,
|
|
||||||
"output": null,
|
|
||||||
|
|
||||||
// Config file (relative to input)
|
|
||||||
"configFile": "book",
|
|
||||||
|
|
||||||
// Output generator
|
|
||||||
"generator": "site",
|
|
||||||
|
|
||||||
// Book title, keyword, description
|
|
||||||
"title": null,
|
|
||||||
"description": null,
|
|
||||||
|
|
||||||
// Origin github repository id
|
|
||||||
"github": null,
|
|
||||||
"githubHost": 'https://github.com/',
|
|
||||||
|
|
||||||
// Theming
|
|
||||||
"theme": path.resolve(__dirname, '../../theme'),
|
|
||||||
|
|
||||||
// Plugins
|
|
||||||
"plugins": [],
|
|
||||||
"pluginsConfig": {},
|
|
||||||
"defaultsPlugins": [], // Default plugins that can't be set in book.json
|
|
||||||
|
|
||||||
// Links
|
|
||||||
"links": {
|
|
||||||
"about": null,
|
|
||||||
"issues": null,
|
|
||||||
"contribue": null,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Validate options
|
|
||||||
if (!options.input) {
|
|
||||||
return Q.reject(new Error("Need option input (book input directory)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check files to get folder type (book, multilanguage book or neither)
|
|
||||||
return checkGenerator(options)
|
|
||||||
|
|
||||||
// Read config file
|
|
||||||
.then(function() {
|
|
||||||
try {
|
|
||||||
var _config = require(path.resolve(options.input, options.configFile));
|
|
||||||
|
|
||||||
_.extend(options, _.omit(_config, 'input', 'configFile', 'defaultsPlugins'));
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
// No config file: not a big deal
|
|
||||||
return Q();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Read readme
|
|
||||||
.then(function() {
|
|
||||||
return fs.readFile(path.join(options.input, "README.md"), "utf-8")
|
|
||||||
.then(function(_readme) {
|
|
||||||
_readme = parse.readme(_readme);
|
|
||||||
|
|
||||||
options.title = options.title || _readme.title;
|
|
||||||
options.description = options.description || _readme.description || defaultDescription;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
// Detect multi-languages book
|
|
||||||
.then(function() {
|
|
||||||
return containsFiles(options.input, ['LANGS.md'])
|
|
||||||
})
|
|
||||||
|
|
||||||
.then(function(isMultiLang) {
|
|
||||||
// Multi language book
|
|
||||||
if(isMultiLang) {
|
|
||||||
return generateMultiLang(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Book
|
|
||||||
return generateBook(options);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var generateMultiLang = function(options) {
|
|
||||||
var langsSummary;
|
|
||||||
options.output = options.output || path.join(options.input, "_book");
|
|
||||||
|
|
||||||
return checkGenerator(options)
|
|
||||||
|
|
||||||
// Multi-languages book
|
|
||||||
.then(function() {
|
|
||||||
return fs.readFile(path.join(options.input, "LANGS.md"), "utf-8")
|
|
||||||
})
|
|
||||||
|
|
||||||
// Clean output folder
|
|
||||||
.then(function(_langsSummary) {
|
|
||||||
langsSummary = _langsSummary;
|
|
||||||
return fs.remove(options.output);
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
return fs.mkdirp(options.output);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Generate sub-books
|
|
||||||
.then(function() {
|
|
||||||
options.langsSummary = parse.langs(langsSummary);
|
|
||||||
|
|
||||||
// Generated a book for each valid entry
|
|
||||||
return _.reduce(options.langsSummary.list, function(prev, entry) {
|
|
||||||
return prev.then(function() {
|
|
||||||
return generate(_.extend({}, options, {
|
|
||||||
input: path.join(options.input, entry.path),
|
|
||||||
output: path.join(options.output, entry.path),
|
|
||||||
originalInput: options.input,
|
|
||||||
originalOutput: options.output
|
|
||||||
}));
|
|
||||||
})
|
|
||||||
}, Q());
|
|
||||||
})
|
|
||||||
|
|
||||||
.then(function() {
|
|
||||||
return loadGenerator(options);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Generate languages index
|
|
||||||
.then(function(generator) {
|
|
||||||
return generator.langsIndex(options.langsSummary);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Copy cover file
|
|
||||||
.then(function() {
|
|
||||||
return Q.all([
|
|
||||||
fs.copy(path.join(options.input, "cover.jpg"), path.join(options.output, "cover.jpg")),
|
|
||||||
fs.copy(path.join(options.input, "cover_small.jpg"), path.join(options.output, "cover_small.jpg"))
|
|
||||||
])
|
|
||||||
.fail(function() {
|
|
||||||
return Q();
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Return options to caller
|
|
||||||
.then(_.constant(options));
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use a specific generator to convert a gitbook to a site/pdf/ebook/
|
|
||||||
* output is always a folder
|
|
||||||
*/
|
|
||||||
var generateBook = function(options) {
|
|
||||||
var files;
|
|
||||||
|
|
||||||
options.output = options.output || path.join(options.input, "_book");
|
|
||||||
|
|
||||||
// Check if it's a book
|
|
||||||
return containsFiles(options.input, ['SUMMARY.md', 'README.md'])
|
|
||||||
|
|
||||||
// Fail if not a book
|
|
||||||
.then(function(isBook) {
|
|
||||||
if(!isBook) {
|
|
||||||
return Q.reject(new Error("Invalid gitbook repository, need SUMMARY.md and README.md"));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Clean output folder
|
|
||||||
.then(function() {
|
|
||||||
return fs.remove(options.output);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Get repo's URL
|
|
||||||
.then(function() {
|
|
||||||
// Git deactivated
|
|
||||||
if(options.github === false) {
|
|
||||||
options.github = null;
|
|
||||||
return null;
|
|
||||||
} else if(options.github) {
|
|
||||||
// Git already specified in options
|
|
||||||
options.github = (
|
|
||||||
// Support URLs in "github" entry of book.json
|
|
||||||
parse.git.githubID(options.github) ||
|
|
||||||
|
|
||||||
// Fallback
|
|
||||||
options.github
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try auto detecting
|
|
||||||
return parse.git.url(options.input)
|
|
||||||
.then(function(_url) {
|
|
||||||
// Get ID of repo
|
|
||||||
return parse.git.githubID(_url);
|
|
||||||
}, function(err) {
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.then(function(repoId) {
|
|
||||||
options.github = repoId;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
.then(function() {
|
|
||||||
return fs.mkdirp(options.output);
|
|
||||||
})
|
|
||||||
|
|
||||||
// List all files in the repository
|
|
||||||
.then(function() {
|
|
||||||
return fs.list(options.input)
|
|
||||||
.then(function(_files) {
|
|
||||||
files = _files;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
.then(function() {
|
|
||||||
return loadGenerator(options);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Convert files
|
|
||||||
.then(function(generator) {
|
|
||||||
// Generate the book
|
|
||||||
return Q()
|
|
||||||
|
|
||||||
// Get summary
|
|
||||||
.then(function() {
|
|
||||||
var summary = {
|
|
||||||
path: path.join(options.input, "SUMMARY.md")
|
|
||||||
};
|
|
||||||
|
|
||||||
var _callHook = function(name) {
|
|
||||||
return generator.callHook(name, summary)
|
|
||||||
.then(function(_summary) {
|
|
||||||
summary = _summary;
|
|
||||||
return summary;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return fs.readFile(summary.path, "utf-8")
|
|
||||||
.then(function(_content) {
|
|
||||||
summary.content = _content;
|
|
||||||
return _callHook("summary:before");
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
summary.content = parse.summary(summary.content);
|
|
||||||
return _callHook("summary:after");
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
options.summary = summary.content;
|
|
||||||
options.navigation = parse.navigation(options.summary);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Skip processing some files
|
|
||||||
.then(function() {
|
|
||||||
files = _.filter(files, function (file) {
|
|
||||||
return !(
|
|
||||||
file === 'SUMMARY.md'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
// Copy file and replace markdown file
|
|
||||||
.then(function() {
|
|
||||||
return Q.all(
|
|
||||||
_.chain(files)
|
|
||||||
.map(function(file) {
|
|
||||||
if (!file) return;
|
|
||||||
|
|
||||||
if (file[file.length -1] == "/") {
|
|
||||||
return Q(generator.transferFolder(file));
|
|
||||||
} else if (path.extname(file) == ".md" && options.navigation[file] != null) {
|
|
||||||
return fs.readFile(path.join(options.input, file), "utf-8")
|
|
||||||
.then(function(content) {
|
|
||||||
return Q(generator.convertFile(content, file));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Q(generator.transferFile(file));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.value()
|
|
||||||
);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Finish generation
|
|
||||||
.then(function() {
|
|
||||||
return generator.finish();
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
return generator.callHook("finish");
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
// Return all options
|
|
||||||
.then(function() {
|
|
||||||
return options;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extract files from generate output in a temporary folder
|
|
||||||
*/
|
|
||||||
var generateFile = function(options) {
|
|
||||||
options = _.defaults(options || {}, {
|
|
||||||
input: null,
|
|
||||||
output: null,
|
|
||||||
extension: null
|
|
||||||
});
|
|
||||||
|
|
||||||
return Q.nfcall(tmp.dir)
|
|
||||||
.then(function(tmpDir) {
|
|
||||||
return generate(
|
|
||||||
_.extend({},
|
|
||||||
options,
|
|
||||||
{
|
|
||||||
output: tmpDir
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(function(_options) {
|
|
||||||
var ext = options.extension;
|
|
||||||
var outputFile = options.output || path.resolve(options.input, "book."+ext);
|
|
||||||
|
|
||||||
var copyFile = function(lang) {
|
|
||||||
var _outputFile = outputFile;
|
|
||||||
var _tmpDir = tmpDir;
|
|
||||||
|
|
||||||
if (lang) {
|
|
||||||
_outputFile = _outputFile.slice(0, -path.extname(_outputFile).length)+"_"+lang+path.extname(_outputFile);
|
|
||||||
_tmpDir = path.join(_tmpDir, lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fs.copy(
|
|
||||||
path.join(_tmpDir, "index."+ext),
|
|
||||||
_outputFile
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Multi-langs book
|
|
||||||
return Q()
|
|
||||||
.then(function() {
|
|
||||||
if (_options.langsSummary) {
|
|
||||||
return Q.all(
|
|
||||||
_.map(_options.langsSummary.list, function(lang) {
|
|
||||||
return copyFile(lang.lang);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return copyFile();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
return fs.remove(tmpDir);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
generators: generators,
|
|
||||||
folder: generate,
|
|
||||||
file: generateFile,
|
|
||||||
book: generateBook,
|
|
||||||
Plugin: Plugin,
|
|
||||||
};
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
var Q = require('q');
|
|
||||||
var _ = require('lodash');
|
|
||||||
|
|
||||||
var path = require('path');
|
|
||||||
|
|
||||||
var fs = require('./fs');
|
|
||||||
var parse = require('../parse');
|
|
||||||
|
|
||||||
|
|
||||||
// Extract paths out of a summary
|
|
||||||
function paths(summary) {
|
|
||||||
return _.reduce(summary.chapters, function(accu, chapter) {
|
|
||||||
return accu.concat(
|
|
||||||
_.filter([chapter.path].concat(_.pluck(chapter.articles, 'path')))
|
|
||||||
);
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the parent folders out of a group of files
|
|
||||||
function folders(files) {
|
|
||||||
return _.chain(files)
|
|
||||||
.map(function(file) {
|
|
||||||
return path.dirname(file);
|
|
||||||
})
|
|
||||||
.uniq()
|
|
||||||
.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
function initDir(dir) {
|
|
||||||
return fs.readFile(path.join(dir, 'SUMMARY.md'), 'utf8')
|
|
||||||
.then(function(src) {
|
|
||||||
// Parse summary
|
|
||||||
return parse.summary(src);
|
|
||||||
})
|
|
||||||
.then(function(summary) {
|
|
||||||
// Extract paths from summary
|
|
||||||
return paths(summary);
|
|
||||||
})
|
|
||||||
.then(function(paths) {
|
|
||||||
// Convert to absolute paths
|
|
||||||
return _.map(paths, function(file) {
|
|
||||||
return path.resolve(file);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(function(files) {
|
|
||||||
// Create folders
|
|
||||||
return Q.all(_.map(folders(files), function(folder) {
|
|
||||||
return fs.mkdirp(folder);
|
|
||||||
}))
|
|
||||||
.then(_.constant(files));
|
|
||||||
})
|
|
||||||
.then(function(files) {
|
|
||||||
// Create files that don't exist
|
|
||||||
return Q.all(_.map(files, function(file) {
|
|
||||||
return fs.exists(file)
|
|
||||||
.then(function(exists) {
|
|
||||||
if(exists) return;
|
|
||||||
return fs.writeFile(file, '');
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
})
|
|
||||||
.fail(function(err) {
|
|
||||||
console.error(err.stack);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = initDir;
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
var util = require("util");
|
|
||||||
var path = require("path");
|
|
||||||
var Q = require("q");
|
|
||||||
var _ = require("lodash");
|
|
||||||
|
|
||||||
var fs = require("../fs");
|
|
||||||
var parse = require("../../parse");
|
|
||||||
var BaseGenerator = require("../generator");
|
|
||||||
|
|
||||||
|
|
||||||
var Generator = function() {
|
|
||||||
BaseGenerator.apply(this, arguments);
|
|
||||||
};
|
|
||||||
util.inherits(Generator, BaseGenerator);
|
|
||||||
|
|
||||||
Generator.prototype.transferFile = function(input) {
|
|
||||||
// ignore
|
|
||||||
};
|
|
||||||
|
|
||||||
Generator.prototype.convertFile = function(content, input) {
|
|
||||||
var that = this;
|
|
||||||
var json = {
|
|
||||||
progress: parse.progress(this.options.navigation, input)
|
|
||||||
};
|
|
||||||
|
|
||||||
return Q()
|
|
||||||
.then(function() {
|
|
||||||
return parse.page(content, {
|
|
||||||
repo: that.options.githubId,
|
|
||||||
dir: path.dirname(input) || '/'
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(function(sections) {
|
|
||||||
json.sections = sections;
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
return fs.writeFile(
|
|
||||||
path.join(that.options.output, input.replace(".md", ".json")),
|
|
||||||
JSON.stringify(json, null, 4)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate languages index
|
|
||||||
// Contains the first languages readme and langs infos
|
|
||||||
Generator.prototype.langsIndex = function(langs) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
if (langs.list.length == 0) return Q.reject("Need at least one language");
|
|
||||||
|
|
||||||
var mainLang = _.first(langs.list).lang;
|
|
||||||
console.log("Main language is", mainLang);
|
|
||||||
|
|
||||||
return Q()
|
|
||||||
.then(function() {
|
|
||||||
return fs.readFile(
|
|
||||||
path.join(that.options.output, mainLang, "README.json")
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.then(function(content) {
|
|
||||||
var json = JSON.parse(content);
|
|
||||||
_.extend(json, {
|
|
||||||
langs: langs.list
|
|
||||||
});
|
|
||||||
|
|
||||||
return fs.writeFile(
|
|
||||||
path.join(that.options.output, "README.json"),
|
|
||||||
JSON.stringify(json, null, 4)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Generator.prototype.finish = function() {
|
|
||||||
// ignore
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Generator;
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
var _ = require('lodash');
|
|
||||||
var path = require('path');
|
|
||||||
var Q = require('q');
|
|
||||||
|
|
||||||
var fs = require("./fs");
|
|
||||||
|
|
||||||
var extsToIgnore = [".gz"]
|
|
||||||
|
|
||||||
var Manifest = function() {
|
|
||||||
this.revision = 0;
|
|
||||||
this.clear(Date.now());
|
|
||||||
};
|
|
||||||
|
|
||||||
// Regenerate manifest
|
|
||||||
Manifest.prototype.clear = function(revision) {
|
|
||||||
if (revision) this.revision = revision;
|
|
||||||
this.sections = {
|
|
||||||
'CACHE': {},
|
|
||||||
'NETWORK': {},
|
|
||||||
'FALLBACK': {}
|
|
||||||
};
|
|
||||||
return Q(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add a resource
|
|
||||||
Manifest.prototype.add = function(category, resource, value) {
|
|
||||||
if (_.isArray(resource)) {
|
|
||||||
_.each(resource, function(subres) {
|
|
||||||
this.add(category, subres, value);
|
|
||||||
}, this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.sections[category][resource] = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add a directory in cache
|
|
||||||
Manifest.prototype.addFolder = function(folder, root, except) {
|
|
||||||
var that = this;
|
|
||||||
root = root || "/";
|
|
||||||
|
|
||||||
return fs.list(folder)
|
|
||||||
.then(function(files) {
|
|
||||||
_.each(
|
|
||||||
// Ignore diretcories
|
|
||||||
_.filter(files, function(file) {
|
|
||||||
return file.substr(-1) != "/" && !_.contains(except, path.join(root, file)) && !_.contains(extsToIgnore, path.extname(file));
|
|
||||||
}),
|
|
||||||
function(file) {
|
|
||||||
that.add("CACHE", path.join(root, file));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get manifest content
|
|
||||||
Manifest.prototype.dump = function() {
|
|
||||||
var lines = [
|
|
||||||
"CACHE MANIFEST",
|
|
||||||
"# Revision "+this.revision
|
|
||||||
];
|
|
||||||
|
|
||||||
_.each(this.sections, function(content, section) {
|
|
||||||
if (_.size(content) == 0) return;
|
|
||||||
lines.push("");
|
|
||||||
lines.push(section+":");
|
|
||||||
lines = lines.concat(_.keys(content));
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
return Q(lines.join("\n"));
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Manifest;
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
var _ = require("lodash");
|
|
||||||
var util = require("util");
|
|
||||||
var path = require("path");
|
|
||||||
var Q = require("q");
|
|
||||||
var swig = require("../template");
|
|
||||||
|
|
||||||
var fs = require("../fs");
|
|
||||||
var parse = require("../../parse");
|
|
||||||
var BaseGenerator = require("../site");
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This generator will generate a simple index.html which can be converted as a PDF
|
|
||||||
*/
|
|
||||||
var Generator = function() {
|
|
||||||
BaseGenerator.apply(this, arguments);
|
|
||||||
|
|
||||||
// List of pages content
|
|
||||||
this.pages = {};
|
|
||||||
};
|
|
||||||
util.inherits(Generator, BaseGenerator);
|
|
||||||
|
|
||||||
// Load all templates
|
|
||||||
Generator.prototype.loadTemplates = function() {
|
|
||||||
this.template = swig.compileFile(
|
|
||||||
this.plugins.template("page") || path.resolve(this.options.theme, 'templates/page.html')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Generator.prototype.convertFile = function(content, input) {
|
|
||||||
var that = this;
|
|
||||||
var json = {
|
|
||||||
path: input,
|
|
||||||
progress: parse.progress(this.options.navigation, input)
|
|
||||||
};
|
|
||||||
|
|
||||||
return Q()
|
|
||||||
.then(function() {
|
|
||||||
return parse.page(content, {
|
|
||||||
repo: that.options.githubId,
|
|
||||||
dir: path.dirname(input) || '/',
|
|
||||||
outdir: './',
|
|
||||||
singleFile: true
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(function(sections) {
|
|
||||||
json.content = sections;
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
that.pages[input] = json;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate languages index
|
|
||||||
Generator.prototype.langsIndex = function(langs) {
|
|
||||||
return Q();
|
|
||||||
};
|
|
||||||
|
|
||||||
Generator.prototype.finish = function() {
|
|
||||||
var that = this;
|
|
||||||
var basePath = ".";
|
|
||||||
var output = path.join(this.options.output, "index.html");
|
|
||||||
|
|
||||||
var progress = parse.progress(this.options.navigation, "README.md");
|
|
||||||
|
|
||||||
return Q()
|
|
||||||
// Generate html
|
|
||||||
.then(function(pages) {
|
|
||||||
return that._writeTemplate(that.template, {
|
|
||||||
pages: that.pages,
|
|
||||||
progress: progress,
|
|
||||||
|
|
||||||
basePath: basePath,
|
|
||||||
staticBase: path.join(basePath, "gitbook"),
|
|
||||||
}, output);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Copy cover
|
|
||||||
.then(function() {
|
|
||||||
return that.copyCover();
|
|
||||||
})
|
|
||||||
|
|
||||||
// Copy assets
|
|
||||||
.then(function() {
|
|
||||||
return fs.copy(
|
|
||||||
path.join(that.options.theme, "assets"),
|
|
||||||
path.join(that.options.output, "gitbook")
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Generator;
|
|
||||||
@@ -1,279 +0,0 @@
|
|||||||
var _ = require("lodash");
|
|
||||||
var Q = require("q");
|
|
||||||
var semver = require("semver");
|
|
||||||
var path = require("path");
|
|
||||||
var url = require("url");
|
|
||||||
var fs = require("./fs");
|
|
||||||
var resolve = require('resolve');
|
|
||||||
|
|
||||||
var pkg = require("../../package.json");
|
|
||||||
|
|
||||||
var RESOURCES = ["js", "css"];
|
|
||||||
|
|
||||||
var Plugin = function(name, root, generator) {
|
|
||||||
this.name = name;
|
|
||||||
this.root = root;
|
|
||||||
this.packageInfos = {};
|
|
||||||
this.infos = {};
|
|
||||||
this.generator = generator;
|
|
||||||
|
|
||||||
// Bind methods
|
|
||||||
_.bindAll(this);
|
|
||||||
|
|
||||||
_.each([
|
|
||||||
"gitbook-plugin-"+name,
|
|
||||||
"gitbook-theme-"+name,
|
|
||||||
"gitbook-"+name,
|
|
||||||
name,
|
|
||||||
], function(_name) {
|
|
||||||
if (this.load(_name, __dirname)) return false;
|
|
||||||
if (this.load(_name, path.resolve(root))) return false;
|
|
||||||
}, this);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load from a name
|
|
||||||
Plugin.prototype.load = function(name, baseDir) {
|
|
||||||
try {
|
|
||||||
var res = resolve.sync(name+"/package.json", { basedir: baseDir });
|
|
||||||
|
|
||||||
this.baseDir = path.dirname(res);
|
|
||||||
this.packageInfos = require(res);
|
|
||||||
this.infos = require(resolve.sync(name, { basedir: baseDir }));
|
|
||||||
this.name = name;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Plugin.prototype.normalizeResource = function(resource) {
|
|
||||||
// Parse the resource path
|
|
||||||
var parsed = url.parse(resource);
|
|
||||||
|
|
||||||
// This is a remote resource
|
|
||||||
// so we will simply link to using it's URL
|
|
||||||
if (parsed.protocol) {
|
|
||||||
return {
|
|
||||||
"url": resource
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will be copied over from disk
|
|
||||||
// and shipped with the book's build
|
|
||||||
return { "path": this.name+"/"+resource };
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return resources
|
|
||||||
Plugin.prototype._getResources = function() {
|
|
||||||
var book = this.infos.book;
|
|
||||||
|
|
||||||
// Nothing specified, fallback to default
|
|
||||||
if (!book) {
|
|
||||||
return Q({});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamic function
|
|
||||||
if(typeof book === "function") {
|
|
||||||
// Call giving it the context of our generator
|
|
||||||
return Q().then(book.bind(this.generator));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plain data object
|
|
||||||
return Q(_.cloneDeep(book));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Normalize resources and return them
|
|
||||||
Plugin.prototype.getResources = function() {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return this._getResources()
|
|
||||||
.then(function(resources) {
|
|
||||||
|
|
||||||
_.each(RESOURCES, function(resourceType) {
|
|
||||||
resources[resourceType] = (resources[resourceType] || []).map(that.normalizeResource);
|
|
||||||
});
|
|
||||||
|
|
||||||
return resources;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Test if it's a valid plugin
|
|
||||||
Plugin.prototype.isValid = function() {
|
|
||||||
return (
|
|
||||||
this.packageInfos &&
|
|
||||||
this.packageInfos.name &&
|
|
||||||
this.packageInfos.engines &&
|
|
||||||
this.packageInfos.engines.gitbook &&
|
|
||||||
semver.satisfies(pkg.version, this.packageInfos.engines.gitbook)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Resolve file path
|
|
||||||
Plugin.prototype.resolveFile = function(filename) {
|
|
||||||
return path.resolve(this.baseDir, filename);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Resolve file path
|
|
||||||
Plugin.prototype.callHook = function(name, data) {
|
|
||||||
// Our generator will be the context to apply
|
|
||||||
var context = this.generator;
|
|
||||||
|
|
||||||
var hookFunc = this.infos.hooks? this.infos.hooks[name] : null;
|
|
||||||
data = data || {};
|
|
||||||
|
|
||||||
if (!hookFunc) return Q(data);
|
|
||||||
|
|
||||||
return Q()
|
|
||||||
.then(function() {
|
|
||||||
return hookFunc.apply(context, [data]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Copy plugin assets fodler
|
|
||||||
Plugin.prototype.copyAssets = function(out) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
return this.getResources().get('assets')
|
|
||||||
.then(function(assets) {
|
|
||||||
// Assets are undefined
|
|
||||||
if(!assets) return false;
|
|
||||||
|
|
||||||
return fs.copy(
|
|
||||||
that.resolveFile(assets),
|
|
||||||
out
|
|
||||||
).then(_.constant(true));
|
|
||||||
}, _.constant(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Normalize a list of plugin name to use
|
|
||||||
Plugin.normalizeNames = function(names) {
|
|
||||||
// Normalize list to an array
|
|
||||||
names = _.isString(names) ? names.split(",") : (names || []);
|
|
||||||
|
|
||||||
// List plugins to remove
|
|
||||||
var toremove = _.chain(names)
|
|
||||||
.filter(function(name) {
|
|
||||||
return name.length > 0 && name[0] == "-";
|
|
||||||
})
|
|
||||||
.map(function(name) {
|
|
||||||
return name.slice(1);
|
|
||||||
})
|
|
||||||
.value();
|
|
||||||
|
|
||||||
// Merge with defaults
|
|
||||||
names = _.chain(names)
|
|
||||||
.concat(Plugin.defaults)
|
|
||||||
.uniq()
|
|
||||||
.value();
|
|
||||||
|
|
||||||
// Remove plugins starting with
|
|
||||||
names = _.filter(names, function(name) {
|
|
||||||
return !_.contains(toremove, name) && !(name.length > 0 && name[0] == "-");
|
|
||||||
});
|
|
||||||
|
|
||||||
return names;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Extract data from a list of plugin
|
|
||||||
Plugin.fromList = function(names, root, generator) {
|
|
||||||
var failed = [];
|
|
||||||
|
|
||||||
// Load plugins
|
|
||||||
var plugins = _.map(names, function(name) {
|
|
||||||
var plugin = new Plugin(name, root, generator);
|
|
||||||
if (!plugin.isValid()) failed.push(name);
|
|
||||||
return plugin;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (_.size(failed) > 0) return Q.reject(new Error("Error loading plugins: "+failed.join(",")));
|
|
||||||
|
|
||||||
// The raw resources extracted from each plugin
|
|
||||||
var pluginResources;
|
|
||||||
|
|
||||||
// Get resources of plugins
|
|
||||||
return Q.all(_.map(plugins, function(plugin) {
|
|
||||||
return plugin.getResources();
|
|
||||||
}))
|
|
||||||
// Extract resources out
|
|
||||||
// css, js, etc ...
|
|
||||||
.then(function(resources) {
|
|
||||||
pluginResources = resources;
|
|
||||||
// Group by resource types
|
|
||||||
return _.chain(RESOURCES)
|
|
||||||
.map(function(resourceType) {
|
|
||||||
// Get resources from all the plugins for this current type
|
|
||||||
return [
|
|
||||||
// Key
|
|
||||||
resourceType,
|
|
||||||
// Value
|
|
||||||
_.chain(resources)
|
|
||||||
.pluck(resourceType)
|
|
||||||
.compact()
|
|
||||||
.flatten()
|
|
||||||
.value()
|
|
||||||
];
|
|
||||||
})
|
|
||||||
.object()
|
|
||||||
.value();
|
|
||||||
})
|
|
||||||
// Extract html snippets
|
|
||||||
.then(function(resources) {
|
|
||||||
// Map of html resources by name added by each plugin
|
|
||||||
resources.html = pluginResources.reduce(function(accu, resource) {
|
|
||||||
var html = (resource && resource.html) || {};
|
|
||||||
_.each(html, function(code, key) {
|
|
||||||
// Turn into function if not one already
|
|
||||||
if (!_.isFunction(code)) code = _.constant(code);
|
|
||||||
// Append
|
|
||||||
accu[key] = (accu[key] || []).concat([code]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return accu;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
return resources;
|
|
||||||
})
|
|
||||||
// Return big multi-plugin object
|
|
||||||
.then(function(resources) {
|
|
||||||
return {
|
|
||||||
'list': plugins,
|
|
||||||
'resources': resources,
|
|
||||||
'hook': function(name, data) {
|
|
||||||
return _.reduce(plugins, function(prev, plugin) {
|
|
||||||
return prev.then(function(ret) {
|
|
||||||
return plugin.callHook(name, ret);
|
|
||||||
});
|
|
||||||
}, Q(data));
|
|
||||||
},
|
|
||||||
'template': function(name) {
|
|
||||||
var withTpl = _.find(plugins, function(plugin) {
|
|
||||||
return (
|
|
||||||
plugin.infos.templates &&
|
|
||||||
plugin.infos.templates[name]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!withTpl) return null;
|
|
||||||
return withTpl.resolveFile(withTpl.infos.templates[name]);
|
|
||||||
},
|
|
||||||
'html': function(tag, context, options) {
|
|
||||||
return _.map(resources.html[tag] || [], function(code) {
|
|
||||||
return code.call(context, options);
|
|
||||||
}).join("\n");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Default plugins
|
|
||||||
Plugin.defaults = [
|
|
||||||
"mathjax"
|
|
||||||
];
|
|
||||||
|
|
||||||
module.exports = Plugin;
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
var util = require("util");
|
|
||||||
var path = require("path");
|
|
||||||
var Q = require("q");
|
|
||||||
var _ = require("lodash");
|
|
||||||
var swig = require("../template");
|
|
||||||
|
|
||||||
var fs = require("../fs");
|
|
||||||
var parse = require("../../parse");
|
|
||||||
var BaseGenerator = require("../generator");
|
|
||||||
var links = require("../../utils/links");
|
|
||||||
var indexer = require('./search_indexer');
|
|
||||||
var Manifest = require('../manifest');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var Generator = function() {
|
|
||||||
BaseGenerator.apply(this, arguments);
|
|
||||||
|
|
||||||
// Attach methods to instance
|
|
||||||
_.bindAll(this);
|
|
||||||
|
|
||||||
this.revision = Date.now();
|
|
||||||
this.indexer = indexer();
|
|
||||||
this.manifest = new Manifest(Date.now());
|
|
||||||
this.manifest.add("NETWORK", [
|
|
||||||
'*'
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
util.inherits(Generator, BaseGenerator);
|
|
||||||
|
|
||||||
// Load all templates
|
|
||||||
Generator.prototype.loadTemplates = function() {
|
|
||||||
this.template = swig.compileFile(
|
|
||||||
this.plugins.template("site") || path.resolve(this.options.theme, 'templates/site.html')
|
|
||||||
);
|
|
||||||
this.langsTemplate = swig.compileFile(
|
|
||||||
this.plugins.template("langs") || path.resolve(this.options.theme, 'templates/langs.html')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load plugins
|
|
||||||
Generator.prototype.loadPlugins = function() {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
return BaseGenerator.prototype.loadPlugins.apply(this)
|
|
||||||
.then(function() {
|
|
||||||
return that.loadTemplates();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate a template
|
|
||||||
Generator.prototype._writeTemplate = function(tpl, options, output, interpolate) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
interpolate = interpolate || _.identity;
|
|
||||||
return Q()
|
|
||||||
.then(function(sections) {
|
|
||||||
return tpl(_.extend({
|
|
||||||
revision: that.revision,
|
|
||||||
|
|
||||||
title: that.options.title,
|
|
||||||
description: that.options.description,
|
|
||||||
|
|
||||||
githubAuthor: that.options.github ? that.options.github.split("/")[0] : "",
|
|
||||||
githubId: that.options.github,
|
|
||||||
githubHost: that.options.githubHost,
|
|
||||||
|
|
||||||
summary: that.options.summary,
|
|
||||||
allNavigation: that.options.navigation,
|
|
||||||
|
|
||||||
plugins: that.plugins,
|
|
||||||
pluginsConfig: JSON.stringify(that.options.pluginsConfig),
|
|
||||||
htmlSnippet: _.partialRight(that.plugins.html, that, options),
|
|
||||||
|
|
||||||
options: that.options
|
|
||||||
}, options));
|
|
||||||
})
|
|
||||||
.then(interpolate)
|
|
||||||
.then(function(html) {
|
|
||||||
return fs.writeFile(
|
|
||||||
output,
|
|
||||||
html
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Generator.prototype.indexPage = function(lexed, pagePath) {
|
|
||||||
this.indexer.add(lexed, pagePath);
|
|
||||||
return Q();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Convert a markdown file to html
|
|
||||||
Generator.prototype.convertFile = function(content, _input) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
_output = _input.replace(".md", ".html");
|
|
||||||
if (_output == "README.html") _output = "index.html";
|
|
||||||
|
|
||||||
var input = path.join(this.options.input, _input);
|
|
||||||
var output = path.join(this.options.output, _output);
|
|
||||||
var basePath = path.relative(path.dirname(output), this.options.output) || ".";
|
|
||||||
|
|
||||||
var page = {
|
|
||||||
path: _input,
|
|
||||||
rawPath: input, // path to raw md file
|
|
||||||
content: content,
|
|
||||||
progress: parse.progress(this.options.navigation, _input)
|
|
||||||
};
|
|
||||||
|
|
||||||
var _callHook = function(name) {
|
|
||||||
return that.callHook(name, page)
|
|
||||||
.then(function(_page) {
|
|
||||||
page = _page;
|
|
||||||
return page;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return Q()
|
|
||||||
.then(function() {
|
|
||||||
// Send content to plugins
|
|
||||||
return _callHook("page:before");
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
// Lex page
|
|
||||||
return parse.lex(page.content);
|
|
||||||
})
|
|
||||||
.then(function(lexed) {
|
|
||||||
// Index page in search
|
|
||||||
return that.indexPage(lexed, _output)
|
|
||||||
.then(_.constant(lexed));
|
|
||||||
})
|
|
||||||
.then(function(lexed) {
|
|
||||||
// Get HTML generated sections
|
|
||||||
return parse.page(lexed, {
|
|
||||||
repo: that.options.githubId,
|
|
||||||
dir: path.dirname(_input) || '/',
|
|
||||||
outdir: path.dirname(_input) || '/',
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(function(sections) {
|
|
||||||
page.sections = sections;
|
|
||||||
|
|
||||||
// Use plugin hook
|
|
||||||
return _callHook("page");
|
|
||||||
})
|
|
||||||
.then(function() {
|
|
||||||
that.manifest.add("CACHE", _output);
|
|
||||||
|
|
||||||
return that._writeTemplate(that.template, {
|
|
||||||
progress: page.progress,
|
|
||||||
|
|
||||||
_input: _input,
|
|
||||||
content: page.sections,
|
|
||||||
|
|
||||||
basePath: basePath,
|
|
||||||
staticBase: links.join(basePath, "gitbook"),
|
|
||||||
}, output, function(html) {
|
|
||||||
page.content = html;
|
|
||||||
|
|
||||||
return _callHook("page:after").get("content")
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate languages index
|
|
||||||
Generator.prototype.langsIndex = function(langs) {
|
|
||||||
var that = this;
|
|
||||||
var basePath = ".";
|
|
||||||
|
|
||||||
return this._writeTemplate(this.langsTemplate, {
|
|
||||||
langs: langs.list,
|
|
||||||
|
|
||||||
basePath: basePath,
|
|
||||||
staticBase: path.join(basePath, "gitbook"),
|
|
||||||
}, path.join(this.options.output, "index.html"))
|
|
||||||
.then(function() {
|
|
||||||
// Copy assets
|
|
||||||
return that.copyAssets();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Copy assets
|
|
||||||
Generator.prototype.copyAssets = function() {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
// Copy gitbook assets
|
|
||||||
return fs.copy(
|
|
||||||
path.join(that.options.theme, "assets"),
|
|
||||||
path.join(that.options.output, "gitbook")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Add to cache manifest
|
|
||||||
.then(function() {
|
|
||||||
return that.manifest.addFolder(path.join(that.options.output, "gitbook"), "gitbook");
|
|
||||||
})
|
|
||||||
|
|
||||||
// Copy plugins assets
|
|
||||||
.then(function() {
|
|
||||||
return Q.all(
|
|
||||||
_.map(that.plugins.list, function(plugin) {
|
|
||||||
var pluginAssets = path.join(that.options.output, "gitbook/plugins/", plugin.name);
|
|
||||||
return plugin.copyAssets(pluginAssets)
|
|
||||||
.then(function(copiedStuff) {
|
|
||||||
// Nothing was copied
|
|
||||||
if(!copiedStuff) { return; }
|
|
||||||
return that.manifest.addFolder(pluginAssets, "gitbook/plugins/"+plugin.name);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dump search index to disk
|
|
||||||
Generator.prototype.writeSearchIndex = function() {
|
|
||||||
return fs.writeFile(
|
|
||||||
path.join(this.options.output, 'search_index.json'),
|
|
||||||
this.indexer.dump()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Add cache manifest
|
|
||||||
Generator.prototype.writeCacheManifest = function() {
|
|
||||||
return fs.writeFile(
|
|
||||||
path.join(this.options.output, 'manifest.appcache'),
|
|
||||||
this.manifest.dump()
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Generator.prototype.finish = function() {
|
|
||||||
var deferred = this.copyAssets()
|
|
||||||
.then(this.copyCover)
|
|
||||||
.then(this.writeSearchIndex);
|
|
||||||
|
|
||||||
if (this.options.cache !== false) {
|
|
||||||
deferred = deferred.then(this.writeCacheManifest);
|
|
||||||
}
|
|
||||||
|
|
||||||
return deferred;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Generator;
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
var Q = require("q");
|
|
||||||
var _ = require("lodash");
|
|
||||||
|
|
||||||
var lunr = require('lunr');
|
|
||||||
var marked = require('marked');
|
|
||||||
var textRenderer = require('marked-text-renderer');
|
|
||||||
|
|
||||||
|
|
||||||
function Indexer() {
|
|
||||||
if(!(this instanceof Indexer)) {
|
|
||||||
return new Indexer();
|
|
||||||
}
|
|
||||||
|
|
||||||
_.bindAll(this);
|
|
||||||
|
|
||||||
// Setup lunr index
|
|
||||||
this.idx = lunr(function () {
|
|
||||||
this.ref('url');
|
|
||||||
|
|
||||||
this.field('title', { boost: 10 });
|
|
||||||
this.field('body');
|
|
||||||
});
|
|
||||||
|
|
||||||
this.renderer = textRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
Indexer.prototype.text = function(nodes) {
|
|
||||||
// Copy section
|
|
||||||
var section = _.toArray(nodes);
|
|
||||||
|
|
||||||
// marked's Render expects this, we don't use it yet
|
|
||||||
section.links = {};
|
|
||||||
|
|
||||||
var options = _.extend({}, marked.defaults, {
|
|
||||||
renderer: this.renderer
|
|
||||||
});
|
|
||||||
|
|
||||||
return marked.parser(section, options);
|
|
||||||
};
|
|
||||||
|
|
||||||
Indexer.prototype.addSection = function(path, section) {
|
|
||||||
var url = [path, section.id].join('#');
|
|
||||||
|
|
||||||
var title = this.text(
|
|
||||||
_.filter(section, {'type': 'heading'})
|
|
||||||
);
|
|
||||||
|
|
||||||
var body = this.text(
|
|
||||||
_.omit(section, {'type': 'heading'})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add to lunr index
|
|
||||||
this.idx.add({
|
|
||||||
url: url,
|
|
||||||
title: title,
|
|
||||||
body: body,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Indexer.prototype.add = function(lexedPage, url) {
|
|
||||||
var sections = lexedPage;
|
|
||||||
|
|
||||||
_.map(sections, _.partial(this.addSection, url));
|
|
||||||
};
|
|
||||||
|
|
||||||
Indexer.prototype.dump = function() {
|
|
||||||
return JSON.stringify(this.idx);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = Indexer;
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
var path = require("path");
|
|
||||||
var swig = require('swig');
|
|
||||||
var hljs = require('highlight.js');
|
|
||||||
|
|
||||||
var links = require('../utils/').links;
|
|
||||||
var pkg = require('../../package.json');
|
|
||||||
|
|
||||||
swig.setDefaults({
|
|
||||||
locals: {
|
|
||||||
gitbook: {
|
|
||||||
version: pkg.version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Swig filter for returning the count of lines in a code section
|
|
||||||
swig.setFilter('lines', function(content) {
|
|
||||||
return content.split('\n').length;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Swig filter for returning a link to the associated html file of a markdown file
|
|
||||||
swig.setFilter('mdLink', function(link) {
|
|
||||||
var link = link.replace(".md", ".html");
|
|
||||||
if (link == "README.html") link = "index.html";
|
|
||||||
return link;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Swig filter: highlight coloration
|
|
||||||
swig.setFilter('code', function(code, lang) {
|
|
||||||
try {
|
|
||||||
return hljs.highlight(lang, code).value;
|
|
||||||
} catch(e) {
|
|
||||||
return hljs.highlightAuto(code).value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Convert a level into a deep level
|
|
||||||
swig.setFilter('lvl', function(lvl) {
|
|
||||||
return lvl.split(".").length;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Join path
|
|
||||||
swig.setFilter('pathJoin', function(base, _path) {
|
|
||||||
return path.join(base, _path);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Is a link an absolute link
|
|
||||||
swig.setFilter('isExternalLink', function(link) {
|
|
||||||
return links.isExternal(link);
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = swig;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
parse: require('./parse/'),
|
|
||||||
generate: require('./generate/')
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
var fs = require('fs');
|
|
||||||
var path = require('path');
|
|
||||||
|
|
||||||
module.exports = function(code, folder) {
|
|
||||||
folder = folder || '';
|
|
||||||
|
|
||||||
return code.replace(/{{([\s\S]+?)}}/g, function(match, filename) {
|
|
||||||
// Normalize filename
|
|
||||||
var fname = path.join(folder, filename.trim());
|
|
||||||
|
|
||||||
// Try including snippet from FS
|
|
||||||
try {
|
|
||||||
// Trim trailing newlines/space of imported snippets
|
|
||||||
return fs.readFileSync(fname, 'utf8').trimRight();
|
|
||||||
} catch(err) {}
|
|
||||||
|
|
||||||
// If fails leave content as is
|
|
||||||
return match;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
var Q = require('q');
|
|
||||||
var _ = require('lodash');
|
|
||||||
var cp = require('child_process');
|
|
||||||
var url = require('url');
|
|
||||||
|
|
||||||
// Get the remote of a given repo
|
|
||||||
function gitURL(path) {
|
|
||||||
var d = Q.defer();
|
|
||||||
|
|
||||||
cp.exec("git config --get remote.origin.url", {
|
|
||||||
cwd: path,
|
|
||||||
env: process.env,
|
|
||||||
}, function(err, stdout, stderr) {
|
|
||||||
if(err) {
|
|
||||||
return d.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.resolve(stdout);
|
|
||||||
});
|
|
||||||
|
|
||||||
return d.promise
|
|
||||||
.then(function(output) {
|
|
||||||
return output.replace(/(\r\n|\n|\r)/gm, "");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Poorman's parsing
|
|
||||||
// Parse a git URL to a github ID : username/reponame
|
|
||||||
function githubID(_url) {
|
|
||||||
// Remove .git if it's in _url
|
|
||||||
var sliceEnd = _url.slice(-4) === '.git' ? -4 : undefined;
|
|
||||||
|
|
||||||
// Detect HTTPS repos
|
|
||||||
var parsed = url.parse(_url);
|
|
||||||
if(parsed.protocol === 'https:' && parsed.host === 'github.com') {
|
|
||||||
return parsed.path.slice(1, sliceEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect SSH repos
|
|
||||||
if(_url.indexOf('git@') === 0) {
|
|
||||||
return _url.split(':', 2)[1].slice(0, sliceEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// None found
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function titleCase(str) {
|
|
||||||
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
url: gitURL,
|
|
||||||
githubID: githubID,
|
|
||||||
titleCase: titleCase
|
|
||||||
};
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
summary: require('./summary'),
|
|
||||||
langs: require('./langs'),
|
|
||||||
page: require('./page'),
|
|
||||||
lex: require('./lex'),
|
|
||||||
progress: require('./progress'),
|
|
||||||
navigation: require('./navigation'),
|
|
||||||
readme: require('./readme'),
|
|
||||||
git: require('./git')
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
var _ = require("lodash");
|
|
||||||
var parseEntries = require("./summary").entries;
|
|
||||||
|
|
||||||
|
|
||||||
var parseLangs = function(content) {
|
|
||||||
var entries = parseEntries(content);
|
|
||||||
|
|
||||||
return {
|
|
||||||
list: _.chain(entries)
|
|
||||||
.filter(function(entry) {
|
|
||||||
return Boolean(entry.path);
|
|
||||||
})
|
|
||||||
.map(function(entry) {
|
|
||||||
return {
|
|
||||||
title: entry.title,
|
|
||||||
path: entry.path,
|
|
||||||
lang: entry.path.replace("/", "")
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.value()
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = parseLangs;
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
var _ = require('lodash');
|
|
||||||
var marked = require('marked');
|
|
||||||
|
|
||||||
// Split a page up into sections (lesson, exercises, ...)
|
|
||||||
function splitSections(nodes) {
|
|
||||||
var section = [];
|
|
||||||
|
|
||||||
return _.reduce(nodes, function(sections, el) {
|
|
||||||
if(el.type === 'hr') {
|
|
||||||
sections.push(section);
|
|
||||||
section = [];
|
|
||||||
} else {
|
|
||||||
section.push(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sections;
|
|
||||||
}, []).concat([section]); // Add remaining nodes
|
|
||||||
}
|
|
||||||
|
|
||||||
function isQuizNode(node) {
|
|
||||||
return (/^[(\[][ x][)\]]/).test(node.text || node);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isExercise(nodes) {
|
|
||||||
var codeType = { type: 'code' };
|
|
||||||
|
|
||||||
// Number of code nodes in section
|
|
||||||
var len = _.filter(nodes, codeType).length;
|
|
||||||
|
|
||||||
return (
|
|
||||||
// Got 3 or 4 code blocks
|
|
||||||
(len === 3 || len === 4) &&
|
|
||||||
// Ensure all nodes are at the end
|
|
||||||
_.all(_.last(nodes, len), codeType)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isQuiz(nodes) {
|
|
||||||
if (nodes.length < 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support having a first paragraph block
|
|
||||||
// before our series of questions
|
|
||||||
var quizNodes = nodes.slice(nodes[0].type === 'paragraph' ? 1 : 0);
|
|
||||||
|
|
||||||
// No questions
|
|
||||||
if (!_.some(quizNodes, { type: 'blockquote_start' })) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if section has list of questions
|
|
||||||
// or table of questions
|
|
||||||
var listIdx = _.findIndex(quizNodes, { type: 'list_item_start' });
|
|
||||||
var tableIdx = _.findIndex(quizNodes, { type: 'table' });
|
|
||||||
|
|
||||||
if(
|
|
||||||
// List of questions
|
|
||||||
listIdx !== -1 && isQuizNode(quizNodes[listIdx + 1]) ||
|
|
||||||
|
|
||||||
// Table of questions
|
|
||||||
(
|
|
||||||
tableIdx !== -1 &&
|
|
||||||
_.every(quizNodes[tableIdx].cells[0].slice(1), isQuizNode)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// What is the type of this section
|
|
||||||
function sectionType(nodes, idx) {
|
|
||||||
if(isExercise(nodes)) {
|
|
||||||
return 'exercise';
|
|
||||||
} else if(isQuiz(nodes)) {
|
|
||||||
return 'quiz';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'normal';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a uniqueId to identify this section in our code
|
|
||||||
function sectionId(section, idx) {
|
|
||||||
return _.uniqueId('gitbook_');
|
|
||||||
}
|
|
||||||
|
|
||||||
function lexPage(src) {
|
|
||||||
// Lex file
|
|
||||||
var nodes = marked.lexer(src);
|
|
||||||
|
|
||||||
return _.chain(splitSections(nodes))
|
|
||||||
.map(function(section, idx) {
|
|
||||||
// Detect section type
|
|
||||||
section.type = sectionType(section, idx);
|
|
||||||
return section;
|
|
||||||
})
|
|
||||||
.map(function(section, idx) {
|
|
||||||
// Give each section an ID
|
|
||||||
section.id = sectionId(section, idx);
|
|
||||||
return section;
|
|
||||||
|
|
||||||
})
|
|
||||||
.filter(function(section) {
|
|
||||||
return !_.isEmpty(section);
|
|
||||||
})
|
|
||||||
.reduce(function(sections, section) {
|
|
||||||
var last = _.last(sections);
|
|
||||||
|
|
||||||
// Merge normal sections together
|
|
||||||
if(last && last.type === section.type && last.type === 'normal') {
|
|
||||||
last.push.apply(last, [{'type': 'hr'}].concat(section));
|
|
||||||
} else {
|
|
||||||
// Add to list of sections
|
|
||||||
sections.push(section);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sections;
|
|
||||||
}, [])
|
|
||||||
.map(function(section) {
|
|
||||||
section.links = nodes.links;
|
|
||||||
return section;
|
|
||||||
})
|
|
||||||
.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = lexPage;
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
var _ = require('lodash');
|
|
||||||
|
|
||||||
// Cleans up an article/chapter object
|
|
||||||
// remove 'articles' attributes
|
|
||||||
function clean(obj) {
|
|
||||||
return obj && _.omit(obj, ['articles']);
|
|
||||||
}
|
|
||||||
|
|
||||||
function flattenChapters(chapters) {
|
|
||||||
return _.reduce(chapters, function(accu, chapter) {
|
|
||||||
return accu.concat([clean(chapter)].concat(flattenChapters(chapter.articles)));
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns from a summary a map of
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"file/path.md": {
|
|
||||||
prev: ...,
|
|
||||||
next: ...,
|
|
||||||
},
|
|
||||||
...
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
function navigation(summary, files) {
|
|
||||||
// Support single files as well as list
|
|
||||||
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
|
|
||||||
|
|
||||||
// List of all navNodes
|
|
||||||
// Flatten chapters, then add in default README node if ndeeded etc ...
|
|
||||||
var navNodes = flattenChapters(summary.chapters);
|
|
||||||
var prevNodes = [null].concat(navNodes.slice(0, -1));
|
|
||||||
var nextNodes = navNodes.slice(1).concat([null]);
|
|
||||||
|
|
||||||
// Mapping of prev/next for a give path
|
|
||||||
var mapping = _.chain(_.zip(navNodes, prevNodes, nextNodes))
|
|
||||||
.map(function(nodes) {
|
|
||||||
var current = nodes[0], prev = nodes[1], next = nodes[2];
|
|
||||||
|
|
||||||
// Skip if no path
|
|
||||||
if(!current.path) return null;
|
|
||||||
|
|
||||||
return [current.path, {
|
|
||||||
title: current.title,
|
|
||||||
prev: prev,
|
|
||||||
next: next,
|
|
||||||
level: current.level,
|
|
||||||
}];
|
|
||||||
})
|
|
||||||
.filter()
|
|
||||||
.object()
|
|
||||||
.value();
|
|
||||||
|
|
||||||
// Filter for only files we want
|
|
||||||
if(files) {
|
|
||||||
return _.pick(mapping, files);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = navigation;
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
var _ = require('lodash');
|
|
||||||
var marked = require('marked');
|
|
||||||
var hljs = require('highlight.js');
|
|
||||||
|
|
||||||
var lex = require('./lex');
|
|
||||||
var renderer = require('./renderer');
|
|
||||||
|
|
||||||
var codeInclude = require('./code_include');
|
|
||||||
var lnormalize = require('../utils/lang').normalize;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Render a section using our custom renderer
|
|
||||||
function render(section, _options) {
|
|
||||||
// Copy section
|
|
||||||
var links = section.links || {};
|
|
||||||
section = _.toArray(section);
|
|
||||||
section.links = links;
|
|
||||||
|
|
||||||
// Build options using defaults and our custom renderer
|
|
||||||
var options = _.extend({}, marked.defaults, {
|
|
||||||
renderer: renderer(null, _options),
|
|
||||||
|
|
||||||
// Synchronous highlighting with highlight.js
|
|
||||||
highlight: function (code, lang) {
|
|
||||||
if(!lang) return code;
|
|
||||||
|
|
||||||
// Normalize lang
|
|
||||||
lang = lnormalize(lang);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return hljs.highlight(lang, code).value;
|
|
||||||
} catch(e) { }
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return marked.parser(section, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
function quizQuestion(node) {
|
|
||||||
if (node.text) {
|
|
||||||
node.text = node.text.replace(/^([\[(])x([\])])/, "$1 $2");
|
|
||||||
} else {
|
|
||||||
return node.replace(/^([\[(])x([\])])/, "$1 $2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parsePage(src, options) {
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
// Lex if not already lexed
|
|
||||||
return (_.isArray(src) ? src : lex(src))
|
|
||||||
.map(function(section) {
|
|
||||||
// Transform given type
|
|
||||||
if(section.type === 'exercise') {
|
|
||||||
var nonCodeNodes = _.reject(section, {
|
|
||||||
'type': 'code'
|
|
||||||
});
|
|
||||||
|
|
||||||
var codeNodes = _.filter(section, {
|
|
||||||
'type': 'code'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Languages in code blocks
|
|
||||||
var langs = _.pluck(codeNodes, 'lang').map(lnormalize);
|
|
||||||
|
|
||||||
// Check that they are all the same
|
|
||||||
var validLangs = _.all(_.map(langs, function(lang) {
|
|
||||||
return lang && lang === langs[0];
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Main language
|
|
||||||
var lang = validLangs ? langs[0] : null;
|
|
||||||
|
|
||||||
// codeInclude shortcut
|
|
||||||
var ci = function(code) {
|
|
||||||
return codeInclude(code, options.dir);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: section.id,
|
|
||||||
type: section.type,
|
|
||||||
content: render(nonCodeNodes),
|
|
||||||
lang: lang,
|
|
||||||
code: {
|
|
||||||
base: ci(codeNodes[0].text),
|
|
||||||
solution: ci(codeNodes[1].text),
|
|
||||||
validation: ci(codeNodes[2].text),
|
|
||||||
// Context is optional
|
|
||||||
context: codeNodes[3] ? codeNodes[3].text : null,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if (section.type === 'quiz') {
|
|
||||||
var quiz = [], question, foundFeedback = false;
|
|
||||||
var nonQuizNodes = section[0].type === 'paragraph' && section[1].type !== 'list_start' ? [section[0]] : [];
|
|
||||||
var quizNodes = section.slice(0);
|
|
||||||
quizNodes.splice(0, nonQuizNodes.length);
|
|
||||||
|
|
||||||
for (var i = 0; i < quizNodes.length; i++) {
|
|
||||||
var node = quizNodes[i];
|
|
||||||
|
|
||||||
if (question && (((node.type === 'list_end' || node.type === 'blockquote_end') && i === quizNodes.length - 1)
|
|
||||||
|| node.type === 'table' || (node.type === 'paragraph' && !foundFeedback))) {
|
|
||||||
quiz.push({
|
|
||||||
base: render(question.questionNodes),
|
|
||||||
solution: render(question.solutionNodes),
|
|
||||||
feedback: render(question.feedbackNodes)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.type === 'table' || (node.type === 'paragraph' && !foundFeedback)) {
|
|
||||||
question = { questionNodes: [], solutionNodes: [], feedbackNodes: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.type === 'blockquote_start') {
|
|
||||||
foundFeedback = true;
|
|
||||||
} else if (node.type === 'blockquote_end') {
|
|
||||||
foundFeedback = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.type === 'table') {
|
|
||||||
question.solutionNodes.push(_.cloneDeep(node));
|
|
||||||
node.cells = node.cells.map(function(row) {
|
|
||||||
return row.map(quizQuestion);
|
|
||||||
});
|
|
||||||
question.questionNodes.push(node);
|
|
||||||
} else if (!/blockquote/.test(node.type)) {
|
|
||||||
if (foundFeedback) {
|
|
||||||
question.feedbackNodes.push(node);
|
|
||||||
} else if (node.type === 'paragraph' || node.type === 'text'){
|
|
||||||
question.solutionNodes.push(_.cloneDeep(node));
|
|
||||||
quizQuestion(node);
|
|
||||||
question.questionNodes.push(node);
|
|
||||||
} else {
|
|
||||||
question.solutionNodes.push(node);
|
|
||||||
question.questionNodes.push(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: section.id,
|
|
||||||
type: section.type,
|
|
||||||
content: render(nonQuizNodes),
|
|
||||||
quiz: quiz
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render normal pages
|
|
||||||
return {
|
|
||||||
id: section.id,
|
|
||||||
type: section.type,
|
|
||||||
content: render(section, options)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = parsePage;
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
var _ = require("lodash");
|
|
||||||
|
|
||||||
// Returns from a navigation and a current file, a snapshot of current detailed state
|
|
||||||
var calculProgress = function(navigation, current) {
|
|
||||||
var n = _.size(navigation);
|
|
||||||
var percent = 0, prevPercent = 0, currentChapter = null;
|
|
||||||
var done = true;
|
|
||||||
|
|
||||||
var chapters = _.chain(navigation)
|
|
||||||
.map(function(nav, path) {
|
|
||||||
nav.path = path;
|
|
||||||
return nav;
|
|
||||||
})
|
|
||||||
.map(function(nav, i) {
|
|
||||||
// Calcul percent
|
|
||||||
nav.percent = (i * 100) / Math.max((n - 1), 1);
|
|
||||||
|
|
||||||
// Is it done
|
|
||||||
nav.done = done;
|
|
||||||
if (nav.path == current) {
|
|
||||||
currentChapter = nav;
|
|
||||||
percent = nav.percent;
|
|
||||||
done = false;
|
|
||||||
} else if (done) {
|
|
||||||
prevPercent = nav.percent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nav;
|
|
||||||
})
|
|
||||||
.value();
|
|
||||||
|
|
||||||
return {
|
|
||||||
// Previous percent
|
|
||||||
prevPercent: prevPercent,
|
|
||||||
|
|
||||||
// Current percent
|
|
||||||
percent: percent,
|
|
||||||
|
|
||||||
// List of chapter with progress
|
|
||||||
chapters: chapters,
|
|
||||||
|
|
||||||
// Current chapter
|
|
||||||
current: currentChapter
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = calculProgress;
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
var _ = require('lodash');
|
|
||||||
var marked = require('marked');
|
|
||||||
var textRenderer = require('marked-text-renderer');
|
|
||||||
|
|
||||||
function extractFirstNode(nodes, nType) {
|
|
||||||
return _.chain(nodes)
|
|
||||||
.filter(function(node) {
|
|
||||||
return node.type == nType;
|
|
||||||
})
|
|
||||||
.pluck("text")
|
|
||||||
.first()
|
|
||||||
.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function parseReadme(src) {
|
|
||||||
var nodes, title, description;
|
|
||||||
var renderer = textRenderer();
|
|
||||||
|
|
||||||
// Parse content
|
|
||||||
nodes = marked.lexer(src);
|
|
||||||
|
|
||||||
title = extractFirstNode(nodes, "heading") || '';
|
|
||||||
description = extractFirstNode(nodes, "paragraph") || '';
|
|
||||||
|
|
||||||
var convert = _.compose(
|
|
||||||
function(text) {
|
|
||||||
return _.unescape(text.replace(/(\r\n|\n|\r)/gm, ""));
|
|
||||||
},
|
|
||||||
function(text) {
|
|
||||||
return marked.parse(text, _.extend({}, marked.defaults, {
|
|
||||||
renderer: renderer
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
title: convert(title),
|
|
||||||
description: convert(description)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = parseReadme;
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
var url = require('url');
|
|
||||||
var inherits = require('util').inherits;
|
|
||||||
var links = require('../utils').links;
|
|
||||||
var codeInclude = require('./code_include');
|
|
||||||
|
|
||||||
|
|
||||||
var path = require('path');
|
|
||||||
|
|
||||||
var marked = require('marked');
|
|
||||||
|
|
||||||
var rendererId = 0;
|
|
||||||
|
|
||||||
function GitBookRenderer(options, extra_options) {
|
|
||||||
if(!(this instanceof GitBookRenderer)) {
|
|
||||||
return new GitBookRenderer(options, extra_options);
|
|
||||||
}
|
|
||||||
GitBookRenderer.super_.call(this, options);
|
|
||||||
|
|
||||||
this._extra_options = extra_options;
|
|
||||||
this.quizRowId = 0;
|
|
||||||
this.id = rendererId++;
|
|
||||||
this.quizIndex = 0;
|
|
||||||
}
|
|
||||||
inherits(GitBookRenderer, marked.Renderer);
|
|
||||||
|
|
||||||
GitBookRenderer.prototype._unsanitized = function(href) {
|
|
||||||
var prot = '';
|
|
||||||
try {
|
|
||||||
prot = decodeURIComponent(unescape(href))
|
|
||||||
.replace(/[^\w:]/g, '')
|
|
||||||
.toLowerCase();
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(prot.indexOf('javascript:') === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
GitBookRenderer.prototype.link = function(href, title, text) {
|
|
||||||
// Our "fixed" href
|
|
||||||
var _href = href;
|
|
||||||
|
|
||||||
// Don't build if it looks malicious
|
|
||||||
if (this.options.sanitize && this._unsanitized(href)) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parsed version of the url
|
|
||||||
var parsed = url.parse(href);
|
|
||||||
|
|
||||||
var o = this._extra_options;
|
|
||||||
|
|
||||||
// Relative link, rewrite it to point to github repo
|
|
||||||
if(links.isRelative(_href)) {
|
|
||||||
if (path.extname(parsed.path) == ".md") {
|
|
||||||
_href = links.toAbsolute(_href, o.dir || "./", o.outdir || "./");
|
|
||||||
|
|
||||||
if (o.singleFile) {
|
|
||||||
_href = "#"+_href;
|
|
||||||
} else {
|
|
||||||
_href = _href.replace(".md", ".html");
|
|
||||||
}
|
|
||||||
} else if (o && o.repo && o.dir) {
|
|
||||||
href = url.resolve('https://github.com/' + o.repo + '/blob/', [o.dir, _href].join("/"));
|
|
||||||
parsed = url.parse(href);
|
|
||||||
_href = parsed.href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate HTML for link
|
|
||||||
var out = '<a href="' + _href + '"';
|
|
||||||
// Title if no null
|
|
||||||
if (title) {
|
|
||||||
out += ' title="' + title + '"';
|
|
||||||
}
|
|
||||||
// Target blank if external
|
|
||||||
if(parsed.protocol) {
|
|
||||||
out += ' target="_blank"';
|
|
||||||
}
|
|
||||||
out += '>' + text + '</a>';
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
|
|
||||||
GitBookRenderer.prototype.image = function(href, title, text) {
|
|
||||||
// Our "fixed" href
|
|
||||||
var _href = href;
|
|
||||||
|
|
||||||
// Parsed version of the url
|
|
||||||
var parsed = url.parse(href);
|
|
||||||
|
|
||||||
// Options
|
|
||||||
var o = this._extra_options;
|
|
||||||
|
|
||||||
// Relative image, rewrite it depending output
|
|
||||||
if(links.isRelative(href) && o && o.dir && o.outdir) {
|
|
||||||
// o.dir: directory parent of the file currently in rendering process
|
|
||||||
// o.outdir: directory parent from the html output
|
|
||||||
|
|
||||||
_href = links.toAbsolute(_href, o.dir, o.outdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GitBookRenderer.super_.prototype.image.call(this, _href, title, text);
|
|
||||||
};
|
|
||||||
|
|
||||||
GitBookRenderer.prototype.tablerow = function(content) {
|
|
||||||
this.quizRowId += 1;
|
|
||||||
return GitBookRenderer.super_.prototype.tablerow(content);
|
|
||||||
};
|
|
||||||
|
|
||||||
var fieldRegex = /^([(\[])([ x])[\])]/;
|
|
||||||
GitBookRenderer.prototype._createCheckboxAndRadios = function(text) {
|
|
||||||
var match = fieldRegex.exec(text);
|
|
||||||
if (!match) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
var quizIdentifier = 'quiz-row-' + this.id + '-' + this.quizRowId + '-' + this.quizIndex++;
|
|
||||||
var field = "<input name='" + quizIdentifier + "' id='" + quizIdentifier + "' type='";
|
|
||||||
field += match[1] === '(' ? "radio" : "checkbox";
|
|
||||||
field += match[2] === 'x' ? "' checked/>" : "'/>";
|
|
||||||
var splittedText = text.split(fieldRegex);
|
|
||||||
var length = splittedText.length;
|
|
||||||
var label = '<label class="quiz-label" for="' + quizIdentifier + '">' + splittedText[length - 1] + '</label>';
|
|
||||||
return text.replace(fieldRegex, field).replace(splittedText[length - 1], label);
|
|
||||||
};
|
|
||||||
|
|
||||||
GitBookRenderer.prototype.tablecell = function(content, flags) {
|
|
||||||
return GitBookRenderer.super_.prototype.tablecell(this._createCheckboxAndRadios(content), flags);
|
|
||||||
};
|
|
||||||
|
|
||||||
GitBookRenderer.prototype.listitem = function(text) {
|
|
||||||
return GitBookRenderer.super_.prototype.listitem(this._createCheckboxAndRadios(text));
|
|
||||||
};
|
|
||||||
|
|
||||||
GitBookRenderer.prototype.code = function(code, lang, escaped) {
|
|
||||||
return GitBookRenderer.super_.prototype.code.call(
|
|
||||||
this,
|
|
||||||
// Import code snippets
|
|
||||||
codeInclude(code, this._extra_options.dir),
|
|
||||||
lang,
|
|
||||||
escaped
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
GitBookRenderer.prototype.heading = function(text, level, raw) {
|
|
||||||
var id = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w -]+/g, '').replace(/ /g, '-');
|
|
||||||
return '<h' + level + ' id="' + id + '">' + text + '</h' + level + '>\n';
|
|
||||||
};
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = GitBookRenderer;
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
var _ = require('lodash');
|
|
||||||
var marked = require('marked');
|
|
||||||
|
|
||||||
|
|
||||||
// Utility function for splitting a list into groups
|
|
||||||
function splitBy(list, starter, ender) {
|
|
||||||
var starts = 0;
|
|
||||||
var ends = 0;
|
|
||||||
var group = [];
|
|
||||||
|
|
||||||
// Groups
|
|
||||||
return _.reduce(list, function(groups, value) {
|
|
||||||
// Ignore start and end delimiters in resulted groups
|
|
||||||
if(starter(value)) {
|
|
||||||
starts++;
|
|
||||||
} else if(ender(value)) {
|
|
||||||
ends++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add current value to group
|
|
||||||
group.push(value);
|
|
||||||
|
|
||||||
// We've got a matching
|
|
||||||
if(starts === ends && starts !== 0) {
|
|
||||||
// Add group to end groups
|
|
||||||
// (remove starter and ender token)
|
|
||||||
groups.push(group.slice(1, -1));
|
|
||||||
|
|
||||||
// Reset group
|
|
||||||
group = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups;
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function listSplit(nodes, start_type, end_type) {
|
|
||||||
return splitBy(nodes, function(el) {
|
|
||||||
return el.type === start_type;
|
|
||||||
}, function(el) {
|
|
||||||
return el.type === end_type;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the biggest list
|
|
||||||
// out of a list of marked nodes
|
|
||||||
function filterList(nodes) {
|
|
||||||
return _.chain(nodes)
|
|
||||||
.toArray()
|
|
||||||
.rest(function(el) {
|
|
||||||
// Get everything after list_start
|
|
||||||
return el.type !== 'list_start';
|
|
||||||
})
|
|
||||||
.reverse()
|
|
||||||
.rest(function(el) {
|
|
||||||
// Get everything after list_end (remember we're reversed)
|
|
||||||
return el.type !== 'list_end';
|
|
||||||
})
|
|
||||||
.reverse()
|
|
||||||
.value().slice(1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses an Article or Chapter title
|
|
||||||
// supports extracting links
|
|
||||||
function parseTitle(src, nums) {
|
|
||||||
// Check if it's a link
|
|
||||||
var matches = marked.InlineLexer.rules.link.exec(src);
|
|
||||||
|
|
||||||
var level = nums.join('.');
|
|
||||||
|
|
||||||
// Not a link, return plain text
|
|
||||||
if(!matches) {
|
|
||||||
return {
|
|
||||||
title: src,
|
|
||||||
level: level,
|
|
||||||
path: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
title: matches[1],
|
|
||||||
level: level,
|
|
||||||
|
|
||||||
// Normalize path
|
|
||||||
// 1. Convert Window's "\" to "/"
|
|
||||||
// 2. Remove leading "/" if exists
|
|
||||||
path: matches[2].replace(/\\/g, '/').replace(/^\/+/, ''),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseChapter(nodes, nums) {
|
|
||||||
// Convert single number to an array
|
|
||||||
nums = _.isArray(nums) ? nums : [nums];
|
|
||||||
|
|
||||||
return _.extend(parseTitle(_.first(nodes).text, nums), {
|
|
||||||
articles: _.map(listSplit(filterList(nodes), 'list_item_start', 'list_item_end'), function(nodes, i) {
|
|
||||||
return parseChapter(nodes, nums.concat(i + 1));
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultChapterList(chapterList) {
|
|
||||||
var first = _.first(chapterList);
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
var chapter = parseChapter(first, [0]);
|
|
||||||
|
|
||||||
// Already have README node, we're good to go
|
|
||||||
if(chapter.path === 'README.md') {
|
|
||||||
return chapterList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
[ { type: 'text', text: '[Introduction](README.md)' } ]
|
|
||||||
].concat(chapterList);
|
|
||||||
}
|
|
||||||
|
|
||||||
function listGroups(src) {
|
|
||||||
var nodes = marked.lexer(src);
|
|
||||||
|
|
||||||
// Get out groups of lists
|
|
||||||
return listSplit(
|
|
||||||
filterList(nodes),
|
|
||||||
'list_item_start', 'list_item_end'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseSummary(src) {
|
|
||||||
// Split out chapter sections
|
|
||||||
var chapters = defaultChapterList(listGroups(src))
|
|
||||||
.map(parseChapter);
|
|
||||||
|
|
||||||
return {
|
|
||||||
chapters: chapters
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseEntries (src) {
|
|
||||||
return listGroups(src).map(parseChapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = parseSummary;
|
|
||||||
module.exports.entries = parseEntries;
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
lang: require('./lang'),
|
|
||||||
links: require('./links')
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
var MAP = {
|
|
||||||
'py': 'python',
|
|
||||||
'js': 'javascript',
|
|
||||||
'rb': 'ruby',
|
|
||||||
'csharp': 'cs',
|
|
||||||
};
|
|
||||||
|
|
||||||
function normalize(lang) {
|
|
||||||
if(!lang) { return null; }
|
|
||||||
|
|
||||||
var lower = lang.toLowerCase();
|
|
||||||
return MAP[lower] || lower;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = {
|
|
||||||
normalize: normalize,
|
|
||||||
MAP: MAP
|
|
||||||
};
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
var url = require('url');
|
|
||||||
var path = require('path');
|
|
||||||
|
|
||||||
// Is the link an external link
|
|
||||||
var isExternal = function(href) {
|
|
||||||
try {
|
|
||||||
return Boolean(url.parse(href).protocol);
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return true if the link is relative
|
|
||||||
var isRelative = function(href) {
|
|
||||||
try {
|
|
||||||
var parsed = url.parse(href);
|
|
||||||
|
|
||||||
return !parsed.protocol && parsed.path && parsed.path[0] != '/';
|
|
||||||
} catch(err) {}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Relative to absolute path
|
|
||||||
// dir: directory parent of the file currently in rendering process
|
|
||||||
// outdir: directory parent from the html output
|
|
||||||
|
|
||||||
var toAbsolute = function(_href, dir, outdir) {
|
|
||||||
// Absolute file in source
|
|
||||||
_href = path.join(dir, _href);
|
|
||||||
|
|
||||||
// make it relative to output
|
|
||||||
_href = path.relative(outdir, _href);
|
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
_href = _href.replace(/\\/g, '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
return _href;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Join links
|
|
||||||
|
|
||||||
var join = function() {
|
|
||||||
var _href = path.join.apply(path, arguments);
|
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
_href = _href.replace(/\\/g, '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
return _href;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
isRelative: isRelative,
|
|
||||||
isExternal: isExternal,
|
|
||||||
toAbsolute: toAbsolute,
|
|
||||||
join: join
|
|
||||||
};
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
var _ = require("lodash");
|
|
||||||
|
|
||||||
function escapeShellArg(arg) {
|
|
||||||
var ret = '';
|
|
||||||
|
|
||||||
ret = arg.replace(/"/g, '\\"');
|
|
||||||
|
|
||||||
return "\"" + ret + "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
function optionsToShellArgs(options) {
|
|
||||||
return _.chain(options)
|
|
||||||
.map(function(value, key) {
|
|
||||||
if (value == null || value == false) return null;
|
|
||||||
if (value == true) return key;
|
|
||||||
return key+"="+escapeShellArg(value);
|
|
||||||
})
|
|
||||||
.compact()
|
|
||||||
.value()
|
|
||||||
.join(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
escapeShellArg: escapeShellArg,
|
|
||||||
optionsToShellArgs: optionsToShellArgs
|
|
||||||
};
|
|
||||||
+24
-64
@@ -1,66 +1,26 @@
|
|||||||
{
|
{
|
||||||
"name": "gitbook",
|
"private": true,
|
||||||
"version": "0.6.3",
|
"devDependencies": {
|
||||||
"homepage": "http://www.gitbook.io/",
|
"eslint": "3.12.2",
|
||||||
"description": "Library and cmd utility to generate GitBooks",
|
"eslint-config-gitbook": "1.5.0",
|
||||||
"main": "lib/index.js",
|
"lerna": "2.0.0-beta.31"
|
||||||
"dependencies": {
|
},
|
||||||
"q": "1.0.1",
|
"scripts": {
|
||||||
"lodash": "2.4.1",
|
"lint": "eslint .",
|
||||||
"marked": "0.3.2",
|
"test": "lerna run --concurrency 1 test",
|
||||||
"marked-text-renderer": "0.0.1",
|
"bootstrap": "lerna bootstrap",
|
||||||
"lunr": "0.5.2",
|
"clean": "lerna clean",
|
||||||
"swig": "1.3.2",
|
"dist": "lerna run --concurrency 1 prepublish",
|
||||||
"send": "0.2.0",
|
"publish-version": "./scripts/publish.sh"
|
||||||
"fstream-ignore": "0.0.7",
|
},
|
||||||
"commander": "2.2.0",
|
"repository": {
|
||||||
"fs-extra": "0.8.1",
|
"type": "git",
|
||||||
"highlight.js": "8.0.0",
|
"url": "git+https://github.com/GitbookIO/gitbook.git"
|
||||||
"tmp": "0.0.23",
|
},
|
||||||
"semver": "2.2.1",
|
"author": "GitBook Inc. <contact@gitbook.com>",
|
||||||
"gaze": "~0.5.1",
|
"license": "Apache-2.0",
|
||||||
"resolve": "0.6.3",
|
"bugs": {
|
||||||
"tiny-lr-fork": "0.0.5",
|
"url": "https://github.com/GitbookIO/gitbook/issues"
|
||||||
"gitbook-plugin": "0.0.2",
|
},
|
||||||
"gitbook-plugin-mathjax": "0.0.4",
|
"homepage": "https://github.com/GitbookIO/gitbook#readme"
|
||||||
"gitbook-plugin-livereload": "0.0.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"mocha": "1.18.2",
|
|
||||||
"grunt": "~0.4.2",
|
|
||||||
"grunt-cli": "0.1.11",
|
|
||||||
"grunt-contrib-less": "~0.5.0",
|
|
||||||
"grunt-contrib-requirejs": "0.4.1",
|
|
||||||
"grunt-bower-install-simple": "0.9.2"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "export TESTING=true; mocha --reporter list"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"gitbook": "./bin/gitbook.js"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/GitbookIO/gitbook.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"git",
|
|
||||||
"book",
|
|
||||||
"gitbook"
|
|
||||||
],
|
|
||||||
"author": "FriendCode <contact@friendco.de>",
|
|
||||||
"license": "Apache 2",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/GitbookIO/gitbook/issues"
|
|
||||||
},
|
|
||||||
"contributors": [
|
|
||||||
{
|
|
||||||
"name": "Aaron O'Mullan",
|
|
||||||
"email": "aaron.omullan@gmail.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Samy Pessé",
|
|
||||||
"email": "samypesse@gmail.com"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"presets": ["es2015", "react", "stage-2"]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
gitbook.core.min.js
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
src
|
||||||
|
!lib
|
||||||
|
!dist
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"name": "gitbook-core",
|
||||||
|
"version": "4.0.0-alpha.3",
|
||||||
|
"description": "Core for GitBook plugins API",
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"bluebird": "^3.4.6",
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"entities": "^1.1.1",
|
||||||
|
"history": "^4.3.0",
|
||||||
|
"html-tags": "^1.1.1",
|
||||||
|
"immutable": "^3.8.1",
|
||||||
|
"mousetrap": "1.6.0",
|
||||||
|
"react": "15.4.1",
|
||||||
|
"react-addons-css-transition-group": "15.4.1",
|
||||||
|
"react-dom": "15.4.1",
|
||||||
|
"react-helmet": "^3.1.0",
|
||||||
|
"react-immutable-proptypes": "^2.1.0",
|
||||||
|
"react-intl": "^2.1.5",
|
||||||
|
"react-redux": "^4.4.5",
|
||||||
|
"react-safe-html": "0.4.0",
|
||||||
|
"redux": "^3.5.2",
|
||||||
|
"redux-thunk": "^2.1.0",
|
||||||
|
"reflexbox": "^2.2.2",
|
||||||
|
"whatwg-fetch": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-cli": "^6.14.0",
|
||||||
|
"babel-preset-es2015": "^6.14.0",
|
||||||
|
"babel-preset-react": "^6.11.1",
|
||||||
|
"babel-preset-stage-2": "^6.13.0",
|
||||||
|
"browserify": "^13.1.0",
|
||||||
|
"envify": "^3.4.1",
|
||||||
|
"uglify-js": "^2.7.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"dist-lib": "rm -rf lib/ && babel -d lib/ src/",
|
||||||
|
"dist-standalone": "mkdir -p dist && browserify -r ./lib/index.js:gitbook-core -r react -r react-dom ./lib/index.js | uglifyjs -c > ./dist/gitbook.core.min.js",
|
||||||
|
"dist": "npm run dist-lib && npm run dist-standalone",
|
||||||
|
"prepublish": "npm run dist"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/GitbookIO/gitbook.git"
|
||||||
|
},
|
||||||
|
"author": "GitBook Inc. <contact@gitbook.com>",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/GitbookIO/gitbook/issues"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Components
|
||||||
|
REGISTER_COMPONENT: 'components/register',
|
||||||
|
UNREGISTER_COMPONENT: 'components/unregister',
|
||||||
|
// Navigation
|
||||||
|
HISTORY_ACTIVATE: 'history/activate',
|
||||||
|
HISTORY_DEACTIVATE: 'history/deactivate',
|
||||||
|
HISTORY_LISTEN: 'history/listen',
|
||||||
|
HISTORY_UPDATE: 'history/update',
|
||||||
|
PAGE_FETCH_START: 'history/fetch:start',
|
||||||
|
PAGE_FETCH_END: 'history/fetch:end',
|
||||||
|
PAGE_FETCH_ERROR: 'history/fetch:error',
|
||||||
|
// i18n
|
||||||
|
I18N_REGISTER_LOCALE: 'i18n/register:locale'
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
const ACTION_TYPES = require('./TYPES');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all components matching a descriptor
|
||||||
|
* @param {List<ComponentDescriptor>} state
|
||||||
|
* @param {String} matching.role
|
||||||
|
*/
|
||||||
|
function findMatchingComponents(state, matching) {
|
||||||
|
return state
|
||||||
|
.filter(({descriptor}) => {
|
||||||
|
if (matching.role && matching.role !== descriptor.role) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.map(component => component.Component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new component
|
||||||
|
* @param {React.Class} Component
|
||||||
|
* @param {Descriptor} descriptor
|
||||||
|
* @return {Action}
|
||||||
|
*/
|
||||||
|
function registerComponent(Component, descriptor) {
|
||||||
|
return {
|
||||||
|
type: ACTION_TYPES.REGISTER_COMPONENT,
|
||||||
|
Component,
|
||||||
|
descriptor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
findMatchingComponents,
|
||||||
|
registerComponent
|
||||||
|
};
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
const ACTION_TYPES = require('./TYPES');
|
||||||
|
const getPayload = require('../lib/getPayload');
|
||||||
|
const Location = require('../models/Location');
|
||||||
|
|
||||||
|
const SUPPORTED = (
|
||||||
|
typeof window !== 'undefined' &&
|
||||||
|
window.history && window.history.pushState && window.history.replaceState &&
|
||||||
|
// pushState isn't reliable on iOS until 5.
|
||||||
|
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the history
|
||||||
|
*/
|
||||||
|
function activate() {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTION_TYPES.HISTORY_ACTIVATE,
|
||||||
|
listener: (location) => {
|
||||||
|
location = Location.fromNative(location);
|
||||||
|
const prevLocation = getState().history.location;
|
||||||
|
|
||||||
|
// Fetch page if required
|
||||||
|
if (!prevLocation || location.pathname !== prevLocation.pathname) {
|
||||||
|
dispatch(fetchPage(location.pathname));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal location to listener
|
||||||
|
dispatch(emit());
|
||||||
|
|
||||||
|
// Update the location
|
||||||
|
dispatch({
|
||||||
|
type: ACTION_TYPES.HISTORY_UPDATE,
|
||||||
|
location
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Trigger for existing listeners
|
||||||
|
dispatch(emit());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit current location
|
||||||
|
* @param {List|Array<Function>} to?
|
||||||
|
*/
|
||||||
|
function emit(to) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const { listeners, client } = getState().history;
|
||||||
|
|
||||||
|
if (!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const location = Location.fromNative(client.location);
|
||||||
|
|
||||||
|
to = to || listeners;
|
||||||
|
|
||||||
|
to.forEach(handler => {
|
||||||
|
handler(location, dispatch, getState);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup the history
|
||||||
|
*/
|
||||||
|
function deactivate() {
|
||||||
|
return { type: ACTION_TYPES.HISTORY_DEACTIVATE };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push a new url into the history
|
||||||
|
* @param {String|Location} location
|
||||||
|
* @return {Action} action
|
||||||
|
*/
|
||||||
|
function push(location) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const { client } = getState().history;
|
||||||
|
location = Location.fromNative(location);
|
||||||
|
|
||||||
|
if (SUPPORTED) {
|
||||||
|
client.push(location.toNative());
|
||||||
|
} else {
|
||||||
|
redirect(location.toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace current state in history
|
||||||
|
* @param {String|Location} location
|
||||||
|
* @return {Action} action
|
||||||
|
*/
|
||||||
|
function replace(location) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const { client } = getState().history;
|
||||||
|
location = Location.fromNative(location);
|
||||||
|
|
||||||
|
if (SUPPORTED) {
|
||||||
|
client.replace(location.toNative());
|
||||||
|
} else {
|
||||||
|
redirect(location.toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hard redirection
|
||||||
|
* @param {String} uri
|
||||||
|
* @return {Action} action
|
||||||
|
*/
|
||||||
|
function redirect(uri) {
|
||||||
|
return () => {
|
||||||
|
window.location.href = uri;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to url change
|
||||||
|
* @param {Function} listener
|
||||||
|
* @return {Action} action
|
||||||
|
*/
|
||||||
|
function listen(listener) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
dispatch({ type: ACTION_TYPES.HISTORY_LISTEN, listener });
|
||||||
|
|
||||||
|
// Trigger for existing listeners
|
||||||
|
dispatch(emit([ listener ]));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a new page and update the store accordingly
|
||||||
|
* @param {String} pathname
|
||||||
|
* @return {Action} action
|
||||||
|
*/
|
||||||
|
function fetchPage(pathname) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
dispatch({ type: ACTION_TYPES.PAGE_FETCH_START });
|
||||||
|
|
||||||
|
window.fetch(pathname, {
|
||||||
|
credentials: 'include'
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
response => {
|
||||||
|
return response.text();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
html => {
|
||||||
|
const payload = getPayload(html);
|
||||||
|
|
||||||
|
if (!payload) {
|
||||||
|
throw new Error('No payload found in page');
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({ type: ACTION_TYPES.PAGE_FETCH_END, payload });
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch(
|
||||||
|
error => {
|
||||||
|
// dispatch(redirect(pathname));
|
||||||
|
dispatch({ type: ACTION_TYPES.PAGE_FETCH_ERROR, error });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a new article
|
||||||
|
* @param {SummaryArticle} article
|
||||||
|
* @return {Action} action
|
||||||
|
*/
|
||||||
|
function fetchArticle(article) {
|
||||||
|
return fetchPage(article.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
activate,
|
||||||
|
deactivate,
|
||||||
|
listen,
|
||||||
|
push,
|
||||||
|
replace,
|
||||||
|
fetchPage,
|
||||||
|
fetchArticle
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
const ACTION_TYPES = require('./TYPES');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register messages for a locale
|
||||||
|
* @param {String} locale
|
||||||
|
* @param {Map<String:String>} messages
|
||||||
|
* @return {Action}
|
||||||
|
*/
|
||||||
|
function registerLocale(locale, messages) {
|
||||||
|
return { type: ACTION_TYPES.I18N_REGISTER_LOCALE, locale, messages };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register multiple locales
|
||||||
|
* @param {Map<String:Object>} locales
|
||||||
|
* @return {Action}
|
||||||
|
*/
|
||||||
|
function registerLocales(locales) {
|
||||||
|
return (dispatch) => {
|
||||||
|
for (const locale in locales) {
|
||||||
|
if (!locales.hasOwnProperty(locale)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(registerLocale(locale, locales[locale]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
registerLocale,
|
||||||
|
registerLocales
|
||||||
|
};
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const HotKeys = require('./HotKeys');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backdrop for modals, dropdown, etc. that covers the whole screen
|
||||||
|
* and handles click and pressing escape.
|
||||||
|
*
|
||||||
|
* <Backdrop onClose={onCloseModal} />
|
||||||
|
*/
|
||||||
|
const Backdrop = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
// Callback when backdrop is closed
|
||||||
|
onClose: React.PropTypes.func.isRequired,
|
||||||
|
// Z-index for the backdrop
|
||||||
|
zIndex: React.PropTypes.number,
|
||||||
|
children: React.PropTypes.node
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps() {
|
||||||
|
return {
|
||||||
|
zIndex: 200
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onClick(event) {
|
||||||
|
const { onClose } = this.props;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { zIndex, children, onClose } = this.props;
|
||||||
|
const style = {
|
||||||
|
zIndex,
|
||||||
|
position: 'fixed',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%'
|
||||||
|
};
|
||||||
|
const keyMap = {
|
||||||
|
'escape': onClose
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HotKeys keyMap={keyMap}>
|
||||||
|
<div style={style} onClick={this.onClick}>{children}</div>
|
||||||
|
</HotKeys>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Backdrop;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const classNames = require('classnames');
|
||||||
|
|
||||||
|
const Button = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
active: React.PropTypes.bool,
|
||||||
|
className: React.PropTypes.string,
|
||||||
|
children: React.PropTypes.node,
|
||||||
|
onClick: React.PropTypes.func
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, active, onClick } = this.props;
|
||||||
|
const className = classNames('GitBook-Button', this.props.className, {
|
||||||
|
active
|
||||||
|
});
|
||||||
|
|
||||||
|
return <button className={className} onClick={onClick}>{children}</button>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Button;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const classNames = require('classnames');
|
||||||
|
|
||||||
|
const ButtonGroup = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
className: React.PropTypes.string,
|
||||||
|
children: React.PropTypes.node,
|
||||||
|
onClick: React.PropTypes.func
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { className, children } = this.props;
|
||||||
|
|
||||||
|
className = classNames(
|
||||||
|
'GitBook-ButtonGroup',
|
||||||
|
className
|
||||||
|
);
|
||||||
|
|
||||||
|
return <div className={className}>{children}</div>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = ButtonGroup;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const { Provider } = require('react-redux');
|
||||||
|
|
||||||
|
const ContextShape = require('../propTypes/Context');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React component to provide a GitBook context to children components.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ContextProvider = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
context: ContextShape.isRequired,
|
||||||
|
children: React.PropTypes.node
|
||||||
|
},
|
||||||
|
|
||||||
|
childContextTypes: {
|
||||||
|
gitbook: ContextShape
|
||||||
|
},
|
||||||
|
|
||||||
|
getChildContext() {
|
||||||
|
const { context } = this.props;
|
||||||
|
|
||||||
|
return {
|
||||||
|
gitbook: context
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { context, children } = this.props;
|
||||||
|
return <Provider store={context.store}>{children}</Provider>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = ContextProvider;
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const classNames = require('classnames');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dropdown to display a menu
|
||||||
|
*
|
||||||
|
* <Dropdown.Container>
|
||||||
|
*
|
||||||
|
* <Button />
|
||||||
|
*
|
||||||
|
* <Dropdown.Menu>
|
||||||
|
* <Dropdown.Item href={...}> ... </Dropdown.Item>
|
||||||
|
* <Dropdown.Item onClick={...}> ... </Dropdown.Item>
|
||||||
|
* </Dropdown.Menu>
|
||||||
|
* </Dropdown.Container>
|
||||||
|
*/
|
||||||
|
|
||||||
|
const DropdownContainer = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
className: React.PropTypes.string,
|
||||||
|
children: React.PropTypes.node
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { className, children } = this.props;
|
||||||
|
|
||||||
|
className = classNames(
|
||||||
|
'GitBook-Dropdown',
|
||||||
|
className
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dropdown item which can contains informations.
|
||||||
|
*/
|
||||||
|
const DropdownItem = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
children: React.PropTypes.node
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="GitBook-DropdownItem">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dropdown item, which is always a link.
|
||||||
|
*/
|
||||||
|
const DropdownItemLink = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
children: React.PropTypes.node,
|
||||||
|
onClick: React.PropTypes.func,
|
||||||
|
href: React.PropTypes.string
|
||||||
|
},
|
||||||
|
|
||||||
|
onClick(event) {
|
||||||
|
const { onClick, href } = this.props;
|
||||||
|
|
||||||
|
if (href) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if (onClick) {
|
||||||
|
onClick();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, href, ...otherProps } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a {...otherProps} className="GitBook-DropdownItemLink" href={href || '#'} onClick={this.onClick} >
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DropdownMenu to display DropdownItems. Must be inside a
|
||||||
|
* DropdownContainer.
|
||||||
|
*/
|
||||||
|
const DropdownMenu = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
className: React.PropTypes.string,
|
||||||
|
children: React.PropTypes.node
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { className, children } = this.props;
|
||||||
|
className = classNames('GitBook-DropdownMenu', className);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Dropdown = {
|
||||||
|
Item: DropdownItem,
|
||||||
|
ItemLink: DropdownItemLink,
|
||||||
|
Menu: DropdownMenu,
|
||||||
|
Container: DropdownContainer
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Dropdown;
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const ReactSafeHtml = require('react-safe-html');
|
||||||
|
const { DOMProperty } = require('react-dom/lib/ReactInjection');
|
||||||
|
const htmlTags = require('html-tags');
|
||||||
|
const entities = require('entities');
|
||||||
|
|
||||||
|
const { InjectedComponent } = require('./InjectedComponent');
|
||||||
|
|
||||||
|
DOMProperty.injectDOMPropertyConfig({
|
||||||
|
Properties: {
|
||||||
|
align: DOMProperty.MUST_USE_ATTRIBUTE
|
||||||
|
},
|
||||||
|
isCustomAttribute: (attributeName) => {
|
||||||
|
return attributeName === 'align';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
HTMLContent is a container for the page HTML that parse the content and
|
||||||
|
render the right block.
|
||||||
|
All html elements can be extended using the injected component.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function inject(injectedProps, Component) {
|
||||||
|
return (props) => {
|
||||||
|
const cleanProps = {
|
||||||
|
...props,
|
||||||
|
className: props['class']
|
||||||
|
};
|
||||||
|
delete cleanProps['class'];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InjectedComponent {...injectedProps(cleanProps)}>
|
||||||
|
<Component {...cleanProps} />
|
||||||
|
</InjectedComponent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const COMPONENTS = {
|
||||||
|
// Templating blocks are exported as <xblock name="youtube" props="{}" />
|
||||||
|
'xblock': inject(
|
||||||
|
({name, props}) => {
|
||||||
|
props = entities.decodeHTML(props);
|
||||||
|
return {
|
||||||
|
matching: { role: `block:${name}` },
|
||||||
|
props: JSON.parse(props)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props => <div {...props} />
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
htmlTags.forEach(tag => {
|
||||||
|
COMPONENTS[tag] = inject(
|
||||||
|
props => {
|
||||||
|
return {
|
||||||
|
matching: { role: `html:${tag}` },
|
||||||
|
props
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props => React.createElement(tag, props)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const HTMLContent = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
html: React.PropTypes.string.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { html } = this.props;
|
||||||
|
return <ReactSafeHtml html={html} components={COMPONENTS} />;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = HTMLContent;
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const Mousetrap = require('mousetrap');
|
||||||
|
const { Map } = require('immutable');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines hotkeys globally when this component is mounted.
|
||||||
|
*
|
||||||
|
* keyMap = {
|
||||||
|
* 'escape': (e) => quit()
|
||||||
|
* 'mod+s': (e) => save()
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* <HotKeys keyMap={keyMap}>
|
||||||
|
* < ... />
|
||||||
|
* </HotKeys>
|
||||||
|
*/
|
||||||
|
|
||||||
|
const HotKeys = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
children: React.PropTypes.node.isRequired,
|
||||||
|
keyMap: React.PropTypes.objectOf(React.PropTypes.func)
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps() {
|
||||||
|
return { keyMap: {} };
|
||||||
|
},
|
||||||
|
|
||||||
|
updateBindings(keyMap) {
|
||||||
|
Map(keyMap).forEach((handler, key) => {
|
||||||
|
Mousetrap.bind(key, handler);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clearBindings(keyMap) {
|
||||||
|
Map(keyMap).forEach((handler, key) => {
|
||||||
|
Mousetrap.unbind(key, handler);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.updateBindings(this.props.keyMap);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
this.clearBindings(prevProps.keyMap);
|
||||||
|
this.updateBindings(this.props.keyMap);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.clearBindings(this.props.keyMap);
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// Simply render the only child
|
||||||
|
return React.Children.only(this.props.children);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = HotKeys;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
const { Map } = require('immutable');
|
||||||
|
const React = require('react');
|
||||||
|
const intl = require('react-intl');
|
||||||
|
const ReactRedux = require('react-redux');
|
||||||
|
|
||||||
|
const I18nProvider = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
children: React.PropTypes.node,
|
||||||
|
messages: React.PropTypes.object
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { messages } = this.props;
|
||||||
|
messages = messages.get('en', Map()).toJS();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<intl.IntlProvider locale={'en'} messages={messages}>
|
||||||
|
{this.props.children}
|
||||||
|
</intl.IntlProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return { messages: state.i18n.messages };
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ReactRedux.connect(mapStateToProps)(I18nProvider);
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
const React = require('react');
|
||||||
|
|
||||||
|
const Icon = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
id: React.PropTypes.string,
|
||||||
|
type: React.PropTypes.string,
|
||||||
|
className: React.PropTypes.string
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps() {
|
||||||
|
return {
|
||||||
|
type: 'fa'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { id, type } = this.props;
|
||||||
|
let { className } = this.props;
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
className = 'GitBook-Icon ' + type + ' ' + type + '-' + id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <i className={className}/>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Icon;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user