Comparar commits
839 Commits
0.5.0
...
1.0.0beta2
| Autor | SHA1 | Data | |
|---|---|---|---|
| a947064b7d | |||
| 5bc9866f43 | |||
| 61d82e210a | |||
| a876ac9386 | |||
| da1502c463 | |||
| 76bb782f64 | |||
| e6f4b043cb | |||
| d651ffaf2e | |||
| e554378b5e | |||
| b463bd797e | |||
| 699e6e16c9 | |||
| f8477c41e1 | |||
| 9a63333aec | |||
| 6e40914258 | |||
| 56a1dd931e | |||
| 57fd2e6a52 | |||
| 113db06cdd | |||
| 4ee5c59cfd | |||
| 15812678a3 | |||
| ee0379b321 | |||
| dcf279177d | |||
| 01115824f7 | |||
| b68473ae11 | |||
| a65c203c9b | |||
| 0a848240d4 | |||
| d03821b88a | |||
| 4d32762899 | |||
| 2cb4b6d16d | |||
| b770e566dd | |||
| 51ebc88f0c | |||
| a04a75724d | |||
| 6e5af3d799 | |||
| 0283a73a32 | |||
| 5f593031f0 | |||
| 0eeef2d4bd | |||
| bb6164e30b | |||
| d3beae4871 | |||
| 8df0df32f8 | |||
| b0228dd0fd | |||
| ffca2dee1d | |||
| cba985bfea | |||
| 6a10a67205 | |||
| 880fb5bd89 | |||
| 6a0ade074d | |||
| 6cf4629d0f | |||
| ce23e5fa9e | |||
| d16fb838ca | |||
| 6b9eb8aae3 | |||
| 78008d1fea | |||
| 69fb9bb39b | |||
| 92f1557235 | |||
| 8e487ba36d | |||
| 7eb088b5ed | |||
| 9ef8ea95b0 | |||
| eedf54b485 | |||
| a461815957 | |||
| 687c2f08f6 | |||
| 2294f23e5f | |||
| bdfd81322b | |||
| 3ceb0de8d8 | |||
| c4b5208867 | |||
| 9c3f6b0c10 | |||
| 0550755c7d | |||
| 47602f267a | |||
| 656e67ef90 | |||
| c53883b635 | |||
| c4278c81f1 | |||
| c94dcf5940 | |||
| 08ca3eff12 | |||
| b40a241b2e | |||
| f86f1e83ad | |||
| be85701abe | |||
| 190eb474a6 | |||
| 8db1138081 | |||
| afbfd4d3fa | |||
| 9b8efbfdd5 | |||
| cacada87f3 | |||
| 8a36c54318 | |||
| 879d411669 | |||
| b38be2ce7b | |||
| 1810c9b61c | |||
| 98737f14f1 | |||
| b311118a04 | |||
| 8a337f1faf | |||
| dbc5bd4104 | |||
| a9c3f566da | |||
| 6d9c9cd964 | |||
| 25c8883e49 | |||
| 793943fc2f | |||
| e98f86c540 | |||
| 1c8ff48f92 | |||
| 1fb73e2211 | |||
| 5279ade0e7 | |||
| 984134fb9d | |||
| eb8f1f24b7 | |||
| e49dc8bcfa | |||
| e742da24a7 | |||
| 203b65475c | |||
| 576c5f4c9e | |||
| d2434b5591 | |||
| 634c008fcd | |||
| 83f1ccb8ad | |||
| cea401c513 | |||
| 6b54c1b6d4 | |||
| 193c4a953e | |||
| d389134036 | |||
| d8b140e341 | |||
| 5931e1143b | |||
| e6d0c4b79f | |||
| 44a4a18320 | |||
| 2f96506a6e | |||
| f904606b32 | |||
| 99bb14680a | |||
| 83df3dda95 | |||
| 5e4d67209c | |||
| 2798af1668 | |||
| f0e41ce4c7 | |||
| 300602dd32 | |||
| 136f6778e2 | |||
| 2fa7907054 | |||
| f3803c4c22 | |||
| 5d37927b0a | |||
| 6227f5cfa2 | |||
| 9fbb9fa5e1 | |||
| de81ee7ee6 | |||
| 5fcf971e28 | |||
| 492f70fc4b | |||
| 3ced7b7212 | |||
| 7b55867ea7 | |||
| 3e15ef1c86 | |||
| 0cdc836054 | |||
| 1aad62b95d | |||
| ed1c88920e | |||
| e6ca20c4a2 | |||
| cfa3470df6 | |||
| 479f297cf6 | |||
| 7e1b222f90 | |||
| 69baa6ea1a | |||
| 0fce93be37 | |||
| 51611ec2bb | |||
| 228a78136d | |||
| 34d10ace7a | |||
| 57bd0a5628 | |||
| 42e4860855 | |||
| ea1c9f70d7 | |||
| d3085b0450 | |||
| 63d02f1d5f | |||
| dfecbe5bfa | |||
| bcf9f00de5 | |||
| a8e8e35678 | |||
| 2ec4a8b4ce | |||
| 6c3d3dee81 | |||
| 40b3116ed7 | |||
| df7582b138 | |||
| b08dab9aa1 | |||
| da5a4804df | |||
| d12f43498e | |||
| f9f2facd76 | |||
| eaee3954c1 | |||
| eb235e11b6 | |||
| 0c5fe61ed3 | |||
| 76052b443a | |||
| 5a48248e1e | |||
| bedff3278f | |||
| 0bb48153a5 | |||
| b75246e3ca | |||
| 2d31f0d7fe | |||
| 87cfca721e | |||
| 54d36f3337 | |||
| a4a17d171a | |||
| 7c2673fc66 | |||
| c77ecbb10f | |||
| f0ba57ba23 | |||
| 893aa80361 | |||
| 59ac3d1d45 | |||
| 247a9478c8 | |||
| 1c64d858c2 | |||
| 91a1d7faaf | |||
| 214bbfa7b6 | |||
| 3ee4492b3c | |||
| 38c453b3c6 | |||
| 3d41c61991 | |||
| 1f9f47f97e | |||
| 41cc2923b1 | |||
| 4c180f3eed | |||
| 5f9a64dbea | |||
| 9d37bfdcf1 | |||
| d738c3aca6 | |||
| 836c4313ab | |||
| 91c6478add | |||
| fce527a55b | |||
| 9a1f62fc1f | |||
| 018d8656d3 | |||
| 2636e1ba45 | |||
| caed07dfc1 | |||
| 373cf3328d | |||
| 0370c3fa01 | |||
| f5143a7d63 | |||
| 346b2a27cb | |||
| 38281e6361 | |||
| 6e8413f568 | |||
| cb04364381 | |||
| 83d2555123 | |||
| 0ace97c8d4 | |||
| 9e3a0c61b8 | |||
| 2fda5c7873 | |||
| e29868c8ce | |||
| ac560be870 | |||
| 5a29cbf4a7 | |||
| dc77894f68 | |||
| 74432a6b9d | |||
| 2b2fa7e77c | |||
| c3f71b33aa | |||
| 927aae72d1 | |||
| 2a674f4e8d | |||
| 0b86ce2bda | |||
| 548a0709f4 | |||
| da84c0bb4d | |||
| 9e68a5b9ab | |||
| 6982bdaa28 | |||
| c1809232fe | |||
| 3c06c82eb7 | |||
| 1bcccb3134 | |||
| cdf49dc87e | |||
| 0a0fb8f803 | |||
| 60cfd56369 | |||
| 73050d38c5 | |||
| c50e941972 | |||
| 7c59fd21e2 | |||
| b095a4221c | |||
| 1ef39fa3b8 | |||
| fcf4530d83 | |||
| 0515e14d27 | |||
| ddbef0bd79 | |||
| bc5d31f86a | |||
| 09147a2aab | |||
| a75a119e2f | |||
| c1b3546161 | |||
| 8338432c7b | |||
| 8beae065cf | |||
| 0e7d39aa13 | |||
| 74063ad735 | |||
| 55a29808c9 | |||
| 40f3de3939 | |||
| 5d94ab09e3 | |||
| b34ff6853d | |||
| e2570be957 | |||
| 95e6fff3da | |||
| 9de12b7385 | |||
| beffe906e4 | |||
| e850d1073d | |||
| c02a2ba5ba | |||
| f92bb6690b | |||
| 5842a3bba6 | |||
| fcf691d97c | |||
| a32c7d5f07 | |||
| edfb18b75a | |||
| 5544c5d5d4 | |||
| 22100f7c3a | |||
| 8ece01ccda | |||
| 9b68039a62 | |||
| a914326e75 | |||
| 2b7dd35e05 | |||
| 15e41169ad | |||
| f8c5219c12 | |||
| c570b67dda | |||
| 456fac1700 | |||
| 41e58c394b | |||
| 5aeda5f67b | |||
| c96adf168c | |||
| 40c5bc01ff | |||
| 09dabef70c | |||
| 96edee806e | |||
| e58f4683d1 | |||
| 9750817bf0 | |||
| 7099d730e6 | |||
| 13c290e99f | |||
| cf37966e39 | |||
| 9449c4b9b5 | |||
| 046172e5d9 | |||
| c74446e38c | |||
| 7897460993 | |||
| 4b59583bca | |||
| 41f73559f2 | |||
| d3090c0965 | |||
| dc5caebbf8 | |||
| 14280dfedb | |||
| 8fdf11135a | |||
| c8baa8f349 | |||
| a6e25b46af | |||
| 395d14ab58 | |||
| 0d4b57df7a | |||
| 416e7617b3 | |||
| 838c470017 | |||
| f0a09665db | |||
| 1397fa64d5 | |||
| ac17a6afcf | |||
| 35af1bab30 | |||
| 1fe7bb271a | |||
| 774e25d944 | |||
| 6770e8541d | |||
| 70e94e4dde | |||
| 0ffbc6e345 | |||
| 25e796753f | |||
| 70d9ef4f77 | |||
| fd67c9a589 | |||
| f0917ff774 | |||
| 843281dec0 | |||
| 3a21588429 | |||
| 21eeb09a3c | |||
| 900c5ed358 | |||
| 195c8a92d1 | |||
| 7c651e6093 | |||
| 860b899f0c | |||
| 87b7524de9 | |||
| 29641ae16a | |||
| 02e32a7a9d | |||
| 3056369c6e | |||
| 3da75726d3 | |||
| b7346de47d | |||
| 7a69100b2f | |||
| 2732d2b9d3 | |||
| 87bb27cc4f | |||
| bafa300b0f | |||
| 939cf4542f | |||
| 874975da54 | |||
| f0bebd4c33 | |||
| c444a11862 | |||
| 4c0704e338 | |||
| 77f4cd5d58 | |||
| 9858d3c5a8 | |||
| 414acbc9ec | |||
| 21f904db42 | |||
| f6ca253849 | |||
| 3f989191e3 | |||
| 2bea014e89 | |||
| 84fc19a75f | |||
| d803924ef0 | |||
| 889f8d9d30 | |||
| 1dcb7eaf1f | |||
| 5f9e4ace2f | |||
| 6386330973 | |||
| fd89b9755e | |||
| 730f454278 | |||
| e2fca29c91 | |||
| f97a222cf5 | |||
| c75105e977 | |||
| 7096471d65 | |||
| cc1cee8a38 | |||
| 5f2680889f | |||
| b3ae8bb606 | |||
| 72d9f37845 | |||
| fdfccafd84 | |||
| a784f946ba | |||
| a04af6c4bd | |||
| 64b24a96c8 | |||
| a62a5d0d7b | |||
| 3043d1e839 | |||
| a3aefb6902 | |||
| a42aaa270c | |||
| f8b471c17b | |||
| 87adff44db | |||
| 767bba9c04 | |||
| 0c827521d0 | |||
| 80cec7d12f | |||
| 5f916357e9 | |||
| ea82eea9bb | |||
| 22222d7db4 | |||
| cebee369d1 | |||
| faf809851c | |||
| d05aafd76b | |||
| 8d52721873 | |||
| 66c6152cd2 | |||
| 32cd51d3a5 | |||
| 497a28401e | |||
| e46912047c | |||
| 56b573ede5 | |||
| 0276be1789 | |||
| 7db4c60fc3 | |||
| 95cc01dd91 | |||
| cce1dddf42 | |||
| 0938b57841 | |||
| aef8550e2f | |||
| 71bf0bde32 | |||
| 750623b9b1 | |||
| 1f12c53b65 | |||
| 8717ea1b95 | |||
| db2eb658ca | |||
| 70483484ce | |||
| d21afc43a1 | |||
| 7ad0803f2e | |||
| ec4bfd55f9 | |||
| f65174a0db | |||
| 8b1fcd4dd7 | |||
| 9509237958 | |||
| f20fd20a06 | |||
| 8e48120fb7 | |||
| 44cc5ac883 | |||
| 9a43cc8c4b | |||
| 8dfc0d54f4 | |||
| 77febd21de | |||
| 84a997c66b | |||
| b900a59fc2 | |||
| ca782dbc58 | |||
| 746cda27ec | |||
| 16d1651656 | |||
| 4735fb2377 | |||
| ec6b518fd2 | |||
| 580ad1b192 | |||
| 23d8810486 | |||
| d579d62eb6 | |||
| 529f785e3c | |||
| 0581ae87b4 | |||
| cda1059336 | |||
| 1aed6b5c30 | |||
| 4e68705b24 | |||
| 216cb1ea12 | |||
| 8ef6a0b432 | |||
| 5dc152c46e | |||
| c3a21437e4 | |||
| 32bc8dcbf9 | |||
| 677ca7b4aa | |||
| dfc2331104 | |||
| cd06bbfb8d | |||
| 1d596bcbac | |||
| 0cb7b9c13d | |||
| a180efeca7 | |||
| eef24ea29c | |||
| 458bb3d7f7 | |||
| ffb23d92c0 | |||
| 0ce39a4cf6 | |||
| a24c70e490 | |||
| 8d4ef6e883 | |||
| 54865ebdee | |||
| cb8e704d5c | |||
| 57f4978442 | |||
| b8833f4c9e | |||
| 5c40cbc675 | |||
| a455dcc919 | |||
| 289487cc46 | |||
| 42b28d5bd6 | |||
| 46bee05d93 | |||
| 49bed5cd5f | |||
| 624cf93e2e | |||
| 6ab76cda51 | |||
| 15beb81368 | |||
| 6a6cce03b7 | |||
| 970ff87ef6 | |||
| 8b6c4d322f | |||
| 4467a00acd | |||
| 63efc61517 | |||
| 7aa18345c8 | |||
| 34149187a8 | |||
| 2d132cd0d5 | |||
| 8d741361e0 | |||
| 2bcea3a370 | |||
| ead3cace02 | |||
| 7afa5c7b43 | |||
| 115765e1ee | |||
| d712fae2d7 | |||
| 0dba9bd87f | |||
| 2fbc495088 | |||
| 37d490cbe4 | |||
| 451679c582 | |||
| 7270a13ef7 | |||
| 16f3f90ed7 | |||
| 9ff2f81a10 | |||
| 1bc9a1af6a | |||
| 760d9e3341 | |||
| 5b28abc5ed | |||
| defb1596bb | |||
| 9c117d5875 | |||
| 1b09fce42a | |||
| 5e328830e7 | |||
| 606da1c45b | |||
| 6232c1a8f3 | |||
| 15a24e68d2 | |||
| c12ace81db | |||
| 531990b516 | |||
| b90a3dbffe | |||
| 0352b97798 | |||
| e45abe60bf | |||
| 8077481707 | |||
| 4651dd33cd | |||
| c93cfa0871 | |||
| d57cb7d411 | |||
| 81088766ee | |||
| ae59a50c28 | |||
| 4a05056393 | |||
| 71e97c815a | |||
| 8b7787aa60 | |||
| e0f94b052b | |||
| eb2c9ffd32 | |||
| 5af315c165 | |||
| e9fdfc339b | |||
| 132730acea | |||
| 405097d323 | |||
| c9d79f26c5 | |||
| 7ef13eaf0c | |||
| 2756aba21f | |||
| c01a7f57df | |||
| 33a4dd3841 | |||
| 3c150db4a2 | |||
| e31f5d2325 | |||
| f8a61c667e | |||
| e2fe60399f | |||
| 59c4e35691 | |||
| 2dc5afd018 | |||
| b5df39bc46 | |||
| f87b709923 | |||
| 671aa1036b | |||
| 4580340db3 | |||
| 31b53eae39 | |||
| 089423958d | |||
| 0d02ea43e1 | |||
| 93239ae3fb | |||
| 5d21e9364d | |||
| b9306c4cca | |||
| c07bd31f61 | |||
| fee4830669 | |||
| 9016b6778e | |||
| e05501a1ae | |||
| 23d09fcc9e | |||
| 5d11fccbf2 | |||
| 3851957dd0 | |||
| 135afb0883 | |||
| 27b27af7cd | |||
| 20fe31b803 | |||
| ebca9aab8d | |||
| 49821e0416 | |||
| b5d6f1ada5 | |||
| b40325cd7b | |||
| 3b27ec66e1 | |||
| 52b8b36d54 | |||
| 7e3106dd1b | |||
| 399e0d94fc | |||
| eef1ff9e87 | |||
| 9202c7504b | |||
| 3fd7e3b93e | |||
| b6996df86a | |||
| 4b3efd7bfa | |||
| 12c2682c34 | |||
| 2caf67b813 | |||
| fbbe13661a | |||
| 0fb102edae | |||
| b4dd90d074 | |||
| 2e3f806d07 | |||
| f76092e83e | |||
| 1e44081583 | |||
| 26b3a4259d | |||
| 8a074a7e6d | |||
| e99434582f | |||
| fec57df994 | |||
| 033cb2d20a | |||
| a5fa58e3e6 | |||
| fdc9d2714b | |||
| 824ca9b513 | |||
| a74a740964 | |||
| 2041d52495 | |||
| fb5d528eff | |||
| a2cedbd9da | |||
| 8574eddfa0 | |||
| 2ccf876929 | |||
| 28df150784 | |||
| 0950083da2 | |||
| 88c5f910da | |||
| a9d3e4798e | |||
| d85d834b23 | |||
| 5729da5a9f | |||
| 1255331160 | |||
| 0fef51b5f6 | |||
| 7cf18c0468 | |||
| b994509b9d | |||
| 6571e19e8f | |||
| 7441164db9 | |||
| 09bb10cd3f | |||
| bd6f24f4b1 | |||
| 0a174ad219 | |||
| 33d004fb9a | |||
| 652bf34c77 | |||
| 3f11bad68e | |||
| 5245fbfc6d | |||
| 68f8ee8a99 | |||
| 7b83a52dce | |||
| 5f57c82478 | |||
| 3128cbef73 | |||
| 694b2bf055 | |||
| e03a023c5f | |||
| 3ff5d3bd09 | |||
| 04841196e3 | |||
| 18dd495d99 | |||
| f714945bbb | |||
| a318ef2232 | |||
| 8ed24de9d3 | |||
| e06e50936d | |||
| d710e9cb47 | |||
| 9af3699850 | |||
| 3cc7b4d8c2 | |||
| 8b58732a1f | |||
| a2a0935343 | |||
| 2668156e53 | |||
| d67615d239 | |||
| afd70b64ed | |||
| 78a6e43667 | |||
| a65af97e43 | |||
| 637dfabe69 | |||
| ff8b3c10f3 | |||
| f442555d8f | |||
| bdf9f882ad | |||
| 1e5c5bfe00 | |||
| 0e78fdfcb4 | |||
| 4f532f86dc | |||
| 92844825cb | |||
| 6b13fc99b0 | |||
| 0f7aa26757 | |||
| a06f963263 | |||
| d31de1e654 | |||
| 46a0301022 | |||
| 73d26036ef | |||
| b9637c9d7d | |||
| 08497683bf | |||
| 44a50f6e58 | |||
| 4c2b4e5c66 | |||
| b0884ad7c3 | |||
| cf09f86df2 | |||
| d33c38f671 | |||
| fbfba21854 | |||
| b2093d6f10 | |||
| 736a0190c1 | |||
| a74c259c38 | |||
| d3dedd6312 | |||
| 920eab0ef9 | |||
| d576085e8d | |||
| 62b9a9e287 | |||
| 56ffe1d62a | |||
| 14acbcb5f1 | |||
| 9a0011bf49 | |||
| 7b9f18b097 | |||
| f8e4333157 | |||
| b5c933aa94 | |||
| c441af3f2c | |||
| e885421a67 | |||
| ce4fe24a93 | |||
| 1c0e2ceba5 | |||
| a435e8ec47 | |||
| b958393135 | |||
| a6dd697a68 | |||
| a4833e7b35 | |||
| 54fa643c10 | |||
| 6047cd4542 | |||
| 8c5f7df280 | |||
| ff1250c33c | |||
| 4297c10fe9 | |||
| ab6ad94ec3 | |||
| 759183461f | |||
| f850fa6bc9 | |||
| 5a242d35b7 | |||
| abf5d66e01 | |||
| e92360e0d4 | |||
| b5c0fdc013 | |||
| 906ef02c5e | |||
| 7550decbc0 | |||
| acd88c3c8a | |||
| a3854a2de1 | |||
| 880aca5d83 | |||
| 2d1c98a5a7 | |||
| fefa06ba21 | |||
| 18faa91c94 | |||
| 9f23c7b31a | |||
| eee6926bab | |||
| 6806f952d6 | |||
| faaef54b42 | |||
| c29852fae7 | |||
| 7d100dae97 | |||
| 206e800963 | |||
| 555a334315 | |||
| d2c5def108 | |||
| 98323c530e | |||
| b36510dbb9 | |||
| 50e533c32b | |||
| 33277c3d37 | |||
| 28f2ad0109 | |||
| 5d10ee4e61 | |||
| b4190ada0c | |||
| 60d314552d | |||
| c971d54543 | |||
| 346f019fa8 | |||
| d61c2480b6 | |||
| e30b5b86da | |||
| bd74fe24fd | |||
| b30eaa8ee3 | |||
| 75c530516a | |||
| 3b49821e82 | |||
| febf443960 | |||
| f5da81e782 | |||
| 9cb23ac584 | |||
| 6ff3100c1f | |||
| e3ea3723bf | |||
| 33443d9b41 | |||
| e0ef61659f | |||
| 655ad77bce | |||
| c09e546240 | |||
| a08b14a89e | |||
| 12e90b0eef | |||
| 7606f1bcbd | |||
| cabb43b187 | |||
| b85cda3f6e | |||
| b92f1b7497 | |||
| 273a51a335 | |||
| 212dc88b89 | |||
| ce82a91d14 | |||
| 52a08401c7 | |||
| 706c0cb033 | |||
| 1567a613a6 | |||
| d767d80d20 | |||
| 1103a9d510 | |||
| c34af4b97a | |||
| 8dcee4d338 | |||
| fc1e69ea73 | |||
| db460117c1 | |||
| 1c514df0fd | |||
| 780ec5cbec | |||
| 3721873b62 | |||
| 3bdc77ca91 | |||
| b8f54d64a4 | |||
| 90d48b320a | |||
| a797342800 | |||
| 31e608e0ae | |||
| ebcfb0e577 | |||
| 161c9f9142 | |||
| 2a099da726 | |||
| 5118397004 | |||
| 546c340656 | |||
| 3034cc7c52 | |||
| d89381ff78 | |||
| 86cac58100 | |||
| 8fc062007e | |||
| 9fd92e3306 | |||
| a4cbbe5dd4 | |||
| da7ea9655f | |||
| 00a8c642dd | |||
| e1152f6e56 | |||
| 7cf9c6842a | |||
| d375535cd9 | |||
| c5ea868f47 | |||
| 884d333805 | |||
| 3b9921a15b | |||
| 17b753d95e | |||
| 6a8781b5e2 | |||
| 0dfaf01749 | |||
| 088aa83e22 | |||
| 934adb1e9f | |||
| 50e0593de6 | |||
| f2637c6421 | |||
| a52dacea68 | |||
| f56a33d22d | |||
| 2aa858b0fb | |||
| c3b8ba4b9a | |||
| ac96b8c0e1 | |||
| a329a9f4d8 | |||
| 63cc7eb44d | |||
| 6505f32221 | |||
| 22088260f4 | |||
| d893009a8d | |||
| b62e1741be | |||
| 903c2aa642 | |||
| d0a8bb550e | |||
| f96f1423e1 | |||
| 7bf17f2f61 | |||
| 670b6cfc15 | |||
| b6d2c8479c | |||
| 5aaa114271 | |||
| e99c2791bb | |||
| 656d7754cd | |||
| 4aaf10fbfc | |||
| 85e77b77aa | |||
| f23ef09247 | |||
| 440d956438 | |||
| acd2852cf3 | |||
| 4246f43bdf | |||
| 7d33769cd2 | |||
| 31fdba80d4 | |||
| 77f8e460d0 | |||
| 51e51db9f7 | |||
| 73c506f19c | |||
| 79143f3334 | |||
| 128ba9040e | |||
| 300cfe74ad | |||
| f008af05bd | |||
| 3aa870d6bd | |||
| 25e1a8c001 | |||
| 0ba3b114b0 | |||
| c429e88e8e | |||
| c7a2fe8440 | |||
| de237e760b | |||
| 927f5c9883 | |||
| 88f461baf2 | |||
| 3251ae26a0 | |||
| e84c81633e | |||
| a2ec966ac7 | |||
| 69660fbfda | |||
| dcedca1a80 | |||
| 6455e954fc | |||
| 646904688f | |||
| 62779fc972 | |||
| fdee4cde26 | |||
| 0c18ac5adc | |||
| 6da4a942ca | |||
| 565f68d2d7 | |||
| a7cee4c889 | |||
| 4f315f9b11 | |||
| 51febfec2d | |||
| df8bd96b2e | |||
| 9da9beb342 | |||
| f93af823df | |||
| 5e74723a92 | |||
| ec77e1acea | |||
| 1afad64972 | |||
| a3365dda07 | |||
| 4c246a4cd1 | |||
| 934ffd0731 | |||
| 790e2c233d | |||
| 9e9967381c | |||
| 891ed08827 | |||
| 55d13a6f08 | |||
| 5569ea4397 | |||
| 693e37459a | |||
| 90de1fa55d | |||
| 6d6e1557ce | |||
| 2d84f16dc0 | |||
| 2f98ef9f6d | |||
| e0c07d2385 | |||
| 0b2413d8c0 | |||
| e92b01f813 | |||
| 27ff13459f | |||
| 3e80915454 | |||
| 4063d2e2c4 | |||
| ce9416857b | |||
| 575d5e8e57 |
@@ -1 +1,9 @@
|
||||
.DS_Store
|
||||
lib-cov
|
||||
*.seed
|
||||
*.log
|
||||
*.csv
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
benchmarks/graphs
|
||||
+18
-12
@@ -1,12 +1,18 @@
|
||||
[submodule "lib/support/haml"]
|
||||
path = lib/support/haml
|
||||
url = git://github.com/creationix/haml-js.git
|
||||
[submodule "lib/support/js-oo"]
|
||||
path = lib/support/js-oo
|
||||
url = git://github.com/visionmedia/js-oo.git
|
||||
[submodule "lib/support/sass"]
|
||||
path = lib/support/sass
|
||||
url = git://github.com/visionmedia/sass.js.git
|
||||
[submodule "lib/support/ext"]
|
||||
path = lib/support/ext
|
||||
url = git://github.com/visionmedia/ext.js.git
|
||||
[submodule "support/expresso"]
|
||||
path = support/expresso
|
||||
url = git://github.com/visionmedia/expresso.git
|
||||
[submodule "support/jade"]
|
||||
path = support/jade
|
||||
url = git://github.com/visionmedia/jade.git
|
||||
[submodule "support/haml"]
|
||||
path = support/haml
|
||||
url = git://github.com/visionmedia/haml.js.git
|
||||
[submodule "support/ejs"]
|
||||
path = support/ejs
|
||||
url = git://github.com/visionmedia/ejs.git
|
||||
[submodule "support/connect-form"]
|
||||
path = support/connect-form
|
||||
url = git://github.com/visionmedia/connect-form.git
|
||||
[submodule "support/connect"]
|
||||
path = support/connect
|
||||
url = git://github.com/senchalabs/connect.git
|
||||
|
||||
+213
@@ -1,3 +1,216 @@
|
||||
|
||||
1.0.0beta2 / 2010-07-23
|
||||
==================
|
||||
|
||||
* Added more examples
|
||||
* Added; exporting `Server` constructor
|
||||
* Added `Server#helpers()` for view locals
|
||||
* Added `Server#dynamicHelpers()` for dynamic view locals. Closes #349
|
||||
* Added support for absolute view paths
|
||||
* Added; _home_ setting defaults to `Server#route` for mounted apps. Closes #363
|
||||
* Added mkdir to _install.sh_ to ensure _~/.node_libraries_. Closes #362 [thanks jf]
|
||||
* Added Guillermo Rauch to the contributor list
|
||||
* Added support for "as" for non-collection partials. Closes #341
|
||||
* Fixed `res.render()` exceptions, now passed to `next()` when no callback is given [thanks guillermo]
|
||||
* Fixed instanceof `Array` checks, now `Array.isArray()`
|
||||
* Fixed express(1) expansion of public dirs. Closes #348
|
||||
* Fixed middleware precedence. Closes #345
|
||||
* Fixed view watcher, now async [thanks aheckmann]
|
||||
|
||||
1.0.0beta / 2010-07-15
|
||||
==================
|
||||
|
||||
* Re-write
|
||||
- much faster
|
||||
- much lighter
|
||||
- Check [ExpressJS.com](http://expressjs.com) for migration guide and updated docs
|
||||
|
||||
0.14.0 / 2010-06-15
|
||||
==================
|
||||
|
||||
* Utilize relative requires
|
||||
* Added Static bufferSize option [aheckmann]
|
||||
* Fixed caching of view and partial subdirectories [aheckmann]
|
||||
* Fixed mime.type() comments now that ".ext" is not supported
|
||||
* Updated haml submodule
|
||||
* Updated class submodule
|
||||
* Removed bin/express
|
||||
|
||||
0.13.0 / 2010-06-01
|
||||
==================
|
||||
|
||||
* Added node v0.1.97 compatibility
|
||||
* Added support for deleting cookies via Request#cookie('key', null)
|
||||
* Updated haml submodule
|
||||
* Fixed not-found page, now using using charset utf-8
|
||||
* Fixed show-exceptions page, now using using charset utf-8
|
||||
* Fixed view support due to fs.readFile Buffers
|
||||
* Changed; mime.type() no longer accepts ".type" due to node extname() changes
|
||||
|
||||
0.12.0 / 2010-05-22
|
||||
==================
|
||||
|
||||
* Added node v0.1.96 compatibility
|
||||
* Added view `helpers` export which act as additional local variables
|
||||
* Updated haml submodule
|
||||
* Changed ETag; removed inode, modified time only
|
||||
* Fixed LF to CRLF for setting multiple cookies
|
||||
* Fixed cookie complation; values are now urlencoded
|
||||
* Fixed cookies parsing; accepts quoted values and url escaped cookies
|
||||
|
||||
0.11.0 / 2010-05-06
|
||||
==================
|
||||
|
||||
* Added support for layouts using different engines
|
||||
- this.render('page.html.haml', { layout: 'super-cool-layout.html.ejs' })
|
||||
- this.render('page.html.haml', { layout: 'foo' }) // assumes 'foo.html.haml'
|
||||
- this.render('page.html.haml', { layout: false }) // no layout
|
||||
* Updated ext submodule
|
||||
* Updated haml submodule
|
||||
* Fixed EJS partial support by passing along the context. Issue #307
|
||||
|
||||
0.10.1 / 2010-05-03
|
||||
==================
|
||||
|
||||
* Fixed binary uploads.
|
||||
|
||||
0.10.0 / 2010-04-30
|
||||
==================
|
||||
|
||||
* Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s
|
||||
encoding is set to 'utf8' or 'utf-8'.
|
||||
* Added "encoding" option to Request#render(). Closes #299
|
||||
* Added "dump exceptions" setting, which is enabled by default.
|
||||
* Added simple ejs template engine support
|
||||
* Added error reponse support for text/plain, application/json. Closes #297
|
||||
* Added callback function param to Request#error()
|
||||
* Added Request#sendHead()
|
||||
* Added Request#stream()
|
||||
* Added support for Request#respond(304, null) for empty response bodies
|
||||
* Added ETag support to Request#sendfile()
|
||||
* Added options to Request#sendfile(), passed to fs.createReadStream()
|
||||
* Added filename arg to Request#download()
|
||||
* Performance enhanced due to pre-reversing plugins so that plugins.reverse() is not called on each request
|
||||
* Performance enhanced by preventing several calls to toLowerCase() in Router#match()
|
||||
* Changed; Request#sendfile() now streams
|
||||
* Changed; Renamed Request#halt() to Request#respond(). Closes #289
|
||||
* Changed; Using sys.inspect() instead of JSON.encode() for error output
|
||||
* Changed; run() returns the http.Server instance. Closes #298
|
||||
* Changed; Defaulting Server#host to null (INADDR_ANY)
|
||||
* Changed; Logger "common" format scale of 0.4f
|
||||
* Removed Logger "request" format
|
||||
* Fixed; Catching ENOENT in view caching, preventing error when "views/partials" is not found
|
||||
* Fixed several issues with http client
|
||||
* Fixed Logger Content-Length output
|
||||
* Fixed bug preventing Opera from retaining the generated session id. Closes #292
|
||||
|
||||
0.9.0 / 2010-04-14
|
||||
==================
|
||||
|
||||
* Added DSL level error() route support
|
||||
* Added DSL level notFound() route support
|
||||
* Added Request#error()
|
||||
* Added Request#notFound()
|
||||
* Added Request#render() callback function. Closes #258
|
||||
* Added "max upload size" setting
|
||||
* Added "magic" variables to collection partials (\_\_index\_\_, \_\_length\_\_, \_\_isFirst\_\_, \_\_isLast\_\_). Closes #254
|
||||
* Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js
|
||||
* Added callback function support to Request#halt() as 3rd/4th arg
|
||||
* Added preprocessing of route param wildcards using param(). Closes #251
|
||||
* Added view partial support (with collections etc)
|
||||
* Fixed bug preventing falsey params (such as ?page=0). Closes #286
|
||||
* Fixed setting of multiple cookies. Closes #199
|
||||
* Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml)
|
||||
* Changed; session cookie is now httpOnly
|
||||
* Changed; Request is no longer global
|
||||
* Changed; Event is no longer global
|
||||
* Changed; "sys" module is no longer global
|
||||
* Changed; moved Request#download to Static plugin where it belongs
|
||||
* Changed; Request instance created before body parsing. Closes #262
|
||||
* Changed; Pre-caching views in memory when "cache view contents" is enabled. Closes #253
|
||||
* Changed; Pre-caching view partials in memory when "cache view partials" is enabled
|
||||
* Updated support to node --version 0.1.90
|
||||
* Updated dependencies
|
||||
* Removed set("session cookie") in favour of use(Session, { cookie: { ... }})
|
||||
* Removed utils.mixin(); use Object#mergeDeep()
|
||||
|
||||
0.8.0 / 2010-03-19
|
||||
==================
|
||||
|
||||
* Added coffeescript example app. Closes #242
|
||||
* Changed; cache api now async friendly. Closes #240
|
||||
* Removed deprecated 'express/static' support. Use 'express/plugins/static'
|
||||
|
||||
0.7.6 / 2010-03-19
|
||||
==================
|
||||
|
||||
* Added Request#isXHR. Closes #229
|
||||
* Added `make install` (for the executable)
|
||||
* Added `express` executable for setting up simple app templates
|
||||
* Added "GET /public/*" to Static plugin, defaulting to <root>/public
|
||||
* Added Static plugin
|
||||
* Fixed; Request#render() only calls cache.get() once
|
||||
* Fixed; Namespacing View caches with "view:"
|
||||
* Fixed; Namespacing Static caches with "static:"
|
||||
* Fixed; Both example apps now use the Static plugin
|
||||
* Fixed set("views"). Closes #239
|
||||
* Fixed missing space for combined log format
|
||||
* Deprecated Request#sendfile() and 'express/static'
|
||||
* Removed Server#running
|
||||
|
||||
0.7.5 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Added Request#flash() support without args, now returns all flashes
|
||||
* Updated ext submodule
|
||||
|
||||
0.7.4 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Fixed session reaper
|
||||
* Changed; class.js replacing js-oo Class implementation (quite a bit faster, no browser cruft)
|
||||
|
||||
0.7.3 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Added package.json
|
||||
* Fixed requiring of haml / sass due to kiwi removal
|
||||
|
||||
0.7.2 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Fixed GIT submodules (HAH!)
|
||||
|
||||
0.7.1 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Changed; Express now using submodules again until a PM is adopted
|
||||
* Changed; chat example using millisecond conversions from ext
|
||||
|
||||
0.7.0 / 2010-03-15
|
||||
==================
|
||||
|
||||
* Added Request#pass() support (finds the next matching route, or the given path)
|
||||
* Added Logger plugin (default "common" format replaces CommonLogger)
|
||||
* Removed Profiler plugin
|
||||
* Removed CommonLogger plugin
|
||||
|
||||
0.6.0 / 2010-03-11
|
||||
==================
|
||||
|
||||
* Added seed.yml for kiwi package management support
|
||||
* Added HTTP client query string support when method is GET. Closes #205
|
||||
|
||||
* Added support for arbitrary view engines.
|
||||
For example "foo.engine.html" will now require('engine'),
|
||||
the exports from this module are cached after the first require().
|
||||
|
||||
* Added async plugin support
|
||||
|
||||
* Removed usage of RESTful route funcs as http client
|
||||
get() etc, use http.get() and friends
|
||||
|
||||
* Removed custom exceptions
|
||||
|
||||
0.5.0 / 2010-03-10
|
||||
==================
|
||||
|
||||
+68
-15
@@ -1,20 +1,73 @@
|
||||
|
||||
NODE = node
|
||||
PREFIX = /usr/local
|
||||
LIB_PREFIX = ~/.node_libraries
|
||||
|
||||
all: test
|
||||
DOCS = docs/index.md \
|
||||
docs/executable.md \
|
||||
docs/contrib.md \
|
||||
docs/guide.md \
|
||||
docs/migrate.md
|
||||
|
||||
init:
|
||||
@git submodule init && git submodule update
|
||||
MANPAGES =$(DOCS:.md=.1)
|
||||
HTMLDOCS =$(DOCS:.md=.html)
|
||||
|
||||
install: install-docs
|
||||
@mkdir -p $(PREFIX)/bin
|
||||
cp -f bin/express $(PREFIX)/bin/express
|
||||
cp -fr lib/express $(LIB_PREFIX)/express
|
||||
|
||||
uninstall: uninstall-docs
|
||||
rm -f $(PREFIX)/bin/express
|
||||
rm -fr $(LIB_PREFIX)/express
|
||||
|
||||
install-support:
|
||||
cd support/connect && $(MAKE) install
|
||||
cd support/jade && $(MAKE) install
|
||||
|
||||
uninstall-support:
|
||||
cd support/connect && $(MAKE) uninstall
|
||||
cd support/jade && $(MAKE) uninstall
|
||||
|
||||
install-docs:
|
||||
cp -f docs/executable.1 $(PREFIX)/share/man/man1/express.1
|
||||
|
||||
uninstall-docs:
|
||||
rm -f $(PREFIX)/share/man/man1/express.1
|
||||
|
||||
test:
|
||||
@$(NODE) spec/node.js all
|
||||
|
||||
app: app-chat
|
||||
|
||||
app-chat:
|
||||
@$(NODE) examples/chat/app.js
|
||||
|
||||
app-upload:
|
||||
@$(NODE) examples/upload/app.js
|
||||
|
||||
.PHONY: init test app
|
||||
@CONNECT_ENV=test ./support/expresso/bin/expresso \
|
||||
--growl \
|
||||
-I lib \
|
||||
-I support/connect/lib \
|
||||
-I support/haml/lib \
|
||||
-I support/jade/lib \
|
||||
-I support/ejs/lib \
|
||||
$(TESTFLAGS) \
|
||||
test/*.test.js
|
||||
test-cov:
|
||||
@TESTFLAGS=--cov $(MAKE) test
|
||||
|
||||
docs: docs/api.html $(MANPAGES) $(HTMLDOCS)
|
||||
@ echo "... generating TOC"
|
||||
@./support/toc.js docs/guide.html
|
||||
|
||||
docs/api.html: lib/express/*.js
|
||||
dox --title Express \
|
||||
--desc "High performance web framework for [node](http://nodejs.org)." \
|
||||
$(shell find lib/express/* -type f) > $@
|
||||
|
||||
%.1: %.md
|
||||
@echo "... $< -> $@"
|
||||
@ronn -r --pipe $< > $@
|
||||
|
||||
%.html: %.md
|
||||
@echo "... $< -> $@"
|
||||
@ronn -5 --pipe --fragment $< \
|
||||
| cat docs/layout/head.html - docs/layout/foot.html \
|
||||
| sed 's/NAME/Express/g' \
|
||||
> $@
|
||||
|
||||
docclean:
|
||||
rm -f docs/*.{1,html}
|
||||
|
||||
.PHONY: install uninstall install-docs install-support uninstall-support install-docs uninstall-docs test test-cov docs docclean
|
||||
+61
-87
@@ -2,113 +2,87 @@
|
||||
# Express
|
||||
|
||||
Insanely fast (and small) server-side JavaScript web development framework
|
||||
built on **node.js** and the **V8 JavaScript engine**.
|
||||
|
||||
* Visit the [Wiki](http://wiki.github.com/visionmedia/express) for documentation
|
||||
* Visit the [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
|
||||
## Features (so far)
|
||||
|
||||
* Sexy DSL with robust sinatra-like routing
|
||||
* High performance
|
||||
* Session support
|
||||
* Mime helpers
|
||||
* Redirection helpers
|
||||
* Multipart file upload support
|
||||
* Test helpers (mock requests etc)
|
||||
* Environment based configuration
|
||||
* Light-weight JavaScript class implementation via js-oo
|
||||
* View support (ejs, haml, sass, etc)
|
||||
* Full test coverage
|
||||
* Extremely readable specs
|
||||
built on [node](http://nodejs.org) and [Connect](http://github.com/extjs/Connect).
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
## Installation
|
||||
|
||||
Currently Express must be cloned (or downloaded), you can use the following command to
|
||||
get rolling and initialize the submodule dependencies:
|
||||
npm:
|
||||
|
||||
$ git clone git://github.com/visionmedia/express.git && cd express && git submodule update --init && make app
|
||||
|
||||
Or with the [gh](http://github.com/visionmedia/gh) utility:
|
||||
$ npm install connect
|
||||
$ npm install express
|
||||
|
||||
$ gh clone visionmedia express && cd express && git submodule update --init && make app
|
||||
curl:
|
||||
|
||||
## Performance
|
||||
$ curl -# http://expressjs.com/install.sh | sh
|
||||
|
||||
Extensive performance enhancements have not yet been made,
|
||||
since we are focusing on the framework it-self at the moment.
|
||||
|
||||
However if you are interested view the premature [benchmarks for Express framework](http://vision-media.ca/resources/nodejs/express-nodejs-web-development-framework-performance).
|
||||
git clone, first update the submodules:
|
||||
|
||||
## Examples
|
||||
$ git submodule update --init
|
||||
$ make install
|
||||
$ make install-support
|
||||
|
||||
Below is a minimal app example when express is already within your load path.
|
||||
## Features
|
||||
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/hello', function(){
|
||||
this.contentType('html')
|
||||
return '<h1>World<h1>'
|
||||
})
|
||||
|
||||
get('/user/:id?', function(id) {
|
||||
this.render('user.haml.html', {
|
||||
locals: {
|
||||
name: id ? 'User ' + id : 'You'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
run()
|
||||
|
||||
## Running Tests
|
||||
* Robust routing
|
||||
* Redirection helpers
|
||||
* Dynamic view helpers
|
||||
* Content negotiation
|
||||
* Focus on high performance
|
||||
* View rendering and partials support
|
||||
* Environment based configuration
|
||||
* Session based flash notifications
|
||||
* Built on [Connect](http://github.com/senchalabs/connect)
|
||||
* Executable for generating applications quickly
|
||||
|
||||
First we need to ensure all submodules are updated:
|
||||
|
||||
$ make init
|
||||
Via Connect:
|
||||
|
||||
Express uses the [JSpec](http://jspec.info) BDD JavaScript testing
|
||||
framework to write and run elegant spec suites. JSpec is frozen
|
||||
to spec/lib and does not require separate installation.
|
||||
* Session support
|
||||
* Cache API
|
||||
* Mime helpers
|
||||
* ETag support
|
||||
* Persistent flash notifications
|
||||
* Cookie support
|
||||
* JSON-RPC
|
||||
* Logging
|
||||
* and _much_ more!
|
||||
|
||||
$ make test
|
||||
|
||||
Run individual suites:
|
||||
|
||||
$ node spec/node.js core
|
||||
$ node spec/node.js mime
|
||||
$ node spec/node.js routing
|
||||
...
|
||||
|
||||
Express is currently being developed with node --version:
|
||||
v0.1.31
|
||||
|
||||
## More Information
|
||||
|
||||
* [JavaScript Extensions & Utilities](http://github.com/visionmedia/ext.js)
|
||||
* [JavaScript Sass](http://github.com/visionmedia/sass.js)
|
||||
* [Scons Build System](http://www.scons.org/) (some development dependencies rely on this, ex libxmljs)
|
||||
* Featured in [Advanced JavaScript e-book](http://www.dev-mag.com/2010/02/18/advanced-javascript/) for only $4
|
||||
|
||||
## Contributors
|
||||
|
||||
* TJ Holowaychuk (visionmedia) <tj@vision-media.ca>
|
||||
* Aaron Heckmann (aheckmann) <aaron.heckmann+github@gmail.com>
|
||||
* Ciaran Jessup (ciaranj) <ciaranj@gmail.com>
|
||||
* Gareth Jones (csausdev) <gareth.jones@sensis.com.au>
|
||||
The following are the major contributors of Express (in no specific order).
|
||||
|
||||
* TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
|
||||
* Ciaran Jessup ([ciaranj](http://github.com/ciaranj))
|
||||
* Aaron Heckmann ([aheckmann](http://github.com/aheckmann))
|
||||
* Guillermo Rauch ([guille](http://github.com/guille))
|
||||
|
||||
## More Information
|
||||
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* [JavaScript Extensions & Utilities](http://github.com/visionmedia/ext.js)
|
||||
* [JavaScript Sass](http://github.com/visionmedia/sass.js)
|
||||
* [JavaScript Haml](http://github.com/visionmedia/haml.js)
|
||||
* [JavaScript Jade](http://github.com/visionmedia/jade) Haml successor
|
||||
|
||||
## Node Compatibility
|
||||
|
||||
The latest release of Express is compatible with node --version:
|
||||
|
||||
v0.1.100
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2009-2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
Arquivo executável
+185
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var sys = require('sys'),
|
||||
fs = require('fs'),
|
||||
childProcess = require('child_process');
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
var version = '1.0.0beta2';
|
||||
|
||||
/**
|
||||
* Usage documentation.
|
||||
*/
|
||||
|
||||
var usage = ''
|
||||
+ '\x1b[1mUsage\x1b[0m: express [options] [PATH]\n'
|
||||
+ '\n'
|
||||
+ '\x1b[1mOptions\x1b[0m:\n'
|
||||
+ ' -v, --version Output framework version\n'
|
||||
+ ' -h, --help Output help information\n';
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
*/
|
||||
|
||||
var jadeLayout = [
|
||||
'!!!',
|
||||
'html',
|
||||
' head',
|
||||
' title= title',
|
||||
' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')',
|
||||
' body!= body'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Default sass template.
|
||||
*/
|
||||
|
||||
var sass = [
|
||||
'body',
|
||||
' :padding 50px',
|
||||
' :font 14px "Lucida Grande", "Helvetica Nueue", Arial, sans-serif'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Jade index template.
|
||||
*/
|
||||
|
||||
var jadeIndex = [
|
||||
'h1= title',
|
||||
'p Welcome to #{title}'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* App template.
|
||||
*/
|
||||
|
||||
var app = [
|
||||
'',
|
||||
'/**',
|
||||
' * Module dependencies.',
|
||||
' */',
|
||||
'',
|
||||
'var express = require(\'express\'),',
|
||||
' connect = require(\'connect\');',
|
||||
'',
|
||||
'// Create and export Express app',
|
||||
'',
|
||||
'var app = express.createServer();',
|
||||
'',
|
||||
'// Configuration',
|
||||
'',
|
||||
'app.configure(function(){',
|
||||
' app.set(\'views\', __dirname + \'/views\');',
|
||||
' app.use(connect.bodyDecoder());',
|
||||
' app.use(connect.methodOverride());',
|
||||
' app.use(connect.compiler({ src: __dirname + \'/public\', enable: [\'sass\'] }));',
|
||||
' app.use(connect.staticProvider(__dirname + \'/public\'));',
|
||||
'});',
|
||||
'',
|
||||
'app.configure(\'development\', function(){',
|
||||
' app.set(\'reload views\', 1000);',
|
||||
' app.use(connect.errorHandler({ dumpExceptions: true, showStack: true })); ',
|
||||
'});',
|
||||
'',
|
||||
'app.configure(\'production\', function(){',
|
||||
' app.use(connect.errorHandler()); ',
|
||||
'});',
|
||||
'',
|
||||
'// Routes',
|
||||
'',
|
||||
'app.get(\'/\', function(req, res){',
|
||||
' res.render(\'index.jade\', {',
|
||||
' locals: {',
|
||||
' title: \'Express\'',
|
||||
' }',
|
||||
' });',
|
||||
'});',
|
||||
'',
|
||||
'app.listen(3000);',
|
||||
''
|
||||
].join('\n');
|
||||
|
||||
// Parse arguments
|
||||
|
||||
var args = process.argv.slice(2),
|
||||
path = '.';
|
||||
while (args.length) {
|
||||
var arg = args.shift();
|
||||
switch (arg) {
|
||||
case '-h':
|
||||
case '--help':
|
||||
abort(usage);
|
||||
break;
|
||||
case '-v':
|
||||
case '--version':
|
||||
abort(version);
|
||||
break;
|
||||
default:
|
||||
path = arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate application
|
||||
|
||||
(function createApplication(path) {
|
||||
mkdir(path, function(){
|
||||
mkdir(path + '/pids');
|
||||
mkdir(path + '/logs');
|
||||
mkdir(path + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
write(path + '/public/stylesheets/style.sass', sass);
|
||||
});
|
||||
mkdir(path + '/views/partials', function(){
|
||||
write(path + '/views/layout.jade', jadeLayout);
|
||||
write(path + '/views/index.jade', jadeIndex);
|
||||
});
|
||||
write(path + '/app.js', app);
|
||||
});
|
||||
})(path);
|
||||
|
||||
/**
|
||||
* echo str > path.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function write(path, str) {
|
||||
fs.writeFile(path, str);
|
||||
sys.puts(' create : ' + path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mkdir -p.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function mkdir(path, fn) {
|
||||
childProcess.exec('mkdir -p ' + path, function(err){
|
||||
if (err) throw err;
|
||||
sys.puts(' create : ' + path);
|
||||
fn && fn();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit with the given `str`.
|
||||
*
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function abort(str) {
|
||||
sys.error(str);
|
||||
process.exit(1);
|
||||
}
|
||||
+1088
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -0,0 +1,77 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "CONTRIB" "" "July 2010" "" ""
|
||||
.
|
||||
.SS "Development Dependencies"
|
||||
Express development dependencies are stored within the \fI\./support\fR directory\. To update them execute:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ git submodule update \-\-init
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Running Tests"
|
||||
Express uses the Expresso \fIhttp://github\.com/visionmedia/expresso\fR TDD framework to write and run elegant test suites extremely fast\. To run all test suites simply execute:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ make test
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
To target specific suites we may specify the files via:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ make test TESTS=test/view\.test\.js
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
To check test coverage run:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ make test\-cov
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Contributions"
|
||||
To accept a contribution, you should follow these guidelines:
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
All tests \fImust\fR pass
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Your alterations or additions \fImust\fR include tests
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Your commit(s) should be \fIfocused\fR, do not commit once for several changes
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Do \fInot\fR alter release information such as the \fIversion\fR, or \fIHistory\.md\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Indents are \fI4\fR spaces\.
|
||||
.
|
||||
.IP "" 0
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
var done;
|
||||
$(document).scroll(function(event){
|
||||
if (!done) {
|
||||
$('#toc').animate({
|
||||
top: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<h3 id="Development-Dependencies">Development Dependencies</h3>
|
||||
|
||||
<p>Express development dependencies are stored within the <em>./support</em> directory. To
|
||||
update them execute:</p>
|
||||
|
||||
<pre><code>$ git submodule update --init
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Running-Tests">Running Tests</h3>
|
||||
|
||||
<p>Express uses the <a href="http://github.com/visionmedia/expresso">Expresso</a> TDD
|
||||
framework to write and run elegant test suites extremely fast. To run all test suites
|
||||
simply execute:</p>
|
||||
|
||||
<pre><code>$ make test
|
||||
</code></pre>
|
||||
|
||||
<p>To target specific suites we may specify the files via:</p>
|
||||
|
||||
<pre><code>$ make test TESTS=test/view.test.js
|
||||
</code></pre>
|
||||
|
||||
<p>To check test coverage run:</p>
|
||||
|
||||
<pre><code>$ make test-cov
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Contributions">Contributions</h3>
|
||||
|
||||
<p>To accept a contribution, you should follow these guidelines:</p>
|
||||
|
||||
<ul>
|
||||
<li>All tests <em>must</em> pass</li>
|
||||
<li>Your alterations or additions <em>must</em> include tests</li>
|
||||
<li>Your commit(s) should be <em>focused</em>, do not commit once for several changes</li>
|
||||
<li>Do <em>not</em> alter release information such as the <em>version</em>, or <em>History.md</em></li>
|
||||
<li>Indents are <em>4</em> spaces.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
### Development Dependencies
|
||||
|
||||
Express development dependencies are stored within the _./support_ directory. To
|
||||
update them execute:
|
||||
|
||||
$ git submodule update --init
|
||||
|
||||
### Running Tests
|
||||
|
||||
Express uses the [Expresso](http://github.com/visionmedia/expresso) TDD
|
||||
framework to write and run elegant test suites extremely fast. To run all test suites
|
||||
simply execute:
|
||||
|
||||
$ make test
|
||||
|
||||
To target specific suites we may specify the files via:
|
||||
|
||||
$ make test TESTS=test/view.test.js
|
||||
|
||||
To check test coverage run:
|
||||
|
||||
$ make test-cov
|
||||
|
||||
### Contributions
|
||||
|
||||
To accept a contribution, you should follow these guidelines:
|
||||
|
||||
* All tests _must_ pass
|
||||
* Your alterations or additions _must_ include tests
|
||||
* Your commit(s) should be _focused_, do not commit once for several changes
|
||||
* Do _not_ alter release information such as the _version_, or _History.md_
|
||||
* Indents are _4_ spaces.
|
||||
@@ -0,0 +1,25 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "EXECUTABLE" "" "July 2010" "" ""
|
||||
.
|
||||
.SH "Synopsis"
|
||||
.
|
||||
.nf
|
||||
|
||||
express [\-h|\-\-help] [\-v|\-\-version] [PATH]
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.SH "Description"
|
||||
The \fBexpress\fR executable generates apps at the given \fBPATH\fR or the current working directory\. Although Express is not bound to a specific application structure, this executable creates a maintainable base app\.
|
||||
.
|
||||
.SH "Options"
|
||||
.
|
||||
.nf
|
||||
|
||||
\-v, \-\-version Output framework version
|
||||
\-h, \-\-help Display help information
|
||||
.
|
||||
.fi
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
var done;
|
||||
$(document).scroll(function(event){
|
||||
if (!done) {
|
||||
$('#toc').animate({
|
||||
top: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<h2 id="Synopsis">Synopsis</h2>
|
||||
|
||||
<pre><code>express [-h|--help] [-v|--version] [PATH]
|
||||
</code></pre>
|
||||
|
||||
<h2 id="Description">Description</h2>
|
||||
|
||||
<p>The <code>express</code> executable generates apps at the given <strong>PATH</strong> or the
|
||||
current working directory. Although Express is not bound to a specific
|
||||
application structure, this executable creates a maintainable base app.</p>
|
||||
|
||||
<h2 id="Options">Options</h2>
|
||||
|
||||
<pre><code>-v, --version Output framework version
|
||||
-h, --help Display help information
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
## Synopsis
|
||||
|
||||
express [-h|--help] [-v|--version] [PATH]
|
||||
|
||||
## Description
|
||||
|
||||
The `express` executable generates apps at the given **PATH** or the
|
||||
current working directory. Although Express is not bound to a specific
|
||||
application structure, this executable creates a maintainable base app.
|
||||
|
||||
## Options
|
||||
|
||||
-v, --version Output framework version
|
||||
-h, --help Display help information
|
||||
|
||||
+1109
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -0,0 +1,955 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
var done;
|
||||
$(document).scroll(function(event){
|
||||
if (!done) {
|
||||
$('#toc').animate({
|
||||
top: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container"><ul id="toc">
|
||||
<li><a href="#Installation">Installation</a></li>
|
||||
<li><a href="#Creating-An-Application">Creating An Application</a></li>
|
||||
<li><a href="#Configuration">Configuration</a></li>
|
||||
<li><a href="#Settings">Settings</a></li>
|
||||
<li><a href="#Routing">Routing</a></li>
|
||||
<li><a href="#Passing-Route-Control">Passing Route Control</a></li>
|
||||
<li><a href="#Middleware">Middleware</a></li>
|
||||
<li><a href="#Error-Handling">Error Handling</a></li>
|
||||
<li><a href="#View-Rendering">View Rendering</a></li>
|
||||
<li><a href="#View-Partials">View Partials</a></li>
|
||||
<li><a href="#Template-Engines">Template Engines</a></li>
|
||||
<li><a href="#req-header-key-defaultValue-">req.header()</a></li>
|
||||
<li><a href="#req-accepts-type-">req.accepts()</a></li>
|
||||
<li><a href="#req-param-name-">req.param()</a></li>
|
||||
<li><a href="#req-flash-type-msg-">req.flash()</a></li>
|
||||
<li><a href="#req-isXMLHttpRequest">req.isXMLHttpRequest</a></li>
|
||||
<li><a href="#res-header-key-val-">res.header()</a></li>
|
||||
<li><a href="#res-contentType-type-">res.contentType()</a></li>
|
||||
<li><a href="#res-attachment-filename-">res.attachment()</a></li>
|
||||
<li><a href="#res-sendfile-path-">res.sendfile()</a></li>
|
||||
<li><a href="#res-download-file-filename-">res.download()</a></li>
|
||||
<li><a href="#res-send-body-status-headers-status-status-">res.send()</a></li>
|
||||
<li><a href="#res-redirect-url-status-">res.redirect()</a></li>
|
||||
<li><a href="#res-render-view-options-fn-">res.render()</a></li>
|
||||
<li><a href="#res-partial-view-options-">res.partial()</a></li>
|
||||
<li><a href="#app-set-name-val-">app.set()</a></li>
|
||||
<li><a href="#app-enable-name-">app.enable()</a></li>
|
||||
<li><a href="#app-disable-name-">app.disable()</a></li>
|
||||
<li><a href="#app-configure-env-function-function-">app.configure()</a></li>
|
||||
<li><a href="#app-redirect-name-val-">app.redirect()</a></li>
|
||||
<li><a href="#app-error-function-">app.error()</a></li>
|
||||
<li><a href="#app-helpers-obj-">app.helpers()</a></li>
|
||||
<li><a href="#app-dynamicHelpers-obj-">app.dynamicHelpers()</a></li>
|
||||
<li><a href="#app-listen-port-host-">app.listen()</a></li>
|
||||
</ul>
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<h3 id="Installation">Installation</h3>
|
||||
|
||||
<p>curl:</p>
|
||||
|
||||
<pre><code>$ curl -# http://expressjs.com/install.sh | sh
|
||||
</code></pre>
|
||||
|
||||
<p>npm:</p>
|
||||
|
||||
<pre><code>$ npm install connect
|
||||
$ npm install express
|
||||
</code></pre>
|
||||
|
||||
<p>git clone, first update the submodules:</p>
|
||||
|
||||
<pre><code>$ git submodule update --init
|
||||
$ make install
|
||||
$ make install-support
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Creating-An-Application">Creating An Application</h3>
|
||||
|
||||
<p>The <em>express.Server</em> now inherits from <em>http.Server</em>, however
|
||||
follows the same idiom by providing <em>express.createServer()</em> as shown below. This means
|
||||
that you can utilize Express server's transparently with other libraries.</p>
|
||||
|
||||
<pre><code>var app = require('express').createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('hello world');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Configuration">Configuration</h3>
|
||||
|
||||
<p>Express supports arbitrary environments, such as <em>production</em> and <em>development</em>. Developers
|
||||
can use the <em>configure()</em> method to setup needs required by the current environment. When
|
||||
<em>configure()</em> is called without an environment name it will be run in <em>every</em> environment
|
||||
prior to the environment specific callback.</p>
|
||||
|
||||
<p>In the example below we only <em>dumpExceptions</em>, and respond with exception stack traces
|
||||
in <em>development</em> mode, however for both environments we utilize <em>methodOverride</em> and <em>bodyDecoder</em>.</p>
|
||||
|
||||
<pre><code>app.configure(function(){
|
||||
app.use(connect.methodOverride());
|
||||
app.use(connect.bodyDecoder());
|
||||
});
|
||||
|
||||
app.configure('development', function(){
|
||||
app.use(connect.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
app.configure('production', function(){
|
||||
app.use(connect.errorHandler());
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>For internal and arbitrary settings Express provides the <em>set(key[, val])</em>, <em>enable(key)</em>, <em>disable(key)</em> methods:</p>
|
||||
|
||||
<pre><code>app.configure(function(){
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('views');
|
||||
// => "... views directory ..."
|
||||
|
||||
app.enable('some feature');
|
||||
// same as app.set('some feature', true);
|
||||
|
||||
app.disable('some feature');
|
||||
// same as app.set('some feature', false);
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>To alter the environment we can set the <em>CONNECT_ENV</em> environment variable,
|
||||
or more specifically <em>EXPRESS_ENV</em>, for example:</p>
|
||||
|
||||
<pre><code>$ EXPRESS_ENV=production node app.js
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Settings">Settings</h3>
|
||||
|
||||
<p>Express supports the following settings out of the box:</p>
|
||||
|
||||
<ul>
|
||||
<li><em>env</em> Application environment set internally, use <em>app.set('env')</em> on <em>Server#listen()</em></li>
|
||||
<li><em>home</em> Application base path used with <em>res.redirect()</em>, when mounted defaults
|
||||
to <em>Server#route</em>, otherwise "/". Assigned on <em>Server#listen()</em>.</li>
|
||||
<li><em>views</em> Root views directory defaulting to <strong>CWD/views</strong></li>
|
||||
<li><em>view engine</em> Default view engine name for views rendered without extensions</li>
|
||||
<li><em>reload views</em> Reloads altered views, by default watches for <em>mtime</em> changes with
|
||||
with a 5 minute interval. Example: <em>app.set('reload views', 60000);</em></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3 id="Routing">Routing</h3>
|
||||
|
||||
<p>Express utilizes the HTTP verbs to provide a meaningful, expressive routing API.
|
||||
For example we may want to render a user's account for the path <em>/user/12</em>, this
|
||||
can be done by defining the route below. The values associated to the named placeholders,
|
||||
are passed as the <em>third</em> argument, which here we name <em>params</em>.</p>
|
||||
|
||||
<pre><code>app.get('/user/:id', function(req, res, params){
|
||||
res.send('user ' + params.id);
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>A route is simple a string which is compiled to a <em>RegExp</em> internally. For example
|
||||
when <em>/user/:id</em> is compiled, a simplified version of the regexp may look similar to:</p>
|
||||
|
||||
<pre><code>\/user\/([^\/]+)\/?
|
||||
</code></pre>
|
||||
|
||||
<p>Regular expression literals may also be passed for complex uses. Since capture
|
||||
groups with literal <em>RegExp</em>'s are anonymous we can access them directly from the <em>params</em> array.</p>
|
||||
|
||||
<pre><code>app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res, params){
|
||||
res.send(params);
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Curl requests against the previously defined route:</p>
|
||||
|
||||
<pre><code> $ curl http://dev:3000/user
|
||||
[null,null]
|
||||
$ curl http://dev:3000/users
|
||||
[null,null]
|
||||
$ curl http://dev:3000/users/1
|
||||
["1",null]
|
||||
$ curl http://dev:3000/users/1..15
|
||||
["1","15"]
|
||||
</code></pre>
|
||||
|
||||
<p>Below are some route examples, and the associated paths that they
|
||||
may consume:</p>
|
||||
|
||||
<pre><code> "/user/:id"
|
||||
/user/12
|
||||
|
||||
"/users/:id?"
|
||||
/users/5
|
||||
/users
|
||||
|
||||
"/files/*"
|
||||
/files/jquery.js
|
||||
/files/javascripts/jquery.js
|
||||
|
||||
"/file/*.*"
|
||||
/files/jquery.js
|
||||
/files/javascripts/jquery.js
|
||||
|
||||
"/user/:id/:operation?"
|
||||
/user/1
|
||||
/user/1/edit
|
||||
|
||||
"/products.:format"
|
||||
/products.json
|
||||
/products.xml
|
||||
|
||||
"/products.:format?"
|
||||
/products.json
|
||||
/products.xml
|
||||
/products
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Passing-Route-Control">Passing Route Control</h3>
|
||||
|
||||
<p>We may pass control to the next <em>matching</em> route, by calling the <em>fourth</em> parameter,
|
||||
the <em>next()</em> function. When a match cannot be made, control is passed back to Connect.</p>
|
||||
|
||||
<pre><code>app.get('/users/:id?', function(req, res, params){
|
||||
if (params.id) {
|
||||
// do something
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res, params){
|
||||
// do something else
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Middleware">Middleware</h3>
|
||||
|
||||
<p>The Express <em>Plugin</em> is no more! middleware via <a href="http://github.com/extjs/Connect">Connect</a> can be
|
||||
passed to <em>express.createServer()</em> as you would with a regular Connect server. For example:</p>
|
||||
|
||||
<pre><code>var connect = require('connect'),
|
||||
express = require('express');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
connect.bodyDecoder()
|
||||
);
|
||||
</code></pre>
|
||||
|
||||
<p>Alternatively we can <em>use()</em> them which is useful when adding middleware within <em>configure()</em> blocks:</p>
|
||||
|
||||
<pre><code>app.use(connect.logger({ format: ':method :uri' }));
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Error-Handling">Error Handling</h3>
|
||||
|
||||
<p>Express provides the <em>app.error()</em> method which receives exceptions thrown within a route,
|
||||
or passed to <em>next(err)</em>. Below is an example which serves different pages based on our
|
||||
ad-hoc <em>NotFound</em> exception:</p>
|
||||
|
||||
<pre><code>function NotFound(msg){
|
||||
this.name = 'NotFound';
|
||||
Error.call(this, msg);
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
}
|
||||
|
||||
sys.inherits(NotFound, Error);
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound;
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res){
|
||||
throw new Error('keyboard cat!');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>We can call <em>app.error()</em> several times as shown below.
|
||||
Here we check for an instanceof <em>NotFound</em> and show the
|
||||
404 page, or we pass on to the next error handler.</p>
|
||||
|
||||
<pre><code>app.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res.render('404.jade');
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Here we assume all errors as 500 for the simplicity of
|
||||
this demo, however you can choose whatever you like</p>
|
||||
|
||||
<pre><code>app.error(function(err, req, res){
|
||||
res.render('500.jade', {
|
||||
locals: {
|
||||
error: err
|
||||
}
|
||||
});
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Our apps could also utilize the Connect <em>errorHandler</em> middleware
|
||||
to report on exceptions. For example if we wish to output exceptions
|
||||
in "development" mode to <em>stderr</em> we can use:</p>
|
||||
|
||||
<pre><code>app.use(connect.errorHandler({ dumpExceptions: true }));
|
||||
</code></pre>
|
||||
|
||||
<p>Also during development we may want fancy html pages to show exceptions
|
||||
that are passed or thrown, so we can set <em>showStack</em> to true:</p>
|
||||
|
||||
<pre><code>app.use(connect.errorHandler({ showStack: true, dumpExceptions: true }));
|
||||
</code></pre>
|
||||
|
||||
<p>The <em>errorHandler</em> middleware also responds with <em>json</em> if <em>Accept: application/json</em>
|
||||
is present, which is useful for developing apps that rely heavily on client-side JavaScript.</p>
|
||||
|
||||
<h3 id="View-Rendering">View Rendering</h3>
|
||||
|
||||
<p>View filenames take the form <em>Express</em>.<em>ENGINE</em>, where <em>ENGINE</em> is the name
|
||||
of the module that will be required. For example the view <em>layout.ejs</em> will
|
||||
tell the view system to <em>require('ejs')</em>, the module being loaded must (currently)
|
||||
export the method <em>exports.render(str, options)</em> to comply with Express, however
|
||||
with will likely be extensible in the future.</p>
|
||||
|
||||
<p>Below is an example using <a href="http://github.com/visionmedia/haml.js">Haml.js</a> to render <em>index.html</em>,
|
||||
and since we do not use <em>layout: false</em> the rendered contents of <em>index.html</em> will be passed as
|
||||
the <em>body</em> local variable in <em>layout.haml</em>.</p>
|
||||
|
||||
<pre><code>app.get('/', function(req, res){
|
||||
res.render('index.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>The new <em>view engine</em> setting allows us to specify our default template engine,
|
||||
so for example when using <a href="http://github.com/visionmedia/jade">Jade</a> we could set:</p>
|
||||
|
||||
<pre><code>app.set('view engine', 'jade');
|
||||
</code></pre>
|
||||
|
||||
<p>Allowing us to render with:</p>
|
||||
|
||||
<pre><code>res.render('index');
|
||||
</code></pre>
|
||||
|
||||
<p>vs:</p>
|
||||
|
||||
<pre><code>res.render('index.jade');
|
||||
</code></pre>
|
||||
|
||||
<p>When <em>view engine</em> is set, extensions are entirely optional, however we can still
|
||||
mix and match template engines:</p>
|
||||
|
||||
<pre><code>res.render('another-page.ejs');
|
||||
</code></pre>
|
||||
|
||||
<h3 id="View-Partials">View Partials</h3>
|
||||
|
||||
<p>The Express view system has built-in support for partials and collections, which are
|
||||
sort of "mini" views representing a document fragment. For example rather than iterating
|
||||
in a view to display comments, we would use a partial with collection support:</p>
|
||||
|
||||
<pre><code>partial('comment.haml', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>To make things even less verbose we can assume the extension as <em>.haml</em> when omitted,
|
||||
however if we wished we could use an ejs partial, within a haml view for example.</p>
|
||||
|
||||
<pre><code>partial('comment', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>And once again even further, when rendering a collection we can simply pass
|
||||
an array, if no other options are desired:</p>
|
||||
|
||||
<pre><code>partial('comments', comments);
|
||||
</code></pre>
|
||||
|
||||
<p>When using the partial collection support a few "magic" variables are provided
|
||||
for free:</p>
|
||||
|
||||
<ul>
|
||||
<li><em>firstInCollection</em> True if this is the first object</li>
|
||||
<li><em>indexInCollection</em> Index of the object in the collection</li>
|
||||
<li>_lastInCollection _ True if this is the last object</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3 id="Template-Engines">Template Engines</h3>
|
||||
|
||||
<p>Below are a few template engines commonly used with Express:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://github.com/visionmedia/jade">Jade</a> haml.js successor</li>
|
||||
<li><a href="http://github.com/visionmedia/haml.js">Haml</a> indented templates</li>
|
||||
<li><a href="http://github.com/visionmedia/ejs">EJS</a> Embedded JavaScript</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3 id="req-header-key-defaultValue-">req.header(key[, defaultValue])</h3>
|
||||
|
||||
<p>Get the case-insensitive request header <em>key</em>, with optional <em>defaultValue</em>:</p>
|
||||
|
||||
<pre><code>req.header('Host');
|
||||
req.header('host');
|
||||
req.header('Accept', '*/*');
|
||||
</code></pre>
|
||||
|
||||
<h3 id="req-accepts-type-">req.accepts(type)</h3>
|
||||
|
||||
<p>Check if the <em>Accept</em> header is present, and includes the given <em>type</em>.</p>
|
||||
|
||||
<p>When the <em>Accept</em> header is not present <em>true</em> is returned. Otherwise
|
||||
the given <em>type</em> is matched by an exact match, and then subtypes. You
|
||||
may pass the subtype such as "html" which is then converted internally
|
||||
to "text/html" using the mime lookup table.</p>
|
||||
|
||||
<pre><code>// Accept: text/html
|
||||
req.accepts('html');
|
||||
// => true
|
||||
|
||||
// Accept: text/*; application/json
|
||||
req.accepts('html');
|
||||
req.accepts('text/html');
|
||||
req.accepts('text/plain');
|
||||
req.accepts('application/json');
|
||||
// => true
|
||||
|
||||
req.accepts('image/png');
|
||||
req.accepts('png');
|
||||
// => false
|
||||
</code></pre>
|
||||
|
||||
<h3 id="req-param-name-">req.param(name)</h3>
|
||||
|
||||
<p>Return the value of param <em>name</em> when present.</p>
|
||||
|
||||
<ul>
|
||||
<li>Checks route placeholders, ex: /user/:id</li>
|
||||
<li>Checks query string params, ex: ?id=12</li>
|
||||
<li>Checks urlencoded body params, ex: id=12</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>To utilize urlencoded request bodies, <em>req.body</em>
|
||||
should be an object. This can be done by using
|
||||
the <em>connect.bodyDecoder</em> middleware.</p>
|
||||
|
||||
<h3 id="req-flash-type-msg-">req.flash(type[, msg])</h3>
|
||||
|
||||
<p>Queue flash <em>msg</em> of the given <em>type</em>.</p>
|
||||
|
||||
<pre><code>req.flash('info', 'email sent');
|
||||
req.flash('error', 'email delivery failed');
|
||||
req.flash('info', 'email re-sent');
|
||||
// => 2
|
||||
|
||||
req.flash('info');
|
||||
// => ['email sent', 'email re-sent']
|
||||
|
||||
req.flash('info');
|
||||
// => []
|
||||
|
||||
req.flash();
|
||||
// => { error: ['email delivery failed'], info: [] }
|
||||
</code></pre>
|
||||
|
||||
<h3 id="req-isXMLHttpRequest">req.isXMLHttpRequest</h3>
|
||||
|
||||
<p>Also aliased as <em>req.xhr</em>, this getter checks the <em>X-Requested-With</em> header
|
||||
to see if it was issued by an <em>XMLHttpRequest</em>:</p>
|
||||
|
||||
<pre><code>req.xhr
|
||||
req.isXMLHttpRequest
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-header-key-val-">res.header(key[, val])</h3>
|
||||
|
||||
<p>Get or set the response header <em>key</em>.</p>
|
||||
|
||||
<pre><code>res.header('Content-Length');
|
||||
// => undefined
|
||||
|
||||
res.header('Content-Length', 123);
|
||||
// => 123
|
||||
|
||||
res.header('Content-Length');
|
||||
// => 123
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-contentType-type-">res.contentType(type)</h3>
|
||||
|
||||
<p>Sets the <em>Content-Type</em> response header to the given <em>type</em>.</p>
|
||||
|
||||
<pre><code> var filename = 'path/to/image.png';
|
||||
res.contentType(filename);
|
||||
// res.headers['Content-Type'] is now "image/png"
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-attachment-filename-">res.attachment([filename])</h3>
|
||||
|
||||
<p>Sets the <em>Content-Disposition</em> response header to "attachment", with optional <em>filename</em>.</p>
|
||||
|
||||
<pre><code> res.attachment('path/to/my/image.png');
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-sendfile-path-">res.sendfile(path)</h3>
|
||||
|
||||
<p>Used by <code>res.download()</code> to transfer an arbitrary file.</p>
|
||||
|
||||
<pre><code>res.sendfile('path/to/my.file');
|
||||
</code></pre>
|
||||
|
||||
<p>This is <em>not</em> a substitution for Connect's <em>staticProvider</em> middleware, it does not
|
||||
support HTTP caching, and does not perform any security checks. This method is utilized
|
||||
by <em>res.download()</em> to transfer static files, and allows you do to so from outside of
|
||||
the public directory, so suitable security checks should be applied.</p>
|
||||
|
||||
<h3 id="res-download-file-filename-">res.download(file[, filename])</h3>
|
||||
|
||||
<p>Transfer the given <em>file</em> as an attachment with optional alternative <em>filename</em>.</p>
|
||||
|
||||
<pre><code>res.download('path/to/image.png');
|
||||
res.download('path/to/image.png', 'foo.png');
|
||||
</code></pre>
|
||||
|
||||
<p>This is equivalent to:</p>
|
||||
|
||||
<pre><code>res.attachment(file);
|
||||
res.sendfile(file);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res-send-body-status-headers-status-status-">res.send(body|status[, headers|status[, status]])</h3>
|
||||
|
||||
<p>The <code>res.send()</code> method is a high level response utility allowing you to pass
|
||||
objects to respond with json, strings for html, arbitrary _Buffer_s or numbers for status
|
||||
code based responses. The following are all valid uses:</p>
|
||||
|
||||
<pre><code> res.send(new Buffer('wahoo'));
|
||||
res.send({ some: 'json' });
|
||||
res.send('<p>some html</p>');
|
||||
res.send('Sorry, cant find that', 404);
|
||||
res.send('text', { 'Content-Type': 'text/plain' }, 201);
|
||||
res.send(404);
|
||||
</code></pre>
|
||||
|
||||
<p>By default the <em>Content-Type</em> response header is set, however if explicitly
|
||||
assigned through <code>res.send()</code> or previously with <code>res.header()</code> or <code>res.contentType()</code>
|
||||
it will not be set again.</p>
|
||||
|
||||
<h3 id="res-redirect-url-status-">res.redirect(url[, status])</h3>
|
||||
|
||||
<p>Redirect to the given <em>url</em> with a default response <em>status</em> of 302.</p>
|
||||
|
||||
<pre><code>res.redirect('/', 301);
|
||||
res.redirect('/account');
|
||||
res.redirect('http://google.com');
|
||||
res.redirect('home');
|
||||
res.redirect('back');
|
||||
</code></pre>
|
||||
|
||||
<p>Express supports "redirect mapping", which by default provides <em>home</em>, and <em>back</em>.
|
||||
The <em>back</em> map checks the <em>Referrer</em> and <em>Referer</em> headers, while <em>home</em> utilizes
|
||||
the "home" setting and defaults to "/".</p>
|
||||
|
||||
<h3 id="res-render-view-options-fn-">res.render(view[, options[, fn]])</h3>
|
||||
|
||||
<p>Render <em>view</em> with the given <em>options</em> and optional callback <em>fn</em>.
|
||||
When a callback function is given a response will <em>not</em> be made
|
||||
automatically, however otherwise a response of <em>200</em> and <em>text/html</em> is given.</p>
|
||||
|
||||
<p> Most engines accept one or more of the following options,
|
||||
both <a href="http://github.com/visionmedia/haml.js">haml</a> and <a href="http://github.com/visionmedia/jade">jade</a> accept all:</p>
|
||||
|
||||
<ul>
|
||||
<li><em>context|scope</em> Template evaluation context (<em>this</em>)</li>
|
||||
<li><em>locals</em> Object containing local variables</li>
|
||||
<li><em>cache</em> Cache intermediate JavaScript in memory (the default in <em>production</em> mode)</li>
|
||||
<li><em>debug</em> Output debugging information</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3 id="res-partial-view-options-">res.partial(view[, options])</h3>
|
||||
|
||||
<p>Render <em>view</em> partial with the given <em>options</em>. This method is always available
|
||||
to the view as a local variable.</p>
|
||||
|
||||
<ul>
|
||||
<li><p><em>as</em> Variable name for each <em>collection</em> value, defaults to the view name.</p>
|
||||
|
||||
<ul>
|
||||
<li>as: 'something' will add the <em>something</em> local variable</li>
|
||||
<li>as: this will use the collection value as the template context</li>
|
||||
<li>as: global will merge the collection value's properties with <em>locals</em></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p><em>collection</em> Array of objects, the name is derived from the view name itself.
|
||||
For example <em>video.html</em> will have a object <em>video</em> available to it.</p></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>The following are equivalent, and the name of collection value when passed
|
||||
to the partial will be <em>movie</em> as derived from the name.</p>
|
||||
|
||||
<pre><code>partial('movie.jade', { collection: movies });
|
||||
partial('movie.jade', movies);
|
||||
partial('movie', movies);
|
||||
// In view: movie.director
|
||||
</code></pre>
|
||||
|
||||
<p>To change the local from <em>movie</em> to <em>video</em> we can use the "as" option:</p>
|
||||
|
||||
<pre><code>partial('movie', { collection: movies, as: 'video' });
|
||||
// In view: video.director
|
||||
</code></pre>
|
||||
|
||||
<p>Also we can make our movie the value of <em>this</em> within our view so that instead
|
||||
of <em>movie.director</em> we could use <em>this.director</em>.</p>
|
||||
|
||||
<pre><code>partial('movie', { collection: movies, as: this });
|
||||
// In view: this.director
|
||||
</code></pre>
|
||||
|
||||
<p>Another alternative is to "explode" the properties of the collection item into
|
||||
pseudo globals (local variables) by using <em>as: global</em>, which again is syntactic sugar:</p>
|
||||
|
||||
<pre><code>partials('movie', { collection: movies, as: global });
|
||||
// In view: director
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-set-name-val-">app.set(name[, val])</h3>
|
||||
|
||||
<p>Apply an application level setting <em>name</em> to <em>val</em>, or
|
||||
get the value of <em>name</em> when <em>val</em> is not present:</p>
|
||||
|
||||
<pre><code>app.set('reload views', 200);
|
||||
app.set('reload views');
|
||||
// => 200
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-enable-name-">app.enable(name)</h3>
|
||||
|
||||
<p>Enable the given setting <em>name</em>:</p>
|
||||
|
||||
<pre><code>app.enable('some arbitrary setting');
|
||||
app.set('some arbitrary setting');
|
||||
// => true
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-disable-name-">app.disable(name)</h3>
|
||||
|
||||
<p>Disable the given setting <em>name</em>:</p>
|
||||
|
||||
<pre><code>app.disable('some setting');
|
||||
app.set('some setting');
|
||||
// => false
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-configure-env-function-function-">app.configure(env|function[, function])</h3>
|
||||
|
||||
<p>Define a callback function for the given <em>env</em> (or all environments) with callback <em>function</em>:</p>
|
||||
|
||||
<pre><code>app.configure(function(){
|
||||
// executed for each env
|
||||
});
|
||||
|
||||
app.configure('development', function(){
|
||||
// executed for 'development' only
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-redirect-name-val-">app.redirect(name, val)</h3>
|
||||
|
||||
<p>For use with <code>res.redirect()</code> we can map redirects at the application level as shown below:</p>
|
||||
|
||||
<pre><code>app.redirect('google', 'http://google.com');
|
||||
</code></pre>
|
||||
|
||||
<p>Now in a route we may call:</p>
|
||||
|
||||
<p> res.redirect('google');</p>
|
||||
|
||||
<p>We may also map dynamic redirects:</p>
|
||||
|
||||
<pre><code>app.redirect('comments', function(req, res, params){
|
||||
return '/post/' + params.id + '/comments';
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>So now we may do the following, and the redirect will dynamically adjust to
|
||||
the context of the request. If we called this route with <em>GET /post/12</em> our
|
||||
redirect <em>Location</em> would be <em>/post/12/comments</em>.</p>
|
||||
|
||||
<pre><code>app.get('/post/:id', function(req, res){
|
||||
res.redirect('comments');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-error-function-">app.error(function)</h3>
|
||||
|
||||
<p>Adds an error handler <em>function</em> which will receive the exception as the first parameter as shown below.
|
||||
Note that we may set several error handlers by making several calls to this method, however the handler
|
||||
should call <em>next(err)</em> if it does not wish to deal with the exception:</p>
|
||||
|
||||
<pre><code>app.error(function(err, req, res, next){
|
||||
res.send(err.message, 500);
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-helpers-obj-">app.helpers(obj)</h3>
|
||||
|
||||
<p>Registers static view helpers.</p>
|
||||
|
||||
<pre><code>app.helpers({
|
||||
name: function(first, last){ return first + ', ' + last },
|
||||
firstName: 'tj',
|
||||
lastName: 'holowaychuk'
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Our view could now utilize the <em>firstName</em> and <em>lastName</em> variables,
|
||||
as well as the <em>name()</em> function exposed.</p>
|
||||
|
||||
<pre><code><%= name(firstName, lastName) %>
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-dynamicHelpers-obj-">app.dynamicHelpers(obj)</h3>
|
||||
|
||||
<p>Registers dynamic view helpers. Dynamic view helpers
|
||||
are simply functions which accept <em>req</em>, <em>res</em>, and <em>params</em>, and are
|
||||
evaluated against the <em>Server</em> instance before a view is rendered. The <em>return value</em> of this function
|
||||
becomes the local variable it is associated with.</p>
|
||||
|
||||
<pre><code>app.dynamicHelpers({
|
||||
session: function(req, res, params){
|
||||
return req.session;
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>All views would now have <em>session</em> available so that session data can be accessed via <em>session.name</em> etc:</p>
|
||||
|
||||
<pre><code><%= session.name %>
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app-listen-port-host-">app.listen([port[, host]])</h3>
|
||||
|
||||
<p>Bind the app server to the given <em>port</em>, which defaults to 3000. When <em>host</em> is omitted all
|
||||
connections will be accepted via <em>INADDR_ANY</em>.</p>
|
||||
|
||||
<pre><code>app.listen();
|
||||
app.listen(3000);
|
||||
app.listen(3000, 'n.n.n.n');
|
||||
</code></pre>
|
||||
|
||||
<p>The <em>port</em> argument may also be a string representing the path to a unix domain socket:</p>
|
||||
|
||||
<pre><code>app.listen('/tmp/express.sock');
|
||||
</code></pre>
|
||||
|
||||
<p>Then try it out:</p>
|
||||
|
||||
<pre><code>$ telnet /tmp/express.sock
|
||||
GET / HTTP/1.1
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/plain
|
||||
Content-Length: 11
|
||||
|
||||
Hello World
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+642
@@ -0,0 +1,642 @@
|
||||
|
||||
### Installation
|
||||
|
||||
curl:
|
||||
|
||||
$ curl -# http://expressjs.com/install.sh | sh
|
||||
|
||||
npm:
|
||||
|
||||
$ npm install connect
|
||||
$ npm install express
|
||||
|
||||
git clone, first update the submodules:
|
||||
|
||||
$ git submodule update --init
|
||||
$ make install
|
||||
$ make install-support
|
||||
|
||||
### Creating An Application
|
||||
|
||||
The _express.Server_ now inherits from _http.Server_, however
|
||||
follows the same idiom by providing _express.createServer()_ as shown below. This means
|
||||
that you can utilize Express server's transparently with other libraries.
|
||||
|
||||
var app = require('express').createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('hello world');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
### Configuration
|
||||
|
||||
Express supports arbitrary environments, such as _production_ and _development_. Developers
|
||||
can use the _configure()_ method to setup needs required by the current environment. When
|
||||
_configure()_ is called without an environment name it will be run in _every_ environment
|
||||
prior to the environment specific callback.
|
||||
|
||||
In the example below we only _dumpExceptions_, and respond with exception stack traces
|
||||
in _development_ mode, however for both environments we utilize _methodOverride_ and _bodyDecoder_.
|
||||
|
||||
app.configure(function(){
|
||||
app.use(connect.methodOverride());
|
||||
app.use(connect.bodyDecoder());
|
||||
});
|
||||
|
||||
app.configure('development', function(){
|
||||
app.use(connect.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
app.configure('production', function(){
|
||||
app.use(connect.errorHandler());
|
||||
});
|
||||
|
||||
For internal and arbitrary settings Express provides the _set(key[, val])_, _enable(key)_, _disable(key)_ methods:
|
||||
|
||||
app.configure(function(){
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('views');
|
||||
// => "... views directory ..."
|
||||
|
||||
app.enable('some feature');
|
||||
// same as app.set('some feature', true);
|
||||
|
||||
app.disable('some feature');
|
||||
// same as app.set('some feature', false);
|
||||
});
|
||||
|
||||
To alter the environment we can set the _CONNECT_ENV_ environment variable,
|
||||
or more specifically _EXPRESS_ENV_, for example:
|
||||
|
||||
$ EXPRESS_ENV=production node app.js
|
||||
|
||||
### Settings
|
||||
|
||||
Express supports the following settings out of the box:
|
||||
|
||||
* _env_ Application environment set internally, use _app.set('env')_ on _Server#listen()_
|
||||
* _home_ Application base path used with _res.redirect()_, when mounted defaults
|
||||
to _Server#route_, otherwise "/". Assigned on _Server#listen()_.
|
||||
* _views_ Root views directory defaulting to **CWD/views**
|
||||
* _view engine_ Default view engine name for views rendered without extensions
|
||||
* _reload views_ Reloads altered views, by default watches for _mtime_ changes with
|
||||
with a 5 minute interval. Example: _app.set('reload views', 60000);_
|
||||
|
||||
### Routing
|
||||
|
||||
Express utilizes the HTTP verbs to provide a meaningful, expressive routing API.
|
||||
For example we may want to render a user's account for the path _/user/12_, this
|
||||
can be done by defining the route below. The values associated to the named placeholders,
|
||||
are passed as the _third_ argument, which here we name _params_.
|
||||
|
||||
app.get('/user/:id', function(req, res, params){
|
||||
res.send('user ' + params.id);
|
||||
});
|
||||
|
||||
A route is simple a string which is compiled to a _RegExp_ internally. For example
|
||||
when _/user/:id_ is compiled, a simplified version of the regexp may look similar to:
|
||||
|
||||
\/user\/([^\/]+)\/?
|
||||
|
||||
Regular expression literals may also be passed for complex uses. Since capture
|
||||
groups with literal _RegExp_'s are anonymous we can access them directly from the _params_ array.
|
||||
|
||||
app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res, params){
|
||||
res.send(params);
|
||||
});
|
||||
|
||||
Curl requests against the previously defined route:
|
||||
|
||||
$ curl http://dev:3000/user
|
||||
[null,null]
|
||||
$ curl http://dev:3000/users
|
||||
[null,null]
|
||||
$ curl http://dev:3000/users/1
|
||||
["1",null]
|
||||
$ curl http://dev:3000/users/1..15
|
||||
["1","15"]
|
||||
|
||||
Below are some route examples, and the associated paths that they
|
||||
may consume:
|
||||
|
||||
"/user/:id"
|
||||
/user/12
|
||||
|
||||
"/users/:id?"
|
||||
/users/5
|
||||
/users
|
||||
|
||||
"/files/*"
|
||||
/files/jquery.js
|
||||
/files/javascripts/jquery.js
|
||||
|
||||
"/file/*.*"
|
||||
/files/jquery.js
|
||||
/files/javascripts/jquery.js
|
||||
|
||||
"/user/:id/:operation?"
|
||||
/user/1
|
||||
/user/1/edit
|
||||
|
||||
"/products.:format"
|
||||
/products.json
|
||||
/products.xml
|
||||
|
||||
"/products.:format?"
|
||||
/products.json
|
||||
/products.xml
|
||||
/products
|
||||
|
||||
### Passing Route Control
|
||||
|
||||
We may pass control to the next _matching_ route, by calling the _fourth_ parameter,
|
||||
the _next()_ function. When a match cannot be made, control is passed back to Connect.
|
||||
|
||||
app.get('/users/:id?', function(req, res, params){
|
||||
if (params.id) {
|
||||
// do something
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res, params){
|
||||
// do something else
|
||||
});
|
||||
|
||||
### Middleware
|
||||
|
||||
The Express _Plugin_ is no more! middleware via [Connect](http://github.com/extjs/Connect) can be
|
||||
passed to _express.createServer()_ as you would with a regular Connect server. For example:
|
||||
|
||||
var connect = require('connect'),
|
||||
express = require('express');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
connect.bodyDecoder()
|
||||
);
|
||||
|
||||
Alternatively we can _use()_ them which is useful when adding middleware within _configure()_ blocks:
|
||||
|
||||
app.use(connect.logger({ format: ':method :uri' }));
|
||||
|
||||
### Error Handling
|
||||
|
||||
Express provides the _app.error()_ method which receives exceptions thrown within a route,
|
||||
or passed to _next(err)_. Below is an example which serves different pages based on our
|
||||
ad-hoc _NotFound_ exception:
|
||||
|
||||
function NotFound(msg){
|
||||
this.name = 'NotFound';
|
||||
Error.call(this, msg);
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
}
|
||||
|
||||
sys.inherits(NotFound, Error);
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound;
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res){
|
||||
throw new Error('keyboard cat!');
|
||||
});
|
||||
|
||||
We can call _app.error()_ several times as shown below.
|
||||
Here we check for an instanceof _NotFound_ and show the
|
||||
404 page, or we pass on to the next error handler.
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res.render('404.jade');
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
Here we assume all errors as 500 for the simplicity of
|
||||
this demo, however you can choose whatever you like
|
||||
|
||||
app.error(function(err, req, res){
|
||||
res.render('500.jade', {
|
||||
locals: {
|
||||
error: err
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Our apps could also utilize the Connect _errorHandler_ middleware
|
||||
to report on exceptions. For example if we wish to output exceptions
|
||||
in "development" mode to _stderr_ we can use:
|
||||
|
||||
app.use(connect.errorHandler({ dumpExceptions: true }));
|
||||
|
||||
Also during development we may want fancy html pages to show exceptions
|
||||
that are passed or thrown, so we can set _showStack_ to true:
|
||||
|
||||
app.use(connect.errorHandler({ showStack: true, dumpExceptions: true }));
|
||||
|
||||
The _errorHandler_ middleware also responds with _json_ if _Accept: application/json_
|
||||
is present, which is useful for developing apps that rely heavily on client-side JavaScript.
|
||||
|
||||
### View Rendering
|
||||
|
||||
View filenames take the form _NAME_._ENGINE_, where _ENGINE_ is the name
|
||||
of the module that will be required. For example the view _layout.ejs_ will
|
||||
tell the view system to _require('ejs')_, the module being loaded must (currently)
|
||||
export the method _exports.render(str, options)_ to comply with Express, however
|
||||
with will likely be extensible in the future.
|
||||
|
||||
Below is an example using [Haml.js](http://github.com/visionmedia/haml.js) to render _index.html_,
|
||||
and since we do not use _layout: false_ the rendered contents of _index.html_ will be passed as
|
||||
the _body_ local variable in _layout.haml_.
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
|
||||
The new _view engine_ setting allows us to specify our default template engine,
|
||||
so for example when using [Jade](http://github.com/visionmedia/jade) we could set:
|
||||
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
Allowing us to render with:
|
||||
|
||||
res.render('index');
|
||||
|
||||
vs:
|
||||
|
||||
res.render('index.jade');
|
||||
|
||||
When _view engine_ is set, extensions are entirely optional, however we can still
|
||||
mix and match template engines:
|
||||
|
||||
res.render('another-page.ejs');
|
||||
|
||||
### View Partials
|
||||
|
||||
The Express view system has built-in support for partials and collections, which are
|
||||
sort of "mini" views representing a document fragment. For example rather than iterating
|
||||
in a view to display comments, we would use a partial with collection support:
|
||||
|
||||
partial('comment.haml', { collection: comments });
|
||||
|
||||
To make things even less verbose we can assume the extension as _.haml_ when omitted,
|
||||
however if we wished we could use an ejs partial, within a haml view for example.
|
||||
|
||||
partial('comment', { collection: comments });
|
||||
|
||||
And once again even further, when rendering a collection we can simply pass
|
||||
an array, if no other options are desired:
|
||||
|
||||
partial('comments', comments);
|
||||
|
||||
When using the partial collection support a few "magic" variables are provided
|
||||
for free:
|
||||
|
||||
* _firstInCollection_ True if this is the first object
|
||||
* _indexInCollection_ Index of the object in the collection
|
||||
* _lastInCollection _ True if this is the last object
|
||||
|
||||
### Template Engines
|
||||
|
||||
Below are a few template engines commonly used with Express:
|
||||
|
||||
* [Jade](http://github.com/visionmedia/jade) haml.js successor
|
||||
* [Haml](http://github.com/visionmedia/haml.js) indented templates
|
||||
* [EJS](http://github.com/visionmedia/ejs) Embedded JavaScript
|
||||
|
||||
### req.header(key[, defaultValue])
|
||||
|
||||
Get the case-insensitive request header _key_, with optional _defaultValue_:
|
||||
|
||||
req.header('Host');
|
||||
req.header('host');
|
||||
req.header('Accept', '*/*');
|
||||
|
||||
### req.accepts(type)
|
||||
|
||||
Check if the _Accept_ header is present, and includes the given _type_.
|
||||
|
||||
When the _Accept_ header is not present _true_ is returned. Otherwise
|
||||
the given _type_ is matched by an exact match, and then subtypes. You
|
||||
may pass the subtype such as "html" which is then converted internally
|
||||
to "text/html" using the mime lookup table.
|
||||
|
||||
// Accept: text/html
|
||||
req.accepts('html');
|
||||
// => true
|
||||
|
||||
// Accept: text/*; application/json
|
||||
req.accepts('html');
|
||||
req.accepts('text/html');
|
||||
req.accepts('text/plain');
|
||||
req.accepts('application/json');
|
||||
// => true
|
||||
|
||||
req.accepts('image/png');
|
||||
req.accepts('png');
|
||||
// => false
|
||||
|
||||
### req.param(name)
|
||||
|
||||
Return the value of param _name_ when present.
|
||||
|
||||
- Checks route placeholders, ex: /user/:id
|
||||
- Checks query string params, ex: ?id=12
|
||||
- Checks urlencoded body params, ex: id=12
|
||||
|
||||
To utilize urlencoded request bodies, _req.body_
|
||||
should be an object. This can be done by using
|
||||
the _connect.bodyDecoder_ middleware.
|
||||
|
||||
### req.flash(type[, msg])
|
||||
|
||||
Queue flash _msg_ of the given _type_.
|
||||
|
||||
req.flash('info', 'email sent');
|
||||
req.flash('error', 'email delivery failed');
|
||||
req.flash('info', 'email re-sent');
|
||||
// => 2
|
||||
|
||||
req.flash('info');
|
||||
// => ['email sent', 'email re-sent']
|
||||
|
||||
req.flash('info');
|
||||
// => []
|
||||
|
||||
req.flash();
|
||||
// => { error: ['email delivery failed'], info: [] }
|
||||
|
||||
### req.isXMLHttpRequest
|
||||
|
||||
Also aliased as _req.xhr_, this getter checks the _X-Requested-With_ header
|
||||
to see if it was issued by an _XMLHttpRequest_:
|
||||
|
||||
req.xhr
|
||||
req.isXMLHttpRequest
|
||||
|
||||
### res.header(key[, val])
|
||||
|
||||
Get or set the response header _key_.
|
||||
|
||||
res.header('Content-Length');
|
||||
// => undefined
|
||||
|
||||
res.header('Content-Length', 123);
|
||||
// => 123
|
||||
|
||||
res.header('Content-Length');
|
||||
// => 123
|
||||
|
||||
### res.contentType(type)
|
||||
|
||||
Sets the _Content-Type_ response header to the given _type_.
|
||||
|
||||
var filename = 'path/to/image.png';
|
||||
res.contentType(filename);
|
||||
// res.headers['Content-Type'] is now "image/png"
|
||||
|
||||
### res.attachment([filename])
|
||||
|
||||
Sets the _Content-Disposition_ response header to "attachment", with optional _filename_.
|
||||
|
||||
res.attachment('path/to/my/image.png');
|
||||
|
||||
### res.sendfile(path)
|
||||
|
||||
Used by `res.download()` to transfer an arbitrary file.
|
||||
|
||||
res.sendfile('path/to/my.file');
|
||||
|
||||
This is _not_ a substitution for Connect's _staticProvider_ middleware, it does not
|
||||
support HTTP caching, and does not perform any security checks. This method is utilized
|
||||
by _res.download()_ to transfer static files, and allows you do to so from outside of
|
||||
the public directory, so suitable security checks should be applied.
|
||||
|
||||
### res.download(file[, filename])
|
||||
|
||||
Transfer the given _file_ as an attachment with optional alternative _filename_.
|
||||
|
||||
res.download('path/to/image.png');
|
||||
res.download('path/to/image.png', 'foo.png');
|
||||
|
||||
This is equivalent to:
|
||||
|
||||
res.attachment(file);
|
||||
res.sendfile(file);
|
||||
|
||||
### res.send(body|status[, headers|status[, status]])
|
||||
|
||||
The `res.send()` method is a high level response utility allowing you to pass
|
||||
objects to respond with json, strings for html, arbitrary _Buffer_s or numbers for status
|
||||
code based responses. The following are all valid uses:
|
||||
|
||||
res.send(new Buffer('wahoo'));
|
||||
res.send({ some: 'json' });
|
||||
res.send('<p>some html</p>');
|
||||
res.send('Sorry, cant find that', 404);
|
||||
res.send('text', { 'Content-Type': 'text/plain' }, 201);
|
||||
res.send(404);
|
||||
|
||||
By default the _Content-Type_ response header is set, however if explicitly
|
||||
assigned through `res.send()` or previously with `res.header()` or `res.contentType()`
|
||||
it will not be set again.
|
||||
|
||||
### res.redirect(url[, status])
|
||||
|
||||
Redirect to the given _url_ with a default response _status_ of 302.
|
||||
|
||||
res.redirect('/', 301);
|
||||
res.redirect('/account');
|
||||
res.redirect('http://google.com');
|
||||
res.redirect('home');
|
||||
res.redirect('back');
|
||||
|
||||
Express supports "redirect mapping", which by default provides _home_, and _back_.
|
||||
The _back_ map checks the _Referrer_ and _Referer_ headers, while _home_ utilizes
|
||||
the "home" setting and defaults to "/".
|
||||
|
||||
### res.render(view[, options[, fn]])
|
||||
|
||||
Render _view_ with the given _options_ and optional callback _fn_.
|
||||
When a callback function is given a response will _not_ be made
|
||||
automatically, however otherwise a response of _200_ and _text/html_ is given.
|
||||
|
||||
Most engines accept one or more of the following options,
|
||||
both [haml](http://github.com/visionmedia/haml.js) and [jade](http://github.com/visionmedia/jade) accept all:
|
||||
|
||||
- _context|scope_ Template evaluation context (_this_)
|
||||
- _locals_ Object containing local variables
|
||||
- _cache_ Cache intermediate JavaScript in memory (the default in _production_ mode)
|
||||
- _debug_ Output debugging information
|
||||
|
||||
### res.partial(view[, options])
|
||||
|
||||
Render _view_ partial with the given _options_. This method is always available
|
||||
to the view as a local variable.
|
||||
|
||||
- _as_ Variable name for each _collection_ value, defaults to the view name.
|
||||
* as: 'something' will add the _something_ local variable
|
||||
* as: this will use the collection value as the template context
|
||||
* as: global will merge the collection value's properties with _locals_
|
||||
|
||||
- _collection_ Array of objects, the name is derived from the view name itself.
|
||||
For example _video.html_ will have a object _video_ available to it.
|
||||
|
||||
The following are equivalent, and the name of collection value when passed
|
||||
to the partial will be _movie_ as derived from the name.
|
||||
|
||||
partial('movie.jade', { collection: movies });
|
||||
partial('movie.jade', movies);
|
||||
partial('movie', movies);
|
||||
// In view: movie.director
|
||||
|
||||
To change the local from _movie_ to _video_ we can use the "as" option:
|
||||
|
||||
partial('movie', { collection: movies, as: 'video' });
|
||||
// In view: video.director
|
||||
|
||||
Also we can make our movie the value of _this_ within our view so that instead
|
||||
of _movie.director_ we could use _this.director_.
|
||||
|
||||
partial('movie', { collection: movies, as: this });
|
||||
// In view: this.director
|
||||
|
||||
Another alternative is to "explode" the properties of the collection item into
|
||||
pseudo globals (local variables) by using _as: global_, which again is syntactic sugar:
|
||||
|
||||
partials('movie', { collection: movies, as: global });
|
||||
// In view: director
|
||||
|
||||
### app.set(name[, val])
|
||||
|
||||
Apply an application level setting _name_ to _val_, or
|
||||
get the value of _name_ when _val_ is not present:
|
||||
|
||||
app.set('reload views', 200);
|
||||
app.set('reload views');
|
||||
// => 200
|
||||
|
||||
### app.enable(name)
|
||||
|
||||
Enable the given setting _name_:
|
||||
|
||||
app.enable('some arbitrary setting');
|
||||
app.set('some arbitrary setting');
|
||||
// => true
|
||||
|
||||
### app.disable(name)
|
||||
|
||||
Disable the given setting _name_:
|
||||
|
||||
app.disable('some setting');
|
||||
app.set('some setting');
|
||||
// => false
|
||||
|
||||
### app.configure(env|function[, function])
|
||||
|
||||
Define a callback function for the given _env_ (or all environments) with callback _function_:
|
||||
|
||||
app.configure(function(){
|
||||
// executed for each env
|
||||
});
|
||||
|
||||
app.configure('development', function(){
|
||||
// executed for 'development' only
|
||||
});
|
||||
|
||||
### app.redirect(name, val)
|
||||
|
||||
For use with `res.redirect()` we can map redirects at the application level as shown below:
|
||||
|
||||
app.redirect('google', 'http://google.com');
|
||||
|
||||
Now in a route we may call:
|
||||
|
||||
res.redirect('google');
|
||||
|
||||
We may also map dynamic redirects:
|
||||
|
||||
app.redirect('comments', function(req, res, params){
|
||||
return '/post/' + params.id + '/comments';
|
||||
});
|
||||
|
||||
So now we may do the following, and the redirect will dynamically adjust to
|
||||
the context of the request. If we called this route with _GET /post/12_ our
|
||||
redirect _Location_ would be _/post/12/comments_.
|
||||
|
||||
app.get('/post/:id', function(req, res){
|
||||
res.redirect('comments');
|
||||
});
|
||||
|
||||
### app.error(function)
|
||||
|
||||
Adds an error handler _function_ which will receive the exception as the first parameter as shown below.
|
||||
Note that we may set several error handlers by making several calls to this method, however the handler
|
||||
should call _next(err)_ if it does not wish to deal with the exception:
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
res.send(err.message, 500);
|
||||
});
|
||||
|
||||
### app.helpers(obj)
|
||||
|
||||
Registers static view helpers.
|
||||
|
||||
app.helpers({
|
||||
name: function(first, last){ return first + ', ' + last },
|
||||
firstName: 'tj',
|
||||
lastName: 'holowaychuk'
|
||||
});
|
||||
|
||||
Our view could now utilize the _firstName_ and _lastName_ variables,
|
||||
as well as the _name()_ function exposed.
|
||||
|
||||
<%= name(firstName, lastName) %>
|
||||
|
||||
### app.dynamicHelpers(obj)
|
||||
|
||||
Registers dynamic view helpers. Dynamic view helpers
|
||||
are simply functions which accept _req_, _res_, and _params_, and are
|
||||
evaluated against the _Server_ instance before a view is rendered. The _return value_ of this function
|
||||
becomes the local variable it is associated with.
|
||||
|
||||
app.dynamicHelpers({
|
||||
session: function(req, res, params){
|
||||
return req.session;
|
||||
}
|
||||
});
|
||||
|
||||
All views would now have _session_ available so that session data can be accessed via _session.name_ etc:
|
||||
|
||||
<%= session.name %>
|
||||
|
||||
### app.listen([port[, host]])
|
||||
|
||||
Bind the app server to the given _port_, which defaults to 3000. When _host_ is omitted all
|
||||
connections will be accepted via _INADDR_ANY_.
|
||||
|
||||
app.listen();
|
||||
app.listen(3000);
|
||||
app.listen(3000, 'n.n.n.n');
|
||||
|
||||
The _port_ argument may also be a string representing the path to a unix domain socket:
|
||||
|
||||
app.listen('/tmp/express.sock');
|
||||
|
||||
Then try it out:
|
||||
|
||||
$ telnet /tmp/express.sock
|
||||
GET / HTTP/1.1
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: text/plain
|
||||
Content-Length: 11
|
||||
|
||||
Hello World
|
||||
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 108 KiB |
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 7.0 KiB |
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 7.2 KiB |
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 143 B |
@@ -0,0 +1,97 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "INDEX" "" "July 2010" "" ""
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var app = express\.createServer();
|
||||
|
||||
app\.get(\'/\', function(req, res){
|
||||
res\.send(\'Hello World\');
|
||||
});
|
||||
|
||||
app\.listen(3000);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SH "Features"
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Robust routing
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Redirection helpers
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Dynamic view helpers
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Content negotiation
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Focus on high performance
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View rendering and partials support
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Environment based configuration
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Session based flash notifications
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Built on Connect \fIhttp://github\.com/senchalabs/connect\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Executable \fIexecutable\.html\fR for generating applications quickly
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SH "Contributors"
|
||||
The following are the major contributors of Express (in no specific order)\.
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
TJ Holowaychuk (visionmedia \fIhttp://github\.com/visionmedia\fR)
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Ciaran Jessup (ciaranj \fIhttp://github\.com/ciaranj\fR)
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Aaron Heckmann (aheckmann \fIhttp://github\.com/aheckmann\fR)
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Guillermo Rauch (guille \fIhttp://github\.com/guille\fR)
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SH "More Information"
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Google Group \fIhttp://groups\.google\.com/group/express\-js\fR for discussion
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Follow tjholowaychuk \fIhttp://twitter\.com/tjholowaychuk\fR on twitter for updates
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
Annotated source documentation \fIapi\.html\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View the Connect \fIhttp://github\.com/senchalabs/connect\fR repo for middleware usage
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View the Connect Wiki \fIhttp://wiki\.github\.com/senchalabs/connect/\fR for contrib middleware
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View the examples \fIhttp://github\.com/visionmedia/express/tree/master/examples/\fR
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
View the source \fIhttp://github\.com/visionmedia/express\fR
|
||||
.
|
||||
.IP "" 0
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
var done;
|
||||
$(document).scroll(function(event){
|
||||
if (!done) {
|
||||
$('#toc').animate({
|
||||
top: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<pre><code>var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
</code></pre>
|
||||
|
||||
<h2 id="Features">Features</h2>
|
||||
|
||||
<ul>
|
||||
<li>Robust routing</li>
|
||||
<li>Redirection helpers</li>
|
||||
<li>Dynamic view helpers</li>
|
||||
<li>Content negotiation</li>
|
||||
<li>Focus on high performance</li>
|
||||
<li>View rendering and partials support</li>
|
||||
<li>Environment based configuration</li>
|
||||
<li>Session based flash notifications</li>
|
||||
<li>Built on <a href="http://github.com/senchalabs/connect">Connect</a></li>
|
||||
<li><a href="executable.html">Executable</a> for generating applications quickly</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="Contributors">Contributors</h2>
|
||||
|
||||
<p>The following are the major contributors of Express (in no specific order).</p>
|
||||
|
||||
<ul>
|
||||
<li>TJ Holowaychuk (<a href="http://github.com/visionmedia">visionmedia</a>)</li>
|
||||
<li>Ciaran Jessup (<a href="http://github.com/ciaranj">ciaranj</a>)</li>
|
||||
<li>Aaron Heckmann (<a href="http://github.com/aheckmann">aheckmann</a>)</li>
|
||||
<li>Guillermo Rauch (<a href="http://github.com/guille">guille</a>)</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="More-Information">More Information</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://groups.google.com/group/express-js">Google Group</a> for discussion</li>
|
||||
<li>Follow <a href="http://twitter.com/tjholowaychuk">tjholowaychuk</a> on twitter for updates</li>
|
||||
<li>Annotated source <a href="api.html">documentation</a></li>
|
||||
<li>View the <a href="http://github.com/senchalabs/connect">Connect</a> repo for middleware usage</li>
|
||||
<li>View the <a href="http://wiki.github.com/senchalabs/connect/">Connect Wiki</a> for contrib middleware</li>
|
||||
<li>View the <a href="http://github.com/visionmedia/express/tree/master/examples/">examples</a></li>
|
||||
<li>View the <a href="http://github.com/visionmedia/express">source</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
## Features
|
||||
|
||||
* Robust routing
|
||||
* Redirection helpers
|
||||
* Dynamic view helpers
|
||||
* Content negotiation
|
||||
* Focus on high performance
|
||||
* View rendering and partials support
|
||||
* Environment based configuration
|
||||
* Session based flash notifications
|
||||
* Built on [Connect](http://github.com/senchalabs/connect)
|
||||
* [Executable](executable.html) for generating applications quickly
|
||||
|
||||
## Contributors
|
||||
|
||||
The following are the major contributors of Express (in no specific order).
|
||||
|
||||
* TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
|
||||
* Ciaran Jessup ([ciaranj](http://github.com/ciaranj))
|
||||
* Aaron Heckmann ([aheckmann](http://github.com/aheckmann))
|
||||
* Guillermo Rauch ([guille](http://github.com/guille))
|
||||
|
||||
## More Information
|
||||
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* Annotated source [documentation](api.html)
|
||||
* View the [Connect](http://github.com/senchalabs/connect) repo for middleware usage
|
||||
* View the [Connect Wiki](http://wiki.github.com/senchalabs/connect/) for contrib middleware
|
||||
* View the [examples](http://github.com/visionmedia/express/tree/master/examples/)
|
||||
* View the [source](http://github.com/visionmedia/express)
|
||||
@@ -0,0 +1,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,192 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
var done;
|
||||
$(document).scroll(function(event){
|
||||
if (!done) {
|
||||
$('#toc').animate({
|
||||
top: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,347 @@
|
||||
.\" generated with Ronn/v0.6.6
|
||||
.\" http://github.com/rtomayko/ronn/
|
||||
.
|
||||
.TH "MIGRATE" "" "July 2010" "" ""
|
||||
.
|
||||
.SS "Built On Connect"
|
||||
Express 1\.x is written to run on\-top of the Connect \fIhttp://extjs\.github\.com/Connect\fR middlware framework, thus the \fIPlugin\fR has been replaced by Connect\'s middleware\. By abstracting our middleware to Connect we allow additional community frameworks to develop robust, high\-level frameworks using the same technologies as Express\.
|
||||
.
|
||||
.SS "Creating Applications"
|
||||
Previously due to legacy code implemented in the early days of node, Express unfortunately had some globals\. The DSL would previously be accessed as shown below:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
require(\'express\');
|
||||
|
||||
configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
get(\'/\', function(){
|
||||
return \'hello world\';
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Now we utilize the CommonJS module system appropriately, and introduce \fIexpress\.createServer()\fR which accepts the same arguments as \fIhttp\.createServer()\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var express = require(\'express\'),
|
||||
app = express\.createServer();
|
||||
|
||||
app\.configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
app\.get(\'/\', function(req, res){
|
||||
res\.send(\'hello world\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Express 1\.x does \fInot\fR currently allow returning of a string\.
|
||||
.
|
||||
.SS "Plugins vs Middleware"
|
||||
Previously Express was bundled with plugins, which were essentially what are now Connect middleware\. Previously plugins would be utilized in a manor similar to below:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
use(Logger);
|
||||
use(MethodOverride);
|
||||
use(Cookie);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Which we can now \fIuse()\fR within our app, or pass to the \fIexpress\.createServer()\fR method:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var connect = require(\'connect\');
|
||||
|
||||
var app = express\.createServer(
|
||||
connect\.logger(),
|
||||
connect\.methodOverride(),
|
||||
connect\.cookieDecoder()
|
||||
);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
or:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
var connect = require(\'connect\');
|
||||
var app = express\.createServer();
|
||||
|
||||
app\.use(connect\.logger());
|
||||
app\.use(connect\.methodOverride());
|
||||
app\.use(connect\.cookieDecoder());
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
For documentation on creating Connect middleware visit Middleware Authoring \fIhttp://extjs\.github\.com/Connect/#Middleware\-Authoring\fR\.
|
||||
.
|
||||
.SS "Running Applications"
|
||||
Previously a global function \fIrun()\fR, was available:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
run();
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
The new \fIexpress\.Server\fR has the same API as \fIhttp\.Server\fR, so we can do things like:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.listen();
|
||||
app\.listen(3000);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Route Parameters"
|
||||
Previously we could use \fIthis\.param()\fR to attempt fetching a route, query string, or request body parameter:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
get(\'/user/:id\', function(){
|
||||
this\.param(\'id\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Polymorphic parameter access can be done using \fBreq\.param()\fR:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/user/:id\', function(req, res){
|
||||
req\.param(\'id\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Route parameters are also passed as the third argument:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/user/:id\', function(req, res, params){
|
||||
params\.id;
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Passing Route Control"
|
||||
Old express had a weak notion of route passing, which did not support async, and was never properly implemented for practical use:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
get(\'/\', function(){
|
||||
this\.pass(\'/foobar\');
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Now Express has access to Connect\'s \fInext()\fR function, which is passed as the fourth and final argument\. Calling \fInext()\fR will pass control to the next \fImatching route\fR, or continue down the stack of Connect middleware\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/user/:id?\', function(req, res, params, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app\.get(\'/user\', function(){
|
||||
// \.\.\. respond
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "View Rendering"
|
||||
View filenames no longer take the form \fINAME\fR\.\fITYPE\fR\.\fIENGINE\fR, the \fIContent\-Type\fR can be set via \fIres\.contentType()\fR or \fIres\.header()\fR\. For example what was previously \fIlayout\.html\.haml\fR, should now be \fIlayout\.haml\fR\.
|
||||
.
|
||||
.P
|
||||
Previously a view render looked something like this:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
get(\'/\', function(){
|
||||
this\.render(\'index\.html\.haml\', {
|
||||
locals: { title: \'My Site\' }
|
||||
});
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
We now have \fIres\.render()\fR, however the options passed to haml \fIhttp://github\.com/visionmedia/haml\.js\fR, jade \fIhttp://github\.com/visionmedia/jade\fR, and others remain the same\.
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
app\.get(\'/\', function(req, res){
|
||||
res\.render(\'index\.haml\', {
|
||||
locals: { title: \'My Site\' }
|
||||
});
|
||||
});
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Previously rendering of a collection via \fIpartial()\fR would look something like this:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
this\.partial(\'comment\.html\.haml\', { collection: comments });
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
Although this worked just fine, it was generally to verbose, the similar but new API looks like this, as \fIpartial()\fR is \fIalways\fR passed as a local variable:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comment\.haml\', { collection: comments });
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
To make things even less verbose we can assume the extension when omitted:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comment\', { collection: comments });
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
And once again even further, when rendering a collection we can simply pass an array, if no other options are desired:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
partial(\'comments\', comments);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "Redirecting"
|
||||
Previously you would
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
this\.redirect(\'/somewhere\');
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.P
|
||||
However you would now:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
res\.redirect(\'/somewhere\');
|
||||
res\.redirect(\'/somewhere\', 301);
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SS "HTTP Client"
|
||||
Previously Express provided a high level http client, this library is no more as it does not belong in Express, however it may be resurrected as a separate module\.
|
||||
.
|
||||
.SS "Core Extensions"
|
||||
Express is no longer dependent on the JavaScript Extensions \fIhttp://github\.com/visionmedia/ext\.js\fR library, so those of you using the methods provided by it such as \fBObject\.merge(a, b)\fR will need to roll your own, or install the module via:
|
||||
.
|
||||
.IP "" 4
|
||||
.
|
||||
.nf
|
||||
|
||||
$ npm install ext
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.IP "" 0
|
||||
|
||||
@@ -0,0 +1,411 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
var done;
|
||||
$(document).scroll(function(event){
|
||||
if (!done) {
|
||||
$('#toc').animate({
|
||||
top: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
#header {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
padding: 12px 0;
|
||||
text-indent: 40px;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(0,0,0,0.7);
|
||||
border-bottom: 1px solid rgba(0,0,0,0.7);
|
||||
background: rgba(255,255,255,0.1) url(http://www.sencha.com/favicon.ico) no-repeat 15px 50%;
|
||||
text-align: left;
|
||||
color: #fff;
|
||||
}
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
margin-bottom: 30px;
|
||||
color: rgba(255,255,255,0.7); }
|
||||
html {
|
||||
background: #1c1c1c url(images/bg.tile.jpg); }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding-bottom: 30px;
|
||||
font: 14px/1.4 "Helvetica Neue", "Lucida Grande", "Arial";
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
-moz-text-stroke: 1px rgba(0, 0, 0, 0.1);
|
||||
background: url(images/bg.jpg) 50% 0 no-repeat;
|
||||
color: #8b8b8b; }
|
||||
|
||||
* {
|
||||
outline: none; }
|
||||
|
||||
em {
|
||||
color: white; }
|
||||
|
||||
a img {
|
||||
border: none !important; }
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, padding, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
a:hover {
|
||||
opacity: 0.8; }
|
||||
|
||||
h1, h2, h3 {
|
||||
margin: 45px 0 0 0;
|
||||
color: white;
|
||||
text-shadow: 1px 2px 2px rgba(0,0,0,0.6); }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
pre {
|
||||
margin: 20px 10px;
|
||||
padding: 25px 20px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border: 1px solid #323232;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px; }
|
||||
|
||||
code {
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; }
|
||||
|
||||
ul {
|
||||
margin: 15px 0;
|
||||
padding: 0 0 0 35px; }
|
||||
ul li {
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
list-style: square; }
|
||||
|
||||
.sect {
|
||||
margin-left: 40px; }
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: 30%;
|
||||
margin-bottom: 30px;
|
||||
width: 194px;
|
||||
height: 51px;
|
||||
background: url(images/logo.png) 0 0 no-repeat;
|
||||
text-indent: -99999px; }
|
||||
#logo:hover {
|
||||
opacity: 0.7; }
|
||||
#logo:active {
|
||||
opacity: 0.3; }
|
||||
|
||||
#ribbon {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2; }
|
||||
|
||||
#wrapper {
|
||||
width: 100%;
|
||||
min-height: 800px;
|
||||
background: url(images/top.png) 0 0 repeat-x; }
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
padding-top: 110px;
|
||||
width: 550px; }
|
||||
|
||||
#toc {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
margin: 0 0 0 15px;
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.2);
|
||||
border-right: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
#toc li {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
#toc li a {
|
||||
font-size: 11px;
|
||||
}
|
||||
#menu {
|
||||
margin-left: 65px;
|
||||
padding: 0;
|
||||
padding-bottom: 30px; }
|
||||
#menu li {
|
||||
display: inline;
|
||||
list-style: none; }
|
||||
#menu li a {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 2px;
|
||||
padding: 3px 15px;
|
||||
background: rgba(0,0,0,0.2);
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-moz-box-shadow: 1px 2px 2px rgba(0,0,0,0.6);
|
||||
-webkit-transition-property: opacity, -webkit-transform, color, background-color, -webkit-box-shadow;
|
||||
-webkit-transition-duration: 0.15s;
|
||||
-webkit-transition-timing-function: ease-out; }
|
||||
#menu li a:hover,
|
||||
#menu li a.active {
|
||||
background: rgba(0,0,0,0.5); }
|
||||
#menu li a:active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0,0,0,0.4); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a href='http://github.com/visionmedia/express'>
|
||||
<img alt='Fork me on GitHub' id='ribbon' src='http://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png' />
|
||||
</a>
|
||||
<div id="header"><strong>Sencha</strong> labs</div>
|
||||
<div id="wrapper">
|
||||
<div id="container">
|
||||
<a href='http://github.com/visionmedia/express' id='logo'>Express</a>
|
||||
<p id="tagline">
|
||||
High performance, high class web development for
|
||||
<a href="http://nodejs.org">Node.js</a>
|
||||
</p>
|
||||
<ul id="menu">
|
||||
<li><a href="index.html">Home</a></li>
|
||||
<li><a href="guide.html">Guide</a></li>
|
||||
<li><a href="contrib.html">Contributing</a></li>
|
||||
<li><a href="migrate.html">1.x Migration</a></li>
|
||||
</ul>
|
||||
<div class='mp'>
|
||||
<h3 id="Built-On-Connect">Built On Connect</h3>
|
||||
|
||||
<p>Express 1.x is written to run on-top of the <a href="http://extjs.github.com/Connect">Connect</a> middlware
|
||||
framework, thus the <em>Plugin</em> has been replaced by Connect's middleware. By abstracting our middleware
|
||||
to Connect we allow additional community frameworks to develop robust, high-level frameworks using
|
||||
the same technologies as Express.</p>
|
||||
|
||||
<h3 id="Creating-Applications">Creating Applications</h3>
|
||||
|
||||
<p>Previously due to legacy code implemented in the early days of node,
|
||||
Express unfortunately had some globals. The DSL would previously be
|
||||
accessed as shown below:</p>
|
||||
|
||||
<pre><code>require('express');
|
||||
|
||||
configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
get('/', function(){
|
||||
return 'hello world';
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Now we utilize the CommonJS module system appropriately, and
|
||||
introduce <em>express.createServer()</em> which accepts the same arguments
|
||||
as <em>http.createServer()</em>:</p>
|
||||
|
||||
<pre><code>var express = require('express'),
|
||||
app = express.createServer();
|
||||
|
||||
app.configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('hello world');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Express 1.x does <em>not</em> currently allow returning of a string.</p>
|
||||
|
||||
<h3 id="Plugins-vs-Middleware">Plugins vs Middleware</h3>
|
||||
|
||||
<p>Previously Express was bundled with plugins, which were essentially what
|
||||
are now Connect middleware. Previously plugins would be utilized in a manor
|
||||
similar to below:</p>
|
||||
|
||||
<pre><code>use(Logger);
|
||||
use(MethodOverride);
|
||||
use(Cookie);
|
||||
</code></pre>
|
||||
|
||||
<p>Which we can now <em>use()</em> within our app, or pass to the <em>express.createServer()</em> method:</p>
|
||||
|
||||
<pre><code>var connect = require('connect');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
connect.methodOverride(),
|
||||
connect.cookieDecoder()
|
||||
);
|
||||
</code></pre>
|
||||
|
||||
<p>or:</p>
|
||||
|
||||
<pre><code>var connect = require('connect');
|
||||
var app = express.createServer();
|
||||
|
||||
app.use(connect.logger());
|
||||
app.use(connect.methodOverride());
|
||||
app.use(connect.cookieDecoder());
|
||||
</code></pre>
|
||||
|
||||
<p>For documentation on creating Connect middleware visit <a href="http://extjs.github.com/Connect/#Middleware-Authoring">Middleware Authoring</a>.</p>
|
||||
|
||||
<h3 id="Running-Applications">Running Applications</h3>
|
||||
|
||||
<p>Previously a global function <em>run()</em>, was available:</p>
|
||||
|
||||
<pre><code>run();
|
||||
</code></pre>
|
||||
|
||||
<p>The new <em>express.Server</em> has the same API as <em>http.Server</em>,
|
||||
so we can do things like:</p>
|
||||
|
||||
<pre><code>app.listen();
|
||||
app.listen(3000);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Route-Parameters">Route Parameters</h3>
|
||||
|
||||
<p>Previously we could use <em>this.param()</em> to attempt
|
||||
fetching a route, query string, or request body parameter:</p>
|
||||
|
||||
<pre><code>get('/user/:id', function(){
|
||||
this.param('id');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Polymorphic parameter access can be done using <code>req.param()</code>:</p>
|
||||
|
||||
<pre><code>app.get('/user/:id', function(req, res){
|
||||
req.param('id');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Route parameters are also passed as the third argument:</p>
|
||||
|
||||
<pre><code>app.get('/user/:id', function(req, res, params){
|
||||
params.id;
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Passing-Route-Control">Passing Route Control</h3>
|
||||
|
||||
<p>Old express had a weak notion of route passing,
|
||||
which did not support async, and was never properly
|
||||
implemented for practical use:</p>
|
||||
|
||||
<pre><code>get('/', function(){
|
||||
this.pass('/foobar');
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Now Express has access to Connect's <em>next()</em> function,
|
||||
which is passed as the fourth and final argument. Calling <em>next()</em> will
|
||||
pass control to the next <em>matching route</em>, or continue down the stack
|
||||
of Connect middleware.</p>
|
||||
|
||||
<pre><code>app.get('/user/:id?', function(req, res, params, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user', function(){
|
||||
// ... respond
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="View-Rendering">View Rendering</h3>
|
||||
|
||||
<p>View filenames no longer take the form <em>Express</em>.<em>TYPE</em>.<em>ENGINE</em>,
|
||||
the <em>Content-Type</em> can be set via <em>res.contentType()</em> or
|
||||
<em>res.header()</em>. For example what was previously <em>layout.html.haml</em>,
|
||||
should now be <em>layout.haml</em>.</p>
|
||||
|
||||
<p>Previously a view render looked something like this:</p>
|
||||
|
||||
<pre><code>get('/', function(){
|
||||
this.render('index.html.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>We now have <em>res.render()</em>, however the options passed to <a href="http://github.com/visionmedia/haml.js">haml</a>, <a href="http://github.com/visionmedia/jade">jade</a>, and others
|
||||
remain the same.</p>
|
||||
|
||||
<pre><code>app.get('/', function(req, res){
|
||||
res.render('index.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>Previously rendering of a collection via <em>partial()</em> would look something like this:</p>
|
||||
|
||||
<pre><code>this.partial('comment.html.haml', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>Although this worked just fine, it was generally to verbose, the similar but new API
|
||||
looks like this, as <em>partial()</em> is <em>always</em> passed as a local variable:</p>
|
||||
|
||||
<pre><code>partial('comment.haml', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>To make things even less verbose we can assume the extension when omitted:</p>
|
||||
|
||||
<pre><code>partial('comment', { collection: comments });
|
||||
</code></pre>
|
||||
|
||||
<p>And once again even further, when rendering a collection we can simply pass
|
||||
an array, if no other options are desired:</p>
|
||||
|
||||
<pre><code>partial('comments', comments);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="Redirecting">Redirecting</h3>
|
||||
|
||||
<p>Previously you would</p>
|
||||
|
||||
<pre><code>this.redirect('/somewhere');
|
||||
</code></pre>
|
||||
|
||||
<p>However you would now:</p>
|
||||
|
||||
<pre><code>res.redirect('/somewhere');
|
||||
res.redirect('/somewhere', 301);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="HTTP-Client">HTTP Client</h3>
|
||||
|
||||
<p>Previously Express provided a high level http client, this library is no more
|
||||
as it does not belong in Express, however it may be resurrected as a separate module.</p>
|
||||
|
||||
<h3 id="Core-Extensions">Core Extensions</h3>
|
||||
|
||||
<p>Express is no longer dependent on the <a href="http://github.com/visionmedia/ext.js">JavaScript Extensions</a> library, so those of you using the methods provided by it such as <code>Object.merge(a, b)</code> will need to
|
||||
roll your own, or install the module via:</p>
|
||||
|
||||
<pre><code>$ npm install ext
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,192 @@
|
||||
|
||||
### Built On Connect
|
||||
|
||||
Express 1.x is written to run on-top of the [Connect](http://extjs.github.com/Connect) middlware
|
||||
framework, thus the _Plugin_ has been replaced by Connect's middleware. By abstracting our middleware
|
||||
to Connect we allow additional community frameworks to develop robust, high-level frameworks using
|
||||
the same technologies as Express.
|
||||
|
||||
### Creating Applications
|
||||
|
||||
Previously due to legacy code implemented in the early days of node,
|
||||
Express unfortunately had some globals. The DSL would previously be
|
||||
accessed as shown below:
|
||||
|
||||
require('express');
|
||||
|
||||
configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
get('/', function(){
|
||||
return 'hello world';
|
||||
});
|
||||
|
||||
Now we utilize the CommonJS module system appropriately, and
|
||||
introduce _express.createServer()_ which accepts the same arguments
|
||||
as _http.createServer()_:
|
||||
|
||||
var express = require('express'),
|
||||
app = express.createServer();
|
||||
|
||||
app.configure(function(){
|
||||
// app configuration
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('hello world');
|
||||
});
|
||||
|
||||
Express 1.x does _not_ currently allow returning of a string.
|
||||
|
||||
### Plugins vs Middleware
|
||||
|
||||
Previously Express was bundled with plugins, which were essentially what
|
||||
are now Connect middleware. Previously plugins would be utilized in a manor
|
||||
similar to below:
|
||||
|
||||
use(Logger);
|
||||
use(MethodOverride);
|
||||
use(Cookie);
|
||||
|
||||
Which we can now _use()_ within our app, or pass to the _express.createServer()_ method:
|
||||
|
||||
var connect = require('connect');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
connect.methodOverride(),
|
||||
connect.cookieDecoder()
|
||||
);
|
||||
|
||||
or:
|
||||
|
||||
var connect = require('connect');
|
||||
var app = express.createServer();
|
||||
|
||||
app.use(connect.logger());
|
||||
app.use(connect.methodOverride());
|
||||
app.use(connect.cookieDecoder());
|
||||
|
||||
For documentation on creating Connect middleware visit [Middleware Authoring](http://extjs.github.com/Connect/#Middleware-Authoring).
|
||||
|
||||
### Running Applications
|
||||
|
||||
Previously a global function _run()_, was available:
|
||||
|
||||
run();
|
||||
|
||||
The new _express.Server_ has the same API as _http.Server_,
|
||||
so we can do things like:
|
||||
|
||||
app.listen();
|
||||
app.listen(3000);
|
||||
|
||||
### Route Parameters
|
||||
|
||||
Previously we could use _this.param()_ to attempt
|
||||
fetching a route, query string, or request body parameter:
|
||||
|
||||
get('/user/:id', function(){
|
||||
this.param('id');
|
||||
});
|
||||
|
||||
Polymorphic parameter access can be done using `req.param()`:
|
||||
|
||||
app.get('/user/:id', function(req, res){
|
||||
req.param('id');
|
||||
});
|
||||
|
||||
Route parameters are also passed as the third argument:
|
||||
|
||||
app.get('/user/:id', function(req, res, params){
|
||||
params.id;
|
||||
});
|
||||
|
||||
### Passing Route Control
|
||||
|
||||
Old express had a weak notion of route passing,
|
||||
which did not support async, and was never properly
|
||||
implemented for practical use:
|
||||
|
||||
get('/', function(){
|
||||
this.pass('/foobar');
|
||||
});
|
||||
|
||||
Now Express has access to Connect's _next()_ function,
|
||||
which is passed as the fourth and final argument. Calling _next()_ will
|
||||
pass control to the next _matching route_, or continue down the stack
|
||||
of Connect middleware.
|
||||
|
||||
app.get('/user/:id?', function(req, res, params, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user', function(){
|
||||
// ... respond
|
||||
});
|
||||
|
||||
### View Rendering
|
||||
|
||||
View filenames no longer take the form _NAME_._TYPE_._ENGINE_,
|
||||
the _Content-Type_ can be set via _res.contentType()_ or
|
||||
_res.header()_. For example what was previously _layout.html.haml_,
|
||||
should now be _layout.haml_.
|
||||
|
||||
Previously a view render looked something like this:
|
||||
|
||||
get('/', function(){
|
||||
this.render('index.html.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
|
||||
We now have _res.render()_, however the options passed to [haml](http://github.com/visionmedia/haml.js), [jade](http://github.com/visionmedia/jade), and others
|
||||
remain the same.
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.haml', {
|
||||
locals: { title: 'My Site' }
|
||||
});
|
||||
});
|
||||
|
||||
Previously rendering of a collection via _partial()_ would look something like this:
|
||||
|
||||
this.partial('comment.html.haml', { collection: comments });
|
||||
|
||||
Although this worked just fine, it was generally to verbose, the similar but new API
|
||||
looks like this, as _partial()_ is _always_ passed as a local variable:
|
||||
|
||||
partial('comment.haml', { collection: comments });
|
||||
|
||||
To make things even less verbose we can assume the extension when omitted:
|
||||
|
||||
partial('comment', { collection: comments });
|
||||
|
||||
And once again even further, when rendering a collection we can simply pass
|
||||
an array, if no other options are desired:
|
||||
|
||||
partial('comments', comments);
|
||||
|
||||
### Redirecting
|
||||
|
||||
Previously you would
|
||||
|
||||
this.redirect('/somewhere');
|
||||
|
||||
However you would now:
|
||||
|
||||
res.redirect('/somewhere');
|
||||
res.redirect('/somewhere', 301);
|
||||
|
||||
### HTTP Client
|
||||
|
||||
Previously Express provided a high level http client, this library is no more
|
||||
as it does not belong in Express, however it may be resurrected as a separate module.
|
||||
|
||||
### Core Extensions
|
||||
|
||||
Express is no longer dependent on the [JavaScript Extensions](http://github.com/visionmedia/ext.js) library, so those of you using the methods provided by it such as `Object.merge(a, b)` will need to
|
||||
roll your own, or install the module via:
|
||||
|
||||
$ npm install ext
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express');
|
||||
|
||||
// Our app IS the exports, this prevents require('./app').app,
|
||||
// instead it is require('./app');
|
||||
var app = module.exports = express.createServer();
|
||||
|
||||
// Illustrates that an app can be broken into
|
||||
// several files, but yet extend the same app
|
||||
require('./main');
|
||||
require('./contact');
|
||||
|
||||
// Illustrates that one app (Server instance) can
|
||||
// be "mounted" to another at the given route.
|
||||
app.use('/blog', require('./blog'));
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../../lib/express'),
|
||||
fs = require('fs');
|
||||
|
||||
// Export our app as the module
|
||||
var app = module.exports = express.createServer();
|
||||
|
||||
// Set views directory
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Load our posts
|
||||
var posts = JSON.parse(fs.readFileSync(__dirname + '/posts.json', 'utf8'));
|
||||
|
||||
// Set our default view engine to "ejs"
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
app.dynamicHelpers({
|
||||
basepath: function(){
|
||||
// "this" is the app, we can
|
||||
// dynamically provide the mounted
|
||||
// route to all templates for url usage
|
||||
return this.route;
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index', {
|
||||
locals: {
|
||||
posts: posts
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/post/:id', function(req, res, params){
|
||||
res.render('post', {
|
||||
locals: {
|
||||
post: posts[params.id]
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{ "id": 0, "title": "Post one", "body": "Just some lame post" },
|
||||
{ "id": 1, "title": "Post two", "body": "Just another lame post" }
|
||||
]
|
||||
@@ -0,0 +1,2 @@
|
||||
<h2>Posts</h2>
|
||||
<%- partial('post', { collection: posts, as: global }) %>
|
||||
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Blog Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Best Blog Ever</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,2 @@
|
||||
<h3><a href="<%= basepath %>/post/<%= id %>"><%= title %></a></h3>
|
||||
<p><%= body %></p>
|
||||
@@ -0,0 +1 @@
|
||||
<%- partial('post', { object: post, as: global }) %>
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
// in ./app.js we did "module.exports", allowing
|
||||
// us to grab the app from the parent module (the one
|
||||
// which required it)
|
||||
var app = module.parent.exports;
|
||||
|
||||
app.get('/contact', function(req, res){
|
||||
res.send('<p>Wahoo contact page</p>');
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
// in ./app.js we did "module.exports", allowing
|
||||
// us to grab the app from the parent module (the one
|
||||
// which required it)
|
||||
var app = module.parent.exports;
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('<p>Visit <a href="/blog">/blog</a>'
|
||||
+ ' or <a href="/contact">/contact</a></p>');
|
||||
});
|
||||
@@ -1,81 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
var fiveMinutes = 300000,
|
||||
oneMinute = 60000
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
use(CommonLogger)
|
||||
use(Cookie)
|
||||
use(Cache, { lifetime: fiveMinutes, reapInterval: oneMinute })
|
||||
use(Session, { lifetime: fiveMinutes, reapInterval: oneMinute })
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
var messages = [],
|
||||
utils = require('express/utils')
|
||||
|
||||
get('/', function(){
|
||||
this.redirect('/chat')
|
||||
})
|
||||
|
||||
get('/chat', function(){
|
||||
this.render('chat.haml.html', {
|
||||
locals: {
|
||||
title: 'Chat',
|
||||
messages: messages,
|
||||
name: this.session.name,
|
||||
usersOnline: Session.store.length()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
post('/chat', function(){
|
||||
this.session.name = this.param('name')
|
||||
messages
|
||||
.push(utils.escape(this.param('name')) + ': ' + utils.escape(this.param('message'))
|
||||
.replace(/(http:\/\/[^\s]+)/g, '<a href="$1" target="express-chat">$1</a>')
|
||||
.replace(/:\)/g, '<img src="http://icons3.iconfinder.netdna-cdn.com/data/icons/ledicons/emoticon_smile.png">'))
|
||||
this.halt(200)
|
||||
})
|
||||
|
||||
get('/chat/messages', function(){
|
||||
var self = this,
|
||||
previousLength = messages.length,
|
||||
timer = setInterval(function(){
|
||||
if (messages.length > previousLength)
|
||||
self.contentType('json'),
|
||||
previousLength = messages.length,
|
||||
self.halt(200, JSON.encode(messages)),
|
||||
clearInterval(timer)
|
||||
}, 100)
|
||||
})
|
||||
|
||||
get('/public/*', function(file){
|
||||
this.sendfile(__dirname + '/public/' + file)
|
||||
})
|
||||
|
||||
get('/*.css', function(file){
|
||||
this.render(file + '.sass.css', { layout: false })
|
||||
})
|
||||
|
||||
get('/error/view', function(){
|
||||
this.render('does.not.exist')
|
||||
})
|
||||
|
||||
get('/error', function(){
|
||||
throw new Error('oh noes!')
|
||||
})
|
||||
|
||||
get('/simple', function(){
|
||||
return 'Hello :)'
|
||||
})
|
||||
|
||||
get('/favicon.ico', function(){
|
||||
this.halt()
|
||||
})
|
||||
|
||||
run()
|
||||
Arquivo binário não exibido.
|
Antes Largura: | Altura: | Tamanho: 5.2 KiB |
@@ -1,28 +0,0 @@
|
||||
|
||||
$(function(){
|
||||
// Send message
|
||||
$('form').submit(function(){
|
||||
var message = $('input[name=message]'),
|
||||
name = $('input[name=name]')
|
||||
if (message.val())
|
||||
$.post('/chat', { name: name.val(), message: message.val() }, function(){
|
||||
message.val('')
|
||||
})
|
||||
else
|
||||
message.css('border', '1px solid red')
|
||||
return false
|
||||
})
|
||||
|
||||
// Longpoll
|
||||
;(function poll(){
|
||||
$.getJSON('/chat/messages', function(messages){
|
||||
$('#messages').empty()
|
||||
$.each(messages, function(i, msg){
|
||||
$('#messages')
|
||||
.append('<li>' + msg + '</li>')
|
||||
.get(0).scrollTop = $('#messages').get(0).scrollHeight
|
||||
})
|
||||
poll()
|
||||
})
|
||||
})()
|
||||
})
|
||||
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1,10 +0,0 @@
|
||||
%h1 Chat
|
||||
%img.bubble{ src: '/public/images/bubble.png' }
|
||||
%ul#messages
|
||||
:each msg in messages
|
||||
%li= msg
|
||||
%form{ method: 'post' }
|
||||
%input{ type: 'hidden', name: '_method', value: 'put' }
|
||||
%input{ type: 'text', name: 'name', value: name || 'guest' }
|
||||
%input{ type: 'text', name: 'message' }
|
||||
%input{ type: 'submit', value: 'Send' }
|
||||
@@ -1,11 +0,0 @@
|
||||
%html
|
||||
%head
|
||||
%title= title
|
||||
%script{ src: '/public/javascripts/jquery.js' }
|
||||
%script{ src: '/public/javascripts/app.js' }
|
||||
%link{ rel: 'stylesheet', href: '/style.css' }
|
||||
%body
|
||||
#wrapper= body
|
||||
#online
|
||||
Online:
|
||||
%strong= usersOnline
|
||||
@@ -1,81 +0,0 @@
|
||||
body
|
||||
:font-family "Helvetica Neue", "Lucida Grande", "Arial"
|
||||
:font-size 13px
|
||||
:text-align center
|
||||
=text-stroke 1px rgba(255, 255, 255, 0.1)
|
||||
:color #555
|
||||
|
||||
h1, h2
|
||||
:margin 0
|
||||
:font-size 22px
|
||||
:color #343434
|
||||
h1
|
||||
:text-shadow 1px 2px 2px #ddd
|
||||
:font-size 60px
|
||||
|
||||
img.bubble
|
||||
:position absolute
|
||||
:top -25px
|
||||
:left 120px
|
||||
|
||||
#wrapper
|
||||
:position relative
|
||||
:margin 100px auto
|
||||
:width 500px
|
||||
:text-align left
|
||||
|
||||
ul
|
||||
:margin 0
|
||||
:padding 0
|
||||
:max-height 300px
|
||||
:overflow-x hidden
|
||||
li
|
||||
:margin 5px 0
|
||||
:padding 3px 8px
|
||||
:list-style none
|
||||
:border 1px solid #eee
|
||||
=border-radius 3px
|
||||
=border-radius 3px
|
||||
li:hover
|
||||
:cursor pointer
|
||||
:color #2E2E2E
|
||||
|
||||
input[type=text]
|
||||
:padding 5px
|
||||
:border 1px solid #ddd
|
||||
:outline none
|
||||
=border-radius 2px
|
||||
input[type=text]:focus
|
||||
:border-color #00C3FF
|
||||
|
||||
input[type=submit]
|
||||
=border-radius 2px
|
||||
=box-shadow 0 1px 2px #ddd
|
||||
:padding 6px 10px
|
||||
:border solid 1px #999
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ddd))
|
||||
:color #333
|
||||
:text-decoration none
|
||||
:cursor pointer
|
||||
:display inline-block
|
||||
:text-align center
|
||||
:text-shadow 0px 1px 1px #fff
|
||||
:line-height 1
|
||||
input[type=submit]:hover
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#E6E4E4))
|
||||
input[type=submit]:active
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#c7c7c7))
|
||||
input[name=name]
|
||||
:width 80px
|
||||
|
||||
a
|
||||
:color #1ABFF1
|
||||
=transition-property padding
|
||||
=transition-duration 0.15s
|
||||
a:hover
|
||||
:padding 0 5px
|
||||
a:hover:before
|
||||
:content 'visit: '
|
||||
|
||||
#online
|
||||
:font-size 12px
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tj', email: 'tj@sencha.com' },
|
||||
{ name: 'ciaran', email: 'ciaranj@gmail.com' },
|
||||
{ name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users.ejs', {
|
||||
locals: {
|
||||
users: users
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Users</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
@@ -0,0 +1,3 @@
|
||||
<ul id="users">
|
||||
<%- partial('user', users) %>
|
||||
</ul>
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// Caught and passed down to the errorHandler middleware
|
||||
throw new Error('something broke!');
|
||||
});
|
||||
|
||||
app.get('/next', function(req, res, params, next){
|
||||
// We can also pass exceptions to next()
|
||||
next(new Error('oh no!'))
|
||||
});
|
||||
|
||||
// The errorHandler middleware in this case will dump exceptions to stderr
|
||||
// as well as show the stack trace in responses, currently handles text/plain,
|
||||
// text/html, and application/json responses to aid in development
|
||||
app.use('/', connect.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect'),
|
||||
sys = require('sys');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Here we use the bodyDecoder middleware
|
||||
// to parse urlencoded request bodies
|
||||
// which populates req.body
|
||||
app.use(connect.bodyDecoder());
|
||||
|
||||
// The methodOverride middleware allows us
|
||||
// to set a hidden input of _method to an arbitrary
|
||||
// HTTP method to support app.put(), app.del() etc
|
||||
app.use(connect.methodOverride());
|
||||
|
||||
// Required by session
|
||||
app.use(connect.cookieDecoder());
|
||||
|
||||
// Required by req.flash() for persistent
|
||||
// notifications
|
||||
app.use(connect.session());
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// get ?name=foo
|
||||
var name = req.param('name') || '';
|
||||
|
||||
// Switch the button label based if we have a name
|
||||
var label = name ? 'Update' : 'Save';
|
||||
|
||||
// Buffer all flash messages.
|
||||
// Typically this would all be done in a template
|
||||
// however for illustration purposes we iterate
|
||||
// here.
|
||||
|
||||
// The messages in req.flash() persist until called,
|
||||
// at which time they are flushed from the session
|
||||
var msgs = '<ul>',
|
||||
flash = req.flash();
|
||||
Object.keys(flash).forEach(function(type){
|
||||
flash[type].forEach(function(msg){
|
||||
msgs += '<li class="' + type + '">' + msg + '</li>';
|
||||
});
|
||||
});
|
||||
msgs += '</ul>';
|
||||
|
||||
// If we have a name, we are updating,
|
||||
// so add the hidden _method input
|
||||
res.send(msgs
|
||||
+ '<form method="post">'
|
||||
+ (name ? '<input type="hidden" value="put" name="_method" />' : '')
|
||||
+ 'Name: <input type="text" name="name" value="' + name + '" />'
|
||||
+ '<input type="submit" value="' + label + '" />'
|
||||
+ '</form>');
|
||||
});
|
||||
|
||||
app.post('/', function(req, res){
|
||||
if (req.body.name) {
|
||||
// Typically here we would create a resource
|
||||
req.flash('info', 'Saved ' + req.body.name);
|
||||
res.redirect('/?name=' + req.body.name);
|
||||
} else {
|
||||
req.flash('error', 'Error: name required');
|
||||
res.redirect('/');
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/', function(req, res){
|
||||
// Typically here we would update a resource
|
||||
req.flash('info', 'Updated ' + req.body.name);
|
||||
res.redirect('/?name=' + req.body.name);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,116 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect'),
|
||||
http = require('http');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Expose our views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
/**
|
||||
* Request github json api `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function request(path, fn){
|
||||
var client = http.createClient(80, 'github.com'),
|
||||
req = client.request('GET', '/api/v2/json' + path, { Host: 'github.com' });
|
||||
req.addListener('response', function(res){
|
||||
res.body = '';
|
||||
res.addListener('data', function(chunk){ res.body += chunk; });
|
||||
res.addListener('end', function(){
|
||||
try {
|
||||
fn(null, JSON.parse(res.body));
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
req.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort repositories by watchers desc.
|
||||
*
|
||||
* @param {Array} repos
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function sort(repos){
|
||||
return repos.sort(function(a, b){
|
||||
if (a.watchers == b.watchers) return 0;
|
||||
if (a.watchers > b.watchers) return -1;
|
||||
if (a.watchers < b.watchers) return 1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tally up total watchers.
|
||||
*
|
||||
* @param {Array} repos
|
||||
* @return {Number}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function totalWatchers(repos) {
|
||||
return repos.reduce(function(sum, repo){
|
||||
return sum + repo.watchers;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default to my user name :)
|
||||
*/
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.redirect('/repos/visionmedia');
|
||||
});
|
||||
|
||||
/**
|
||||
* Display repos.
|
||||
*/
|
||||
|
||||
app.get('/repos/*', function(req, res, params, next){
|
||||
var names = params[0].split('/'),
|
||||
users = [];
|
||||
(function fetchData(name){
|
||||
// We have a user name
|
||||
if (name) {
|
||||
console.log('... fetching %s', name);
|
||||
request('/repos/show/' + name, function(err, user){
|
||||
if (err) {
|
||||
next(err)
|
||||
} else {
|
||||
user.totalWatchers = totalWatchers(user.repositories);
|
||||
user.repos = sort(user.repositories);
|
||||
user.name = name;
|
||||
users.push(user);
|
||||
fetchData(names.shift());
|
||||
}
|
||||
});
|
||||
// No more users
|
||||
} else {
|
||||
console.log('... done');
|
||||
res.render('index.jade', {
|
||||
locals: {
|
||||
users: users
|
||||
}
|
||||
});
|
||||
}
|
||||
})(names.shift());
|
||||
});
|
||||
|
||||
// Serve statics from ./public
|
||||
app.use(connect.staticProvider(__dirname + '/public'));
|
||||
|
||||
// Listen on port 3000
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,19 @@
|
||||
body {
|
||||
padding: 30px 50px;
|
||||
font: 12px/1.4 "Lucida Grande", "Helvetica Nueue", Arial, sans-serif;
|
||||
}
|
||||
a {
|
||||
color: #00AAFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.user {
|
||||
margin: 0 10px;
|
||||
float: left;
|
||||
width: 30%;
|
||||
}
|
||||
table td:nth-child(2) {
|
||||
padding: 0 5px;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
- each user in users
|
||||
.user
|
||||
h2= user.name
|
||||
p.summary
|
||||
| <a href="http://github.com/#{user.name}">#{user.name}</a> has
|
||||
| <strong>#{user.repos.length}</strong> repositories
|
||||
| with a total of <strong>#{user.totalWatchers}</strong> watchers.
|
||||
table#repos!= partial('repo', user.repos)
|
||||
@@ -0,0 +1,7 @@
|
||||
!!!
|
||||
html
|
||||
head
|
||||
title Github Example
|
||||
link(rel="stylesheet", href="/style.css")
|
||||
body
|
||||
#container!= body
|
||||
@@ -0,0 +1,5 @@
|
||||
tr.repo
|
||||
td.name
|
||||
a(href: repo.homepage || repo.url)= repo.name
|
||||
td.watchers
|
||||
= repo.watchers
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect');
|
||||
|
||||
// Path to our public directory
|
||||
|
||||
var pub = __dirname + '/public';
|
||||
|
||||
// Auto-compile sass to css with "compiler"
|
||||
// and then serve with connect's staticProvider
|
||||
|
||||
var app = express.createServer(
|
||||
connect.compiler({ src: pub, enable: ['sass'] }),
|
||||
connect.staticProvider(pub)
|
||||
);
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Enable auto-reloading of view contents when changed
|
||||
// with an interval of 1000 milliseconds. Start the app
|
||||
// with $ node examples/jade/app.js
|
||||
// then alter some views :)
|
||||
|
||||
app.set('reload views', 1000);
|
||||
// or app.enable('reload views'); for defaults
|
||||
|
||||
// Set our default template engine to "jade"
|
||||
// which prevents the need for extensions (although you can still mix and match)
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tj', email: 'tj@sencha.com' },
|
||||
{ name: 'ciaran', email: 'ciaranj@gmail.com' },
|
||||
{ name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users', {
|
||||
locals: {
|
||||
users: users
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,3 @@
|
||||
body {
|
||||
padding: 50px 80px;
|
||||
font: 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif;}
|
||||
@@ -0,0 +1,3 @@
|
||||
body
|
||||
:padding 50px 80px
|
||||
:font 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif
|
||||
@@ -0,0 +1,6 @@
|
||||
!!!
|
||||
html
|
||||
head
|
||||
title Jade Example
|
||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||
body!= body
|
||||
@@ -0,0 +1,3 @@
|
||||
.user
|
||||
h2= user.name
|
||||
.email= user.email
|
||||
@@ -0,0 +1,3 @@
|
||||
- if (users.length)
|
||||
h1 Users
|
||||
#users!= partial('user', users)
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
form = require('./../../support/connect-form'),
|
||||
connect = require('connect'),
|
||||
sys = require('sys');
|
||||
|
||||
var app = express.createServer(
|
||||
// connect-form (http://github.com/visionmedia/connect-form)
|
||||
// middleware uses the formidable middleware to parse urlencoded
|
||||
// and multipart form data
|
||||
form()
|
||||
);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('<form method="post" enctype="form-data/multipart">'
|
||||
+ '<p>Image: <input type="file" name="image" /></p>'
|
||||
+ '<p><input type="submit" value="Upload" /></p>'
|
||||
+ '</form>');
|
||||
});
|
||||
|
||||
app.post('/', function(req, res, params, next){
|
||||
|
||||
// connect-form adds the req.form object
|
||||
// we can (optionally) define onComplete, passing
|
||||
// the exception (if any) fields parsed, and files parsed
|
||||
req.form.complete(function(err, fields, files){
|
||||
if (err) {
|
||||
next(err);
|
||||
} else {
|
||||
sys.puts('\nuploaded ' + files.image.filename);
|
||||
res.redirect('back');
|
||||
}
|
||||
});
|
||||
|
||||
// We can add listeners for several form
|
||||
// events such as "progress"
|
||||
req.form.addListener('progress', function(bytesReceived, bytesExpected){
|
||||
var percent = (bytesReceived / bytesExpected * 100) | 0;
|
||||
sys.print('Uploading: %' + percent + '\r');
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express');
|
||||
|
||||
var app = express.createServer(),
|
||||
sys = require('sys');
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Provide our app with the notion of NotFound exceptions
|
||||
|
||||
function NotFound(msg){
|
||||
this.name = 'NotFound';
|
||||
Error.call(this, msg);
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
}
|
||||
|
||||
sys.inherits(NotFound, Error);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.jade');
|
||||
});
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound;
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res){
|
||||
throw new Error('keyboard cat!');
|
||||
});
|
||||
|
||||
// We can call app.error() several times as shown below.
|
||||
// Here we check for an instanceof NotFound and show the
|
||||
// 404 page, or we pass on to the next error handler.
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res.render('404.jade');
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// Here we assume all errors as 500 for the simplicity of
|
||||
// this demo, however you can choose whatever you like
|
||||
|
||||
app.error(function(err, req, res){
|
||||
res.render('500.jade', {
|
||||
locals: {
|
||||
error: err
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1 @@
|
||||
h2 Page Not Found
|
||||
@@ -0,0 +1,2 @@
|
||||
h1 Error: #{error.message}
|
||||
pre= error.stack
|
||||
@@ -0,0 +1,8 @@
|
||||
h2 Pages Example
|
||||
ul
|
||||
li
|
||||
| visit
|
||||
a(href="/500") 500
|
||||
li
|
||||
| visit
|
||||
a(href="/404") 404
|
||||
@@ -0,0 +1,6 @@
|
||||
html
|
||||
head
|
||||
title Custom Pages Example
|
||||
body
|
||||
h1 My Site
|
||||
!= body
|
||||
@@ -0,0 +1,73 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Ad-hoc example resource method
|
||||
|
||||
app.resource = function(path, obj) {
|
||||
this.get(path, obj.index);
|
||||
this.get(path + '/:a..:b', function(req, res, params){
|
||||
var a = parseInt(params.a, 10),
|
||||
b = parseInt(params.b, 10);
|
||||
obj.range(req, res, a, b);
|
||||
});
|
||||
this.get(path + '/:id', obj.show);
|
||||
this.del(path + '/:id', obj.destroy);
|
||||
};
|
||||
|
||||
// Fake records
|
||||
|
||||
var users = [
|
||||
{ name: 'tj' },
|
||||
{ name: 'ciaran' },
|
||||
{ name: 'aaron' },
|
||||
{ name: 'guillermo' },
|
||||
{ name: 'simon' },
|
||||
{ name: 'tobi' }
|
||||
];
|
||||
|
||||
// Fake model
|
||||
|
||||
var User = {
|
||||
index: function(req, res){
|
||||
res.send(users);
|
||||
},
|
||||
show: function(req, res, params){
|
||||
res.send(users[params.id] || { error: 'Cannot find user' });
|
||||
},
|
||||
destroy: function(req, res, params){
|
||||
var destroyed = params.id in users;
|
||||
delete users[params.id];
|
||||
res.send(destroyed ? 'destroyed' : 'Cannot find user');
|
||||
},
|
||||
range: function(req, res, a, b){
|
||||
res.send(users.slice(a, b));
|
||||
}
|
||||
};
|
||||
|
||||
// curl http://localhost:3000/users -- responds with all users
|
||||
// curl http://localhost:3000/users/1 -- responds with user 1
|
||||
// curl http://localhost:3000/users/4 -- responds with error
|
||||
// curl http://localhost:3000/users/1..3 -- responds with several users
|
||||
// curl -X DELETE http://localhost:3000/users/1 -- deletes the user
|
||||
|
||||
app.resource('/users', User);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send([
|
||||
'<h1>Examples:</h1> <ul>',
|
||||
'<li>GET /users</li>',
|
||||
'<li>GET /users/1</li>',
|
||||
'<li>GET /users/3</li>',
|
||||
'<li>GET /users/1..3</li>',
|
||||
'<li>DELETE /users/4</li>',
|
||||
'</ul>',
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./../../lib/express'),
|
||||
connect = require('connect');
|
||||
|
||||
var app = express.createServer(
|
||||
connect.logger(),
|
||||
|
||||
// Required by session() middleware
|
||||
connect.cookieDecoder(),
|
||||
|
||||
// Populates:
|
||||
// - req.session
|
||||
// - req.sessionStore
|
||||
// - req.sessionHash (the SID fingerprint)
|
||||
connect.session()
|
||||
);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
var body = '';
|
||||
if (req.session.views) {
|
||||
++req.session.views;
|
||||
} else {
|
||||
req.session.views = 1;
|
||||
body += '<p>First time visiting? view this page in several browsers :)</p>';
|
||||
}
|
||||
res.send(body + '<p>viewed <strong>' + req.session.views + '</strong> times.</p>');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
use(CommonLogger)
|
||||
use(Cookie)
|
||||
use(Session)
|
||||
use(Flash)
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.redirect('/upload')
|
||||
})
|
||||
|
||||
get('/upload', function(){
|
||||
this.render('upload.haml.html', {
|
||||
locals: {
|
||||
flashes: this.flash('info')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
post('/upload', function(){
|
||||
this.param('images').each(function(image){
|
||||
puts(image.filename + ' -> ' + image.tempfile)
|
||||
this.flash('info', 'Uploaded ' + image.filename)
|
||||
}, this)
|
||||
this.redirect('/upload')
|
||||
})
|
||||
|
||||
get('/public/*', function(file){
|
||||
this.sendfile(__dirname + '/public/' + file)
|
||||
})
|
||||
|
||||
get('/*.css', function(file){
|
||||
this.render(file + '.sass.css', { layout: false })
|
||||
})
|
||||
|
||||
run()
|
||||
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1,14 +0,0 @@
|
||||
%html
|
||||
%head
|
||||
%title Upload
|
||||
%script{ src: '/public/javascripts/jquery.js' }
|
||||
%script{ src: '/public/javascripts/app.js' }
|
||||
%link{ rel: 'stylesheet', href: '/style.css' }
|
||||
%body
|
||||
#wrapper
|
||||
%h1 Upload
|
||||
:if flashes
|
||||
%ul.messages.info
|
||||
:each msg in flashes
|
||||
%li= msg
|
||||
.body= body
|
||||
@@ -1,68 +0,0 @@
|
||||
body
|
||||
:font-family "Helvetica Neue", "Lucida Grande", "Arial"
|
||||
:font-size 13px
|
||||
:text-align center
|
||||
:-webkit-text-stroke 1px rgba(255, 255, 255, 0.1)
|
||||
:color #555
|
||||
|
||||
h1, h2
|
||||
:margin 0 0 15px 0
|
||||
:font-size 22px
|
||||
:color #343434
|
||||
h1
|
||||
:text-shadow 1px 2px 2px #ddd
|
||||
:font-size 60px
|
||||
h2
|
||||
:margin-top 15px
|
||||
|
||||
#wrapper
|
||||
:position relative
|
||||
:margin 100px auto
|
||||
:width 500px
|
||||
:text-align left
|
||||
|
||||
input[type=file]
|
||||
:padding 5px
|
||||
:border 1px solid #ddd
|
||||
:outline none
|
||||
:-webkit-border-radius 2px
|
||||
:-moz-border-radius 2px
|
||||
input[type=file]:focus
|
||||
:border-color #00C3FF
|
||||
|
||||
input[type=submit]
|
||||
:-webkit-border-radius 2px
|
||||
:-moz-border-radius 2px
|
||||
:-webkit-box-shadow 0 1px 2px #ddd
|
||||
:-moz-box-shadow 0 1px 2px #ddd
|
||||
:padding 6px 10px
|
||||
:border solid 1px #999
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ddd))
|
||||
:color #333
|
||||
:text-decoration none
|
||||
:cursor pointer
|
||||
:display inline-block
|
||||
:text-align center
|
||||
:text-shadow 0px 1px 1px #fff
|
||||
:line-height 1
|
||||
input[type=submit]:hover
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#E6E4E4))
|
||||
input[type=submit]:active
|
||||
:background -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#c7c7c7))
|
||||
input[name=name]
|
||||
:width 80px
|
||||
|
||||
form
|
||||
.panel
|
||||
:float left
|
||||
:width 100%
|
||||
:margin-bottom 15px
|
||||
|
||||
.messages
|
||||
:margin 0
|
||||
:padding 0
|
||||
:border 1px solid #eee
|
||||
=box-shadow 2px 2px 5px #eee
|
||||
li
|
||||
:padding 5px 10px
|
||||
:list-style none
|
||||
@@ -1,18 +0,0 @@
|
||||
:if typeof images !== 'undefined'
|
||||
.images
|
||||
:each img in images
|
||||
%img{ src: img }
|
||||
|
||||
%h2 Singles
|
||||
%form{ method: 'post', enctype: 'multipart/form-data' }
|
||||
%input{ type: 'file', name: 'images[0]' }
|
||||
%input{ type: 'file', name: 'images[1]' }
|
||||
%input{ type: 'file', name: 'images[2]' }
|
||||
.panel
|
||||
%input{ type: 'submit', value: 'Upload' }
|
||||
|
||||
%h2 Multiple
|
||||
%form{ method: 'post', enctype: 'multipart/form-data' }
|
||||
%input{ type: 'file', name: 'images[]', multiple: 'multiple' }
|
||||
.panel
|
||||
%input{ type: 'submit', value: 'Upload' }
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
module.exports = require('./lib/express');
|
||||
Arquivo executável
+15
@@ -0,0 +1,15 @@
|
||||
|
||||
install() {
|
||||
mkdir -p /tmp/$2 \
|
||||
&& cd /tmp/$2 \
|
||||
&& echo "... installing $2" \
|
||||
&& curl -# -L "http://github.com/$1/$2/tarball/master" \
|
||||
| tar xz --strip 1 \
|
||||
&& mkdir -p ~/.node_libraries \
|
||||
&& cp -fr lib/$2 ~/.node_libraries/$2
|
||||
}
|
||||
|
||||
install visionmedia express \
|
||||
&& install senchalabs connect \
|
||||
&& cp -f /tmp/express/bin/express /usr/local/bin/express \
|
||||
&& echo "... installation complete"
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
require.paths.unshift(__dirname + '/support/js-oo/lib')
|
||||
require.paths.unshift(__dirname + '/support/ejs/lib')
|
||||
require.paths.unshift(__dirname + '/support/haml/lib')
|
||||
require.paths.unshift(__dirname + '/support/sass/lib')
|
||||
require.paths.unshift(__dirname + '/support/ext/lib')
|
||||
require('oo')
|
||||
require('ext')
|
||||
require('express/core')
|
||||
@@ -1,335 +0,0 @@
|
||||
|
||||
// Express - Core - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var multipart = require('multipart'),
|
||||
utils = require('express/utils'),
|
||||
events = require('events'),
|
||||
fs = require('fs')
|
||||
|
||||
global.merge(require('sys'))
|
||||
global.merge(require('express/exceptions'))
|
||||
global.merge(require('express/event'))
|
||||
global.merge(require('express/request'))
|
||||
global.merge(require('express/plugin'))
|
||||
global.merge(require('express/dsl'))
|
||||
|
||||
// --- Route
|
||||
|
||||
Route = Class({
|
||||
|
||||
/**
|
||||
* Initialize a route with the given _method_,
|
||||
* _path_, and callback _fn_.
|
||||
*
|
||||
* The given _path_ becomes #originalPath,
|
||||
* #path is then a normalized version converted
|
||||
* to a regular expression for routing.
|
||||
*
|
||||
* @param {string} method
|
||||
* @param {string} path
|
||||
* @param {function} fn
|
||||
* @param {hash} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
init: function(method, path, fn, options){
|
||||
this.method = method
|
||||
this.originalPath = path
|
||||
this.path = this.normalize(path)
|
||||
this.fn = fn
|
||||
},
|
||||
|
||||
/**
|
||||
* Normalize _path_. When a RegExp it is simply returned,
|
||||
* otherwise a string is converted to a regular expression
|
||||
* surrounded by ^$. So /user/:id/edit would become:
|
||||
*
|
||||
* /^\/user\/([^\/]+)\/edit$/i
|
||||
*
|
||||
* Each param key (:id) will be captured and placed in the
|
||||
* params array, so param('id') would give the string captured.
|
||||
*
|
||||
* The following are valid routes:
|
||||
*
|
||||
* - /user/:id Ex: '/user/12'
|
||||
* - /user/:id? Ex: '/user', '/user/12'
|
||||
* - /report.:format Ex: '/report.pdf', 'report.csv'
|
||||
* - /public/* Ex: '/public/app.js', '/public/javascripts/app.js'
|
||||
* - /public/*.* Ex: '/public/app.js', '/public/javascripts/app.js'
|
||||
*
|
||||
* @param {string} path
|
||||
* @return {regexp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
normalize: function(path) {
|
||||
var self = this
|
||||
this.params = []
|
||||
if (path instanceof RegExp) return path
|
||||
return new RegExp('^' + RegExp.escape(normalizePath(path), '.')
|
||||
.replace(/\*/g, '(.+)')
|
||||
.replace(/(\/|\\\.):(\w+)\?/g, function(_, c, key){
|
||||
self.params.push(key)
|
||||
return '(?:' + c + '([^\/]+))?'
|
||||
})
|
||||
.replace(/:(\w+)/g, function(_, key){
|
||||
self.params.push(key)
|
||||
return '([^\/]+)'
|
||||
}) + '$', 'i')
|
||||
}
|
||||
})
|
||||
|
||||
// --- Router
|
||||
|
||||
Router = Class({
|
||||
|
||||
/**
|
||||
* Initialize with _request_ and parse url.
|
||||
*
|
||||
* @param {Request} request
|
||||
* @api private
|
||||
*/
|
||||
|
||||
init: function(request) {
|
||||
this.request = request
|
||||
},
|
||||
|
||||
/**
|
||||
* Evaluate the matched route against #request.
|
||||
*
|
||||
* @return {mixed}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
route: function(){
|
||||
var route = this.matchingRoute()
|
||||
if (route)
|
||||
return route.fn.apply(this.request, this.request.captures.slice(1))
|
||||
else if (this.request.accepts('html') && set('helpful 404'))
|
||||
this.request.halt(404, require('express/pages/not-found').render(this.request))
|
||||
else
|
||||
this.request.halt()
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempt to match a route from Express.routes.
|
||||
*
|
||||
* @return {Route}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
matchingRoute: function(){
|
||||
return Express.routes.find(function(route){
|
||||
return this.match(route)
|
||||
}, this)
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if _route_ matches the current request.
|
||||
* If so populate #captures and #params.
|
||||
*
|
||||
* @param {object} route
|
||||
* @return {bool}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
match: function(route) {
|
||||
if (this.request.method.toLowerCase() == route.method)
|
||||
if (this.request.captures = this.request.url.pathname.match(route.path)) {
|
||||
this.mapParams(route)
|
||||
return true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Map #request.captures to #request.params.path based on the
|
||||
* given _route_ params.
|
||||
*
|
||||
* @param {Route} route
|
||||
* @api private
|
||||
*/
|
||||
|
||||
mapParams: function(route) {
|
||||
route.params.each(function(key, i){
|
||||
this.request.params.path[key] = this.request.captures[++i]
|
||||
}, this)
|
||||
}
|
||||
})
|
||||
|
||||
// --- Server
|
||||
|
||||
Server = Class({
|
||||
|
||||
/**
|
||||
* Default port number.
|
||||
*/
|
||||
|
||||
port: 3000,
|
||||
|
||||
/**
|
||||
* Default host ip, when null node will accept requests on
|
||||
* all network addresses.
|
||||
*/
|
||||
|
||||
host: 'localhost',
|
||||
|
||||
/**
|
||||
* Maximum number of queued connections.
|
||||
*/
|
||||
|
||||
backlog: 128,
|
||||
|
||||
/**
|
||||
* Run Express.
|
||||
*
|
||||
* - Buffers request bodies
|
||||
* - Calls #route() once the request is complete
|
||||
*
|
||||
* @param {int} port
|
||||
* @param {string} host
|
||||
* @param {int} backlog
|
||||
* @see run()
|
||||
* @api private
|
||||
*/
|
||||
|
||||
run: function(port, host, backlog){
|
||||
var self = this
|
||||
this.running = true
|
||||
if (host !== undefined) this.host = host
|
||||
if (port !== undefined) this.port = port
|
||||
if (backlog !== undefined) this.backlog = backlog
|
||||
require('http')
|
||||
.createServer(function(request, response){
|
||||
request.body = ''
|
||||
request.setBodyEncoding('binary')
|
||||
function callback(e, result) {
|
||||
if (e)
|
||||
self.error(e, request, response)
|
||||
else if (!pendingFiles)
|
||||
self.route(request, response)
|
||||
}
|
||||
if (request.headers['content-type'] &&
|
||||
request.headers['content-type'].includes('multipart/form-data')) {
|
||||
var stream = multipart.parse(request),
|
||||
pendingFiles = 0
|
||||
request.params = { post: {}}
|
||||
stream
|
||||
.addListener('partBegin', function(part) {
|
||||
if (part.filename)
|
||||
++pendingFiles,
|
||||
part.tempfile = '/tmp/express-' + Number(new Date) + utils.uid(),
|
||||
part.fileStream = fs.createWriteStream(part.tempfile)
|
||||
else
|
||||
part.buf = ''
|
||||
})
|
||||
.addListener('body', function(chunk) {
|
||||
if (stream.part.fileStream)
|
||||
stream.part.fileStream.write(chunk)
|
||||
else
|
||||
stream.part.buf += chunk
|
||||
})
|
||||
.addListener('partEnd', function(part) {
|
||||
if (!part.name) return
|
||||
if (part.fileStream)
|
||||
part.fileStream.close(function(){
|
||||
--pendingFiles
|
||||
callback()
|
||||
}),
|
||||
utils.mergeParam(part.name, { filename: part.filename, tempfile: part.tempfile }, request.params.post)
|
||||
else
|
||||
utils.mergeParam(part.name, part.buf, request.params.post)
|
||||
})
|
||||
.addListener('error', callback)
|
||||
.addListener('complete', callback)
|
||||
}
|
||||
else
|
||||
request
|
||||
.addListener('data', function(chunk){ request.body += chunk })
|
||||
.addListener('end', callback)
|
||||
})
|
||||
.listen(this.port, this.host, this.backlog)
|
||||
puts('Express started at http://' + this.host + ':' + this.port + '/ in ' + Express.environment + ' mode')
|
||||
},
|
||||
|
||||
/**
|
||||
* Route the given _request_ and _response_.
|
||||
*
|
||||
* @param {object} request
|
||||
* @param {object} response
|
||||
* @api private
|
||||
*/
|
||||
|
||||
route: function(request, response){
|
||||
request = new Request(request, response)
|
||||
request.trigger('request')
|
||||
if (request.response.finished) return
|
||||
try {
|
||||
if (typeof (body = (new Router(request)).route()) == 'string')
|
||||
request.halt(200, body)
|
||||
}
|
||||
catch (e) {
|
||||
this.error(e, request)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle errors.
|
||||
*
|
||||
* @param {Error} e
|
||||
* @param {object} request
|
||||
* @param {object} response
|
||||
* @api private
|
||||
*/
|
||||
|
||||
error: function (e, request, response) {
|
||||
if (e instanceof ExpressError)
|
||||
throw e
|
||||
if (!(request instanceof Request))
|
||||
request = new Request(request, response),
|
||||
request.trigger('request')
|
||||
if (request.accepts('html') && set('show exceptions'))
|
||||
request.halt(500, require('express/pages/show-exceptions').render(request, e))
|
||||
else
|
||||
request.halt(500)
|
||||
if (set('throw exceptions'))
|
||||
throw e
|
||||
}
|
||||
})
|
||||
|
||||
// --- Express
|
||||
|
||||
Express = {
|
||||
version: '0.5.0',
|
||||
config: [],
|
||||
routes: [],
|
||||
plugins: [],
|
||||
settings: {},
|
||||
server: new Server
|
||||
}
|
||||
|
||||
// --- Defaults
|
||||
|
||||
configure(function(){
|
||||
use(require('express/plugins/view').View)
|
||||
use(require('express/plugins/cache').Cache)
|
||||
use(require('express/plugins/redirect').Redirect)
|
||||
use(require('express/plugins/body-decoder').BodyDecoder)
|
||||
})
|
||||
|
||||
configure('development', function(){
|
||||
enable('helpful 404')
|
||||
enable('show exceptions')
|
||||
})
|
||||
|
||||
configure('test', function(){
|
||||
enable('throw exceptions')
|
||||
})
|
||||
|
||||
configure('production', function(){
|
||||
enable('cache view contents')
|
||||
enable('cache static files')
|
||||
})
|
||||
@@ -1,134 +0,0 @@
|
||||
|
||||
// Express - DSL - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('express/http')
|
||||
|
||||
/**
|
||||
* Return a routing function for _method_.
|
||||
*
|
||||
* @param {string} method
|
||||
* @return {function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function route(method) {
|
||||
return function(path, options, fn){
|
||||
if (options instanceof Function)
|
||||
fn = options, options = {}
|
||||
if (path.startsWith('http://'))
|
||||
return http[method].apply(this, arguments)
|
||||
else if (!Express.server.running)
|
||||
Express.routes.push(new Route(method, path, fn, options))
|
||||
else
|
||||
throw new Error('cannot create route ' + method.toUpperCase() + " `" + path + "' at runtime")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set _option_ to _val_. When only _option_ is
|
||||
* present its current value will be returned.
|
||||
*
|
||||
* @param {string} option
|
||||
* @param {mixed} val
|
||||
* @return {mixed}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.set = function(option, val) {
|
||||
return val === undefined
|
||||
? Express.settings[option] instanceof Function
|
||||
? Express.settings[option]()
|
||||
: Express.settings[option]
|
||||
: Express.settings[option] = val
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable _options_.
|
||||
*
|
||||
* @param {string} option
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.enable = function(option) {
|
||||
set(option, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable _option_.
|
||||
*
|
||||
* @param {string} option
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.disable = function(option) {
|
||||
set(option, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Express, view Server#run() for parameters.
|
||||
*
|
||||
* All configuration handlers for EXPRESS_ENV or 'development'
|
||||
* are called before starting the server.
|
||||
*
|
||||
* @see Server#run()
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.run = function() {
|
||||
configure(Express.environment = process.env.EXPRESS_ENV || 'development')
|
||||
Express.plugins.each(function(plugin){
|
||||
if ('init' in plugin.klass)
|
||||
plugin.klass.init(plugin.options)
|
||||
})
|
||||
Express.server.run.apply(Express.server, arguments)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure _env_ with _fn_.
|
||||
*
|
||||
* Global configuration, disregards which
|
||||
* environment is active:
|
||||
*
|
||||
* configure(function(){
|
||||
* // ...
|
||||
* })
|
||||
*
|
||||
* Environment specific configuration:
|
||||
*
|
||||
* configure('development', function(){
|
||||
* // ...
|
||||
* })
|
||||
*
|
||||
* Running configurations:
|
||||
*
|
||||
* configure('development')
|
||||
*
|
||||
* @param {string, function} env
|
||||
* @param {function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.configure = function(env, fn) {
|
||||
if (env instanceof Function)
|
||||
fn = env, env = 'all'
|
||||
if (fn instanceof Function)
|
||||
return Express.config.push([env, fn])
|
||||
if (typeof env !== 'string')
|
||||
throw new Error('environment required')
|
||||
Express.config.each(function(conf){
|
||||
if (conf[0] === env ||
|
||||
conf[0] === 'all')
|
||||
conf[1].call(Express)
|
||||
})
|
||||
}
|
||||
|
||||
// --- Routing API
|
||||
|
||||
exports.get = exports.view = route('get')
|
||||
exports.post = exports.create = route('post')
|
||||
exports.del = exports.destroy = route('delete')
|
||||
exports.put = exports.update = route('put')
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
// Express - Event - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
exports.Event = Class({
|
||||
|
||||
/**
|
||||
* Initialize with event _name_ and optional _data_.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {hash} data
|
||||
* @api private
|
||||
*/
|
||||
|
||||
init: function(name, data) {
|
||||
this.name = name
|
||||
this.merge(data || {})
|
||||
},
|
||||
|
||||
/**
|
||||
* Return event string.
|
||||
*
|
||||
* @return {string}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
toString: function() {
|
||||
return '[Event ' + this.name + ']'
|
||||
}
|
||||
})
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
// Express - Exceptions - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
// --- ExpressError
|
||||
|
||||
ExpressError = Class({
|
||||
name: 'ExpressError',
|
||||
init: function(message) {
|
||||
this.message = message
|
||||
},
|
||||
toString: function() {
|
||||
return this.name + ': ' + this.message
|
||||
}
|
||||
})
|
||||
@@ -1,90 +0,0 @@
|
||||
|
||||
// Express - HTTP - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http'),
|
||||
utils = require('express/utils'),
|
||||
parse = require('url').parse,
|
||||
queryString = require('querystring')
|
||||
|
||||
/**
|
||||
* Mega super awesome private request utility.
|
||||
*
|
||||
* @param {string} method
|
||||
* @param {string} url
|
||||
* @param {hash} data
|
||||
* @param {hash} headers
|
||||
* @param {function} fn
|
||||
* @param {number} redirects
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function request(method, url, data, headers, fn, redirects) {
|
||||
var buf = '',
|
||||
redirects = redirects || 3,
|
||||
url = parse(url),
|
||||
path = url.pathname || '/',
|
||||
search = url.search || '',
|
||||
hash = url.hash || '',
|
||||
port = url.port || 80,
|
||||
headers = utils.mixin(headers, { host: url.hostname }),
|
||||
client = http.createClient(port, url.hostname)
|
||||
if (headers.redirect)
|
||||
redirects = headers.redirect,
|
||||
delete headers.redirect
|
||||
if (data) {
|
||||
data = queryString.stringify(data)
|
||||
headers['content-length'] = data.length
|
||||
headers['content-type'] = 'application/x-www-form-urlencoded'
|
||||
}
|
||||
var req = client.request(method, path + search + hash, headers)
|
||||
if (data) req.write(data)
|
||||
req.addListener('response', function(res){
|
||||
if (req.statusCode < 200 || req.statusCode >= 400)
|
||||
fn(new Error('request failed with status ' + res.statusCode + ' "' + http.STATUS_CODES[res.statusCode] + '"'))
|
||||
else if (res.statusCode >= 300 && res.statusCode < 400)
|
||||
if (--redirects)
|
||||
request(method, res.headers.location, headers, data, fn, redirects)
|
||||
else
|
||||
fn(new Error('maximum number of redirects reached'))
|
||||
else {
|
||||
res.setBodyEncoding('utf8')
|
||||
res
|
||||
.addListener('data', function(chunk){ buf += chunk })
|
||||
.addListener('end', function(){ fn(null, buf, res) })
|
||||
}
|
||||
})
|
||||
req.close()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTTP Client function for the given _method_.
|
||||
*
|
||||
* @param {string} method
|
||||
* @return {function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function client(method) {
|
||||
return function() {
|
||||
var headers, data,
|
||||
args = Array.prototype.slice.call(arguments),
|
||||
url = args.shift(),
|
||||
fn = args.pop(),
|
||||
data = args.shift(),
|
||||
headers = args.shift()
|
||||
if (typeof fn !== 'function')
|
||||
throw new TypeError('http client requires a callback function')
|
||||
return request(method.toUpperCase(), url, data, headers, fn)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Public API
|
||||
|
||||
exports.get = exports.view = client('get')
|
||||
exports.post = exports.create = client('post')
|
||||
exports.put = exports.update = client('put')
|
||||
exports.del = exports.destroy = client('delete')
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
/*!
|
||||
* Express
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '1.0.0beta2';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Server = exports.Server = require('./server');
|
||||
|
||||
/**
|
||||
* Shortcut for `new Server(...)`.
|
||||
*
|
||||
* @param {Function} ...
|
||||
* @return {Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.createServer = function(){
|
||||
return new Server(Array.prototype.slice.call(arguments));
|
||||
};
|
||||
|
||||
/**
|
||||
* View extensions.
|
||||
*/
|
||||
|
||||
require('./view');
|
||||
require('./request');
|
||||
require('./response');
|
||||
@@ -1,370 +0,0 @@
|
||||
|
||||
// Express - Mime - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var extname = require('path').extname
|
||||
|
||||
/**
|
||||
* Mime type lookup table.
|
||||
*/
|
||||
|
||||
exports.types = {
|
||||
'323' : 'text/h323',
|
||||
'3gp' : 'video/3gpp',
|
||||
'a' : 'application/octet-stream',
|
||||
'acx' : 'application/internet-property-stream',
|
||||
'ai' : 'application/postscript',
|
||||
'aif' : 'audio/x-aiff',
|
||||
'aifc' : 'audio/x-aiff',
|
||||
'aiff' : 'audio/x-aiff',
|
||||
'asc' : 'application/pgp-signature',
|
||||
'asf' : 'video/x-ms-asf',
|
||||
'asr' : 'video/x-ms-asf',
|
||||
'asm' : 'text/x-asm',
|
||||
'asx' : 'video/x-ms-asf',
|
||||
'atom' : 'application/atom+xml',
|
||||
'au' : 'audio/basic',
|
||||
'avi' : 'video/x-msvideo',
|
||||
'axs' : 'application/olescript',
|
||||
'bas' : 'text/plain',
|
||||
'bat' : 'application/x-msdownload',
|
||||
'bcpio' : 'application/x-bcpio',
|
||||
'bin' : 'application/octet-stream',
|
||||
'bmp' : 'image/bmp',
|
||||
'bz2' : 'application/x-bzip2',
|
||||
'c' : 'text/x-c',
|
||||
'cab' : 'application/vnd.ms-cab-compressed',
|
||||
'cat' : 'application/vnd.ms-pkiseccat',
|
||||
'cc' : 'text/x-c',
|
||||
'cdf' : 'application/x-netcdf',
|
||||
'cer' : 'application/x-x509-ca-cert',
|
||||
'cgm' : 'image/cgm',
|
||||
'chm' : 'application/vnd.ms-htmlhelp',
|
||||
'class' : 'application/octet-stream',
|
||||
'clp' : 'application/x-msclip',
|
||||
'cmx' : 'image/x-cmx',
|
||||
'cod' : 'image/cis-cod',
|
||||
'com' : 'application/x-msdownload',
|
||||
'conf' : 'text/plain',
|
||||
'cpio' : 'application/x-cpio',
|
||||
'cpp' : 'text/x-c',
|
||||
'cpt' : 'application/mac-compactpro',
|
||||
'crd' : 'application/x-mscardfile',
|
||||
'crl' : 'application/pkix-crl',
|
||||
'crt' : 'application/x-x509-ca-cert',
|
||||
'csh' : 'application/x-csh',
|
||||
'css' : 'text/css',
|
||||
'csv' : 'text/csv',
|
||||
'cxx' : 'text/x-c',
|
||||
'dcr' : 'application/x-director',
|
||||
'deb' : 'application/x-debian-package',
|
||||
'der' : 'application/x-x509-ca-cert',
|
||||
'diff' : 'text/x-diff',
|
||||
'dir' : 'application/x-director',
|
||||
'djv' : 'image/vnd.djvu',
|
||||
'djvu' : 'image/vnd.djvu',
|
||||
'dll' : 'application/x-msdownload',
|
||||
'dmg' : 'application/octet-stream',
|
||||
'dms' : 'application/octet-stream',
|
||||
'doc' : 'application/msword',
|
||||
'dot' : 'application/msword',
|
||||
'dtd' : 'application/xml-dtd',
|
||||
'dv' : 'video/x-dv',
|
||||
'dvi' : 'application/x-dvi',
|
||||
'dxr' : 'application/x-director',
|
||||
'ear' : 'application/java-archive',
|
||||
'eml' : 'message/rfc822',
|
||||
'eps' : 'application/postscript',
|
||||
'etx' : 'text/x-setext',
|
||||
'evy' : 'application/envoy',
|
||||
'exe' : 'application/x-msdownload',
|
||||
'ez' : 'application/andrew-inset',
|
||||
'f' : 'text/x-fortran',
|
||||
'f77' : 'text/x-fortran',
|
||||
'f90' : 'text/x-fortran',
|
||||
'fif' : 'application/fractals',
|
||||
'flr' : 'x-world/x-vrml',
|
||||
'flv' : 'video/x-flv',
|
||||
'for' : 'text/x-fortran',
|
||||
'gem' : 'application/octet-stream',
|
||||
'gemspec' : 'text/x-script.ruby',
|
||||
'gif' : 'image/gif',
|
||||
'gram' : 'application/srgs',
|
||||
'grxml' : 'application/srgs+xml',
|
||||
'gtar' : 'application/x-gtar',
|
||||
'gz' : 'application/x-gzip',
|
||||
'h' : 'text/x-c',
|
||||
'hdf' : 'application/x-hdf',
|
||||
'hh' : 'text/x-c',
|
||||
'hlp' : 'application/winhlp',
|
||||
'hqx' : 'application/mac-binhex40',
|
||||
'hta' : 'application/hta',
|
||||
'htc' : 'text/x-component',
|
||||
'htm' : 'text/html',
|
||||
'html' : 'text/html',
|
||||
'htt' : 'text/webviewhtml',
|
||||
'ice' : 'x-conference/x-cooltalk',
|
||||
'ico' : 'image/vnd.microsoft.icon',
|
||||
'ics' : 'text/calendar',
|
||||
'ief' : 'image/ief',
|
||||
'ifb' : 'text/calendar',
|
||||
'iges' : 'model/iges',
|
||||
'igs' : 'model/iges',
|
||||
'iii' : 'application/x-iphone',
|
||||
'ins' : 'application/x-internet-signup',
|
||||
'isp' : 'application/x-internet-signup',
|
||||
'iso' : 'application/octet-stream',
|
||||
'jar' : 'application/java-archive',
|
||||
'java' : 'text/x-java-source',
|
||||
'jfif' : 'image/pipeg',
|
||||
'jnlp' : 'application/x-java-jnlp-file',
|
||||
'jp2' : 'image/jp2',
|
||||
'jpe' : 'image/jpeg',
|
||||
'jpeg' : 'image/jpeg',
|
||||
'jpg' : 'image/jpeg',
|
||||
'js' : 'application/javascript',
|
||||
'json' : 'application/json',
|
||||
'kar' : 'audio/midi',
|
||||
'latex' : 'application/x-latex',
|
||||
'lha' : 'application/octet-stream',
|
||||
'lsf' : 'video/x-la-asf',
|
||||
'lsx' : 'video/x-la-asf',
|
||||
'lzh' : 'application/octet-stream',
|
||||
'log' : 'text/plain',
|
||||
'm13' : 'application/x-msmediaview',
|
||||
'm14' : 'application/x-msmediaview',
|
||||
'm3u' : 'audio/x-mpegurl',
|
||||
'm4a' : 'audio/mp4a-latm',
|
||||
'm4b' : 'audio/mp4a-latm',
|
||||
'm4p' : 'audio/mp4a-latm',
|
||||
'm4u' : 'video/vnd.mpegurl',
|
||||
'm4v' : 'video/mp4',
|
||||
'mac' : 'image/x-macpaint',
|
||||
'man' : 'text/troff',
|
||||
'mathml' : 'application/mathml+xml',
|
||||
'mbox' : 'application/mbox',
|
||||
'mdb' : 'application/x-msaccess',
|
||||
'mdoc' : 'text/troff',
|
||||
'me' : 'text/troff',
|
||||
'mesh' : 'model/mesh',
|
||||
'mht' : 'message/rfc822',
|
||||
'mhtml' : 'message/rfc822',
|
||||
'mid' : 'audio/midi',
|
||||
'midi' : 'audio/midi',
|
||||
'mif' : 'application/vnd.mif',
|
||||
'mime' : 'message/rfc822',
|
||||
'mml' : 'application/mathml+xml',
|
||||
'mng' : 'video/x-mng',
|
||||
'mny' : 'application/x-msmoney',
|
||||
'mov' : 'video/quicktime',
|
||||
'movie' : 'video/x-sgi-movie',
|
||||
'mp2' : 'video/mpeg',
|
||||
'mp3' : 'audio/mpeg',
|
||||
'mp4' : 'video/mp4',
|
||||
'mp4v' : 'video/mp4',
|
||||
'mpa' : 'video/mpeg',
|
||||
'mpe' : 'video/mpeg',
|
||||
'mpeg' : 'video/mpeg',
|
||||
'mpg' : 'video/mpeg',
|
||||
'mpga' : 'audio/mpeg',
|
||||
'mpp' : 'application/vnd.ms-project',
|
||||
'mpv2' : 'video/mpeg',
|
||||
'ms' : 'text/troff',
|
||||
'msh' : 'model/mesh',
|
||||
'msi' : 'application/x-msdownload',
|
||||
'mvb' : 'application/x-msmediaview',
|
||||
'mxu' : 'video/vnd.mpegurl',
|
||||
'nc' : 'application/x-netcdf',
|
||||
'nws' : 'message/rfc822',
|
||||
'oda' : 'application/oda',
|
||||
'odp' : 'application/vnd.oasis.opendocument.presentation',
|
||||
'ods' : 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'odt' : 'application/vnd.oasis.opendocument.text',
|
||||
'ogg' : 'application/ogg',
|
||||
'p' : 'text/x-pascal',
|
||||
'p10' : 'application/pkcs10',
|
||||
'p12' : 'application/x-pkcs12',
|
||||
'p7b' : 'application/x-pkcs7-certificates',
|
||||
'p7c' : 'application/x-pkcs7-mime',
|
||||
'p7m' : 'application/x-pkcs7-mime',
|
||||
'p7r' : 'application/x-pkcs7-certreqresp',
|
||||
'p7s' : 'application/x-pkcs7-signature',
|
||||
'pas' : 'text/x-pascal',
|
||||
'pbm' : 'image/x-portable-bitmap',
|
||||
'pct' : 'image/pict',
|
||||
'pdb' : 'chemical/x-pdb',
|
||||
'pdf' : 'application/pdf',
|
||||
'pem' : 'application/x-x509-ca-cert',
|
||||
'pfx' : 'application/x-pkcs12',
|
||||
'pgm' : 'image/x-portable-graymap',
|
||||
'pgn' : 'application/x-chess-pgn',
|
||||
'pgp' : 'application/pgp-encrypted',
|
||||
'pic' : 'image/pict',
|
||||
'pict' : 'image/pict',
|
||||
'pkg' : 'application/octet-stream',
|
||||
'pko' : 'application/ynd.ms-pkipko',
|
||||
'pl' : 'text/x-script.perl',
|
||||
'pm' : 'text/x-script.perl-module',
|
||||
'pma' : 'application/x-perfmon',
|
||||
'pmc' : 'application/x-perfmon',
|
||||
'pml' : 'application/x-perfmon',
|
||||
'pmr' : 'application/x-perfmon',
|
||||
'pmw' : 'application/x-perfmon',
|
||||
'png' : 'image/png',
|
||||
'pnm' : 'image/x-portable-anymap',
|
||||
'pnt' : 'image/x-macpaint',
|
||||
'pntg' : 'image/x-macpaint',
|
||||
'pot' : 'application/vnd.ms-powerpoint',
|
||||
'ppm' : 'image/x-portable-pixmap',
|
||||
'pps' : 'application/vnd.ms-powerpoint',
|
||||
'ppt' : 'application/vnd.ms-powerpoint',
|
||||
'prf' : 'application/pics-rules',
|
||||
'ps' : 'application/postscript',
|
||||
'psd' : 'image/vnd.adobe.photoshop',
|
||||
'pub' : 'application/x-mspublisher',
|
||||
'py' : 'text/x-script.python',
|
||||
'qt' : 'video/quicktime',
|
||||
'qti' : 'image/x-quicktime',
|
||||
'qtif' : 'image/x-quicktime',
|
||||
'ra' : 'audio/x-pn-realaudio',
|
||||
'rake' : 'text/x-script.ruby',
|
||||
'ram' : 'audio/x-pn-realaudio',
|
||||
'rar' : 'application/x-rar-compressed',
|
||||
'ras' : 'image/x-cmu-raster',
|
||||
'rb' : 'text/x-script.ruby',
|
||||
'rdf' : 'application/rdf+xml',
|
||||
'rgb' : 'image/x-rgb',
|
||||
'rm' : 'application/vnd.rn-realmedia',
|
||||
'rmi' : 'audio/mid',
|
||||
'roff' : 'text/troff',
|
||||
'rpm' : 'application/x-redhat-package-manager',
|
||||
'rss' : 'application/rss+xml',
|
||||
'rtf' : 'application/rtf',
|
||||
'rtx' : 'text/richtext',
|
||||
'ru' : 'text/x-script.ruby',
|
||||
's' : 'text/x-asm',
|
||||
'scd' : 'application/x-msschedule',
|
||||
'sct' : 'text/scriptlet',
|
||||
'setpay' : 'application/set-payment-initiation',
|
||||
'setreg' : 'application/set-registration-initiation',
|
||||
'sgm' : 'text/sgml',
|
||||
'sgml' : 'text/sgml',
|
||||
'sh' : 'application/x-sh',
|
||||
'shar' : 'application/x-shar',
|
||||
'sig' : 'application/pgp-signature',
|
||||
'silo' : 'model/mesh',
|
||||
'sit' : 'application/x-stuffit',
|
||||
'skd' : 'application/x-koan',
|
||||
'skm' : 'application/x-koan',
|
||||
'skp' : 'application/x-koan',
|
||||
'skt' : 'application/x-koan',
|
||||
'smi' : 'application/smil',
|
||||
'smil' : 'application/smil',
|
||||
'snd' : 'audio/basic',
|
||||
'so' : 'application/octet-stream',
|
||||
'spc' : 'application/x-pkcs7-certificates',
|
||||
'spl' : 'application/x-futuresplash',
|
||||
'src' : 'application/x-wais-source',
|
||||
'sst' : 'application/vnd.ms-pkicertstore',
|
||||
'stl' : 'application/vnd.ms-pkistl',
|
||||
'stm' : 'text/html',
|
||||
'sv4cpio' : 'application/x-sv4cpio',
|
||||
'sv4crc' : 'application/x-sv4crc',
|
||||
'svg' : 'image/svg+xml',
|
||||
'svgz' : 'image/svg+xml',
|
||||
'swf' : 'application/x-shockwave-flash',
|
||||
't' : 'text/troff',
|
||||
'tar' : 'application/x-tar',
|
||||
'tbz' : 'application/x-bzip-compressed-tar',
|
||||
'tcl' : 'application/x-tcl',
|
||||
'tex' : 'application/x-tex',
|
||||
'texi' : 'application/x-texinfo',
|
||||
'texinfo' : 'application/x-texinfo',
|
||||
'text' : 'text/plain',
|
||||
'tgz' : 'application/x-compressed',
|
||||
'tif' : 'image/tiff',
|
||||
'tiff' : 'image/tiff',
|
||||
'torrent' : 'application/x-bittorrent',
|
||||
'tr' : 'text/troff',
|
||||
'trm' : 'application/x-msterminal',
|
||||
'tsv' : 'text/tab-seperated-values',
|
||||
'txt' : 'text/plain',
|
||||
'uls' : 'text/iuls',
|
||||
'ustar' : 'application/x-ustar',
|
||||
'vcd' : 'application/x-cdlink',
|
||||
'vcf' : 'text/x-vcard',
|
||||
'vcs' : 'text/x-vcalendar',
|
||||
'vrml' : 'model/vrml',
|
||||
'vxml' : 'application/voicexml+xml',
|
||||
'war' : 'application/java-archive',
|
||||
'wav' : 'audio/x-wav',
|
||||
'wbmp' : 'image/vnd.wap.wbmp',
|
||||
'wbxml' : 'application/vnd.wap.wbxml',
|
||||
'wcm' : 'application/vnd.ms-works',
|
||||
'wdb' : 'application/vnd.ms-works',
|
||||
'wks' : 'application/vnd.ms-works',
|
||||
'wma' : 'audio/x-ms-wma',
|
||||
'wmf' : 'application/x-msmetafile',
|
||||
'wml' : 'text/vnd.wap.wml',
|
||||
'wmls' : 'text/vnd.wap.wmlscript',
|
||||
'wmlsc' : 'application/vnd.wap.wmlscriptc',
|
||||
'wmv' : 'video/x-ms-wmv',
|
||||
'wmx' : 'video/x-ms-wmx',
|
||||
'wps' : 'application/vnd.ms-works',
|
||||
'wri' : 'application/x-mswrite',
|
||||
'wrl' : 'model/vrml',
|
||||
'wrz' : 'x-world/x-vrml',
|
||||
'wsdl' : 'application/wsdl+xml',
|
||||
'xaf' : 'x-world/x-vrml',
|
||||
'xbm' : 'image/x-xbitmap',
|
||||
'xht' : 'application/xhtml+xml',
|
||||
'xhtml' : 'application/xhtml+xml',
|
||||
'xla' : 'application/vnd.ms-excel',
|
||||
'xlc' : 'application/vnd.ms-excel',
|
||||
'xlm' : 'application/vnd.ms-excel',
|
||||
'xls' : 'application/vnd.ms-excel',
|
||||
'xlt' : 'application/vnd.ms-excel',
|
||||
'xml' : 'application/xml',
|
||||
'xof' : 'x-world/x-vrml',
|
||||
'xpm' : 'image/x-xpixmap',
|
||||
'xsl' : 'application/xml',
|
||||
'xslt' : 'application/xslt+xml',
|
||||
'xul' : 'application/vnd.mozilla.xul+xml',
|
||||
'xwd' : 'image/x-xwindowdump',
|
||||
'xyz' : 'chemical/x-xyz',
|
||||
'yaml' : 'text/yaml',
|
||||
'yml' : 'text/yaml',
|
||||
'z' : 'application/x-compress',
|
||||
'zip' : 'application/zip'
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mime type associated with _path_,
|
||||
* where _path_ may be an extension, or full
|
||||
* file path.
|
||||
*
|
||||
* By default 'application/octet-stream' is returned,
|
||||
* however this can be altered using the 'default mime type'
|
||||
* setting.
|
||||
*
|
||||
* var mime = require('express/mime')
|
||||
* mime.type('png') // => 'image/png'
|
||||
* mime.type('.png') // => 'image/png'
|
||||
* mime.type('image.png') // => 'image/png'
|
||||
* mime.type('path/to/image.png') // => 'image/png'
|
||||
*
|
||||
* @param {string} path
|
||||
* @return {string}
|
||||
* @settings 'default mime type'
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.type = function(path) {
|
||||
return exports.types[path] ||
|
||||
exports.types[extname(path).substr(1)] ||
|
||||
set('default mime type') ||
|
||||
'application/octet-stream'
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
// Express - Pages - Not Found - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
var style = require('express/pages/style').style
|
||||
|
||||
exports.render = function(request) {
|
||||
request.contentType('html')
|
||||
var method = request.method.toLowerCase(),
|
||||
path = request.url.pathname || '/'
|
||||
return '<html> \n\
|
||||
<head> \n\
|
||||
<title>Express -- Not Found</title> \n\
|
||||
' + style + ' \n\
|
||||
</head> \n\
|
||||
<body> \n\
|
||||
<div id="wrapper"> \n\
|
||||
<h1>Express</h1> \n\
|
||||
<h2><em>404</em> Not Found</h2> \n\
|
||||
<p>No routes were matched, try the route below.\n\
|
||||
For restful services ensure that you use(<strong>MethodOverride</strong>).</p> \n\
|
||||
<pre><code> \n\
|
||||
' + method + '(\'' + path + '\', function(){ \n\
|
||||
// Response logic \n\
|
||||
}) \n\
|
||||
</code></pre> \n\
|
||||
</div> \n\
|
||||
</body> \n\
|
||||
</html>'
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
|
||||
// Express - Pages - Show Exceptions - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
var style = require('express/pages/style').style
|
||||
|
||||
/**
|
||||
* Return list items for exception _e_'s stack.
|
||||
*
|
||||
* @param {object} e
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function stack(e) {
|
||||
if (e.stack)
|
||||
return e.stack.split('\n').slice(1).map(function(val, i){
|
||||
if (!i)
|
||||
return '<li>' + val.replace(/^(.*?):/, '<span class="path">$1</span>:') + '</li>'
|
||||
return '<li>' + val
|
||||
.replace(/\(([^:]+)/, '(<span class="path">$1</span>')
|
||||
.replace(/(:\d+:\d+)/, '<span class="line">$1</span>') +
|
||||
'</li>'
|
||||
}).join('\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* Return table rows for _hash_.
|
||||
*
|
||||
* @param {hash} hash
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function hash(hash) {
|
||||
if (!hash || !hash.values.length) return '<tr><td class="empty" colspan="2">Empty</td></tr>'
|
||||
return hash.map(function(val, key){
|
||||
return '<tr><td>' + key + ':</td><td>' + JSON.encode(val) + '</td></tr>'
|
||||
}).join('\n')
|
||||
}
|
||||
|
||||
exports.render = function(request, e) {
|
||||
request.contentType('html')
|
||||
return '<html> \n\
|
||||
<head> \n\
|
||||
<title>Express -- ' + e + '</title> \n\
|
||||
' + style + ' \n\
|
||||
</head> \n\
|
||||
<body> \n\
|
||||
<div id="wrapper"> \n\
|
||||
<h1>Express</h1> \n\
|
||||
<h2><em>500</em> ' + e + '</h2> \n\
|
||||
<ul id="stacktrace"> \n\
|
||||
' + stack(e) + ' \n\
|
||||
</ul> \n\
|
||||
<h3>Request</h3> \n\
|
||||
<table id="request-headers"> \n\
|
||||
' + hash(request.headers) + ' \n\
|
||||
</table> \n\
|
||||
<h3>Response</h3> \n\
|
||||
<table id="response-headers"> \n\
|
||||
' + hash(request.response.headers) + ' \n\
|
||||
</table> \n\
|
||||
<h3>Params</h3> \n\
|
||||
<table id="route-params"> \n\
|
||||
' + hash(request.params) + ' \n\
|
||||
</table> \n\
|
||||
<h3>GET</h3> \n\
|
||||
<table id="get-params"> \n\
|
||||
' + hash(request.url.params) + ' \n\
|
||||
</table> \n\
|
||||
<h3>POST</h3> \n\
|
||||
<table id="post-params"> \n\
|
||||
' + hash(request.url.post) + ' \n\
|
||||
</table> \n\
|
||||
</div> \n\
|
||||
</body> \n\
|
||||
</html>'
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
|
||||
// Express - Pages - Style - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
exports.style = '<style> \n\
|
||||
body { \n\
|
||||
font-family: "Helvetica Neue", "Lucida Grande", "Arial"; \n\
|
||||
font-size: 13px; \n\
|
||||
text-align: center; \n\
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9)); \n\
|
||||
color: #555; \n\
|
||||
-webkit-text-stroke: 1px rgba(255, 255, 255, 0.1); \n\
|
||||
} \n\
|
||||
h1, h2, h3 { \n\
|
||||
margin: 0; \n\
|
||||
font-size: 22px; \n\
|
||||
color: #343434; \n\
|
||||
} \n\
|
||||
h1 em, h2 em { \n\
|
||||
padding: 0 5px; \n\
|
||||
font-weight: normal; \n\
|
||||
} \n\
|
||||
h1 { \n\
|
||||
text-shadow: 1px 2px 2px #ddd; \n\
|
||||
font-size: 60px; \n\
|
||||
} \n\
|
||||
h3 { \n\
|
||||
margin: 5px 0 10px 0; \n\
|
||||
padding-bottom: 5px; \n\
|
||||
border-bottom: 1px solid #eee; \n\
|
||||
font-size: 18px; \n\
|
||||
} \n\
|
||||
#wrapper { \n\
|
||||
margin: 50px auto; \n\
|
||||
width: 750px; \n\
|
||||
text-align: left; \n\
|
||||
} \n\
|
||||
ul { \n\
|
||||
margin: 0; \n\
|
||||
padding: 0; \n\
|
||||
} \n\
|
||||
ul li { \n\
|
||||
margin: 5px 0; \n\
|
||||
padding: 3px 8px; \n\
|
||||
list-style: none; \n\
|
||||
border: 1px solid #eee; \n\
|
||||
-webkit-border-radius: 3px; \n\
|
||||
-mox-border-radius: 3px; \n\
|
||||
-webkit-transition-property: color, padding; \n\
|
||||
-webkit-transition-duration: 0.1s; \n\
|
||||
} \n\
|
||||
ul li:hover { \n\
|
||||
padding: 3px 20px; \n\
|
||||
cursor: pointer; \n\
|
||||
color: #2E2E2E; \n\
|
||||
} \n\
|
||||
ul li .path { \n\
|
||||
padding-left: 5px; \n\
|
||||
font-weight: bold; \n\
|
||||
} \n\
|
||||
ul li .line { \n\
|
||||
padding-right: 5px; \n\
|
||||
font-style: italic; \n\
|
||||
} \n\
|
||||
ul li:first-child .path { \n\
|
||||
padding-left: 0; \n\
|
||||
} \n\
|
||||
p { \n\
|
||||
line-height: 1.5; \n\
|
||||
} \n\
|
||||
pre { \n\
|
||||
margin: 0; \n\
|
||||
padding: 10px; \n\
|
||||
border: 1px solid #eee; \n\
|
||||
-webkit-border-radius: 10px; \n\
|
||||
-moz-border-radius: 10px; \n\
|
||||
-webkit-box-shadow: 1px 1px 6px #ddd; \n\
|
||||
-moz-box-shadow: 1px 1px 6px #ddd; \n\
|
||||
} \n\
|
||||
table { \n\
|
||||
margin-bottom: 35px; \n\
|
||||
width: 100%; \n\
|
||||
border-collapse: collapse; \n\
|
||||
} \n\
|
||||
table td { \n\
|
||||
padding: 5px 10px; \n\
|
||||
font-size: 14px; \n\
|
||||
} \n\
|
||||
table tr { \n\
|
||||
border-bottom: 1px solid #fff; \n\
|
||||
} \n\
|
||||
table tr:last-child { \n\
|
||||
border-bottom: none; \n\
|
||||
} \n\
|
||||
table td:first-child { \n\
|
||||
width: 150px; \n\
|
||||
color: #343434; \n\
|
||||
} \n\
|
||||
</style> \n\
|
||||
'
|
||||
@@ -1,61 +0,0 @@
|
||||
|
||||
// Express - Plugin - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('express/utils');
|
||||
|
||||
/**
|
||||
* Push _plugin_ with _options_ to the plugin stack.
|
||||
* If _plugin_ has already been pushed, then it's options
|
||||
* will override any previously set.
|
||||
*
|
||||
* @param {Plugin} plugin
|
||||
* @param {hash} options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.use = function(plugin, options) {
|
||||
if (Express.environment === 'test' && 'init' in plugin)
|
||||
plugin.init(options)
|
||||
Express.plugins.each(function(other, i){
|
||||
if (other.klass === plugin)
|
||||
delete Express.plugins[i]
|
||||
})
|
||||
Express.plugins.push({
|
||||
klass: plugin,
|
||||
options: options
|
||||
})
|
||||
}
|
||||
|
||||
// --- Plugin
|
||||
|
||||
exports.Plugin = Class({
|
||||
|
||||
/**
|
||||
* Initialize with _options_.
|
||||
*
|
||||
* @param {hash} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
init: function(options) {
|
||||
if (options)
|
||||
utils.mixin(this, options)
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger handler for the given _event_.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @api private
|
||||
*/
|
||||
|
||||
trigger: function(event) {
|
||||
if ('on' in this)
|
||||
if (event.name in this.on)
|
||||
this.on[event.name].call(this, event)
|
||||
}
|
||||
})
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
// Express - Plugins - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
var utils = require('express/utils')
|
||||
utils.mixin(require('express/plugins/hooks'))
|
||||
utils.mixin(require('express/plugins/flash'))
|
||||
utils.mixin(require('express/plugins/cache'))
|
||||
utils.mixin(require('express/plugins/cookie'))
|
||||
utils.mixin(require('express/plugins/session'))
|
||||
utils.mixin(require('express/plugins/profiler'))
|
||||
utils.mixin(require('express/plugins/common-logger'))
|
||||
utils.mixin(require('express/plugins/content-length'))
|
||||
utils.mixin(require('express/plugins/method-override'))
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
// Express - BodyDecoder - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var queryString = require('querystring')
|
||||
|
||||
// --- BodyDecoder
|
||||
|
||||
exports.BodyDecoder = Plugin.extend({
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Decodes common content-types, currently handles:
|
||||
*
|
||||
* - application/x-www-form-urlencoded
|
||||
*/
|
||||
|
||||
request: function(event) {
|
||||
var request = event.request
|
||||
if (request.header('content-type') &&
|
||||
request.header('content-type').includes('application/x-www-form-urlencoded'))
|
||||
request.params.post = queryString.parseQuery(request.body)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,220 +0,0 @@
|
||||
|
||||
// Express - Cache - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
// --- Cache
|
||||
|
||||
var Cache = Class({
|
||||
|
||||
/**
|
||||
* Initialize cache with _key_ and _val_.
|
||||
*/
|
||||
|
||||
init: function(key, val) {
|
||||
this.key = key
|
||||
this.val = val
|
||||
this.created = Number(new Date)
|
||||
}
|
||||
})
|
||||
|
||||
// --- Store
|
||||
|
||||
exports.Store = Class({
|
||||
|
||||
/**
|
||||
* Ensure that the given _key_ is a string.
|
||||
* Override in subclass to provide data-store specific functionality.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {string} val
|
||||
* @api public
|
||||
*/
|
||||
|
||||
set: function(key, val) {
|
||||
if (typeof key !== 'string')
|
||||
throw new Error(this.name + ' store #set() key must be a string')
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure that the given _key_ is a string.
|
||||
* Override in subclass to provide data-store specific functionality.
|
||||
*
|
||||
* @param {string} key
|
||||
* @api public
|
||||
*/
|
||||
|
||||
get: function(key) {
|
||||
if (typeof key !== 'string')
|
||||
throw new Error(this.name + 'store #get() key must be a string')
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert to '[NAME Store]'.
|
||||
*
|
||||
* @return {string}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
toString: function() {
|
||||
return '[' + this.name + ' Store]'
|
||||
}
|
||||
})
|
||||
|
||||
// --- Store.Memory
|
||||
|
||||
exports.Store.Memory = exports.Store.extend({
|
||||
|
||||
/**
|
||||
* Datastore name.
|
||||
*/
|
||||
|
||||
name: 'Memory',
|
||||
|
||||
/**
|
||||
* Initialize data.
|
||||
*/
|
||||
|
||||
init: function() {
|
||||
this.data = {}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given _key_ to _val_, returning _val_.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {string} val
|
||||
* @return {string}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
set: function(key, val) {
|
||||
this.__super__(key, val)
|
||||
return this.data[key] = new Cache(key, val), val
|
||||
},
|
||||
|
||||
/**
|
||||
* Get data found matching the given _key_.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* cache.get('page:front')
|
||||
* // => '<html>...</html>'
|
||||
*
|
||||
* cache.get('page:*')
|
||||
* // => { 'page:front': '<html>...</html>',
|
||||
* 'page:users': '<html>...</html>',
|
||||
* ... }
|
||||
*
|
||||
* @param {string} key
|
||||
* @return {mixed}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
get: function(key) {
|
||||
this.__super__(key)
|
||||
if (key.indexOf('*') === -1)
|
||||
return this.data[key] instanceof Cache ?
|
||||
this.data[key].val :
|
||||
null
|
||||
var regexp = this.normalize(key)
|
||||
return this.data.reduce(function(vals, cache){
|
||||
if (regexp.test(cache.key))
|
||||
vals[cache.key] = cache.val
|
||||
return vals
|
||||
}, {})
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear data matching the given _key_.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* cache.clear('page:front')
|
||||
* cache.clear('page:*')
|
||||
*
|
||||
* @param {string} key
|
||||
* @api public
|
||||
*/
|
||||
|
||||
clear: function(key) {
|
||||
if (key.indexOf('*') === -1)
|
||||
return delete this.data[key]
|
||||
var regexp = this.normalize(key)
|
||||
for (var key in this.data)
|
||||
if (this.data.hasOwnProperty(key))
|
||||
if (regexp.test(key))
|
||||
delete this.data[key]
|
||||
},
|
||||
|
||||
/**
|
||||
* Reap caches older than _ms_.
|
||||
*
|
||||
* @param {int} ms
|
||||
* @api private
|
||||
*/
|
||||
|
||||
reap: function(ms) {
|
||||
var self = this,
|
||||
threshold = Number(new Date(Number(new Date) - ms))
|
||||
this.data.each(function(cache){
|
||||
if (cache.created < threshold)
|
||||
self.clear(cache.key)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert the given key matching _pattern_
|
||||
* into a RegExp.
|
||||
*
|
||||
* - * is converted to (.*?)
|
||||
*
|
||||
* @param {string} pattern
|
||||
* @return {regexp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
normalize: function(pattern) {
|
||||
return new RegExp('^' + pattern.replace(/[*]/g, '(.*?)') + '$')
|
||||
}
|
||||
})
|
||||
|
||||
// --- Cache
|
||||
|
||||
exports.Cache = Plugin.extend({
|
||||
extend: {
|
||||
|
||||
/**
|
||||
* Initialize memory store and start reaper.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - dataStore constructor name of cache data store, defaults to Store.Memory
|
||||
* - lifetime lifetime of cache in milliseconds, defaults to one day
|
||||
* - reapInterval, reapEvery interval in milliseconds in which to reap old caches, defaults to one hour
|
||||
*
|
||||
* @param {hash} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
init: function(options) {
|
||||
this.merge(options || {})
|
||||
this.store = new (this.dataStore || exports.Store.Memory)(options)
|
||||
Request.include({ cache: this.store })
|
||||
this.startReaper()
|
||||
},
|
||||
|
||||
/**
|
||||
* Start reaper.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
startReaper: function() {
|
||||
var self = this,
|
||||
oneDay = 86400000,
|
||||
oneHour = 3600000
|
||||
setInterval(function(){
|
||||
self.store.reap(self.lifetime || oneDay)
|
||||
}, self.reapInterval || self.reapEvery || oneHour)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,50 +0,0 @@
|
||||
|
||||
// Express - CommonLogger - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Months.
|
||||
*/
|
||||
|
||||
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
|
||||
/**
|
||||
* Format _date_.
|
||||
*
|
||||
* @param {Date} date
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function format(date) {
|
||||
var d = date.getDate(),
|
||||
m = months[date.getMonth()],
|
||||
y = date.getFullYear(),
|
||||
h = date.getHours(),
|
||||
mi = date.getMinutes(),
|
||||
s = date.getSeconds()
|
||||
return (d < 10 ? '0' : '') + d + '/' + m + '/' + y + ' ' +
|
||||
(h < 10 ? '0' : '') + h + ':' + (mi < 10 ? '0' : '') +
|
||||
mi + ':' + (s < 10 ? '0' : '') + s
|
||||
}
|
||||
|
||||
// --- CommonLogger
|
||||
|
||||
exports.CommonLogger = Plugin.extend({
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Output log data.
|
||||
*/
|
||||
|
||||
response: function(event) {
|
||||
puts([event.request.connection.remoteAddress,
|
||||
'-',
|
||||
'-',
|
||||
'[' + format(new Date) + ']',
|
||||
'"' + event.request.method.toUpperCase() + ' ' + (event.request.url.pathname || '/') +
|
||||
' HTTP/' + event.request.httpVersion + '"',
|
||||
event.request.response.status,
|
||||
event.request.response.headers['content-length'] || 0].join(' '))
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
// Express - ContentLength - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
exports.ContentLength = Plugin.extend({
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Assign Content-Length header unless present.
|
||||
*/
|
||||
|
||||
response: function(event) {
|
||||
var response = event.request.response
|
||||
response.headers['content-length'] =
|
||||
response.headers['content-length'] ||
|
||||
response.body.length
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,110 +0,0 @@
|
||||
|
||||
// Express - Cookie - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Parse an HTTP _cookie_ string into a hash.
|
||||
*
|
||||
* @param {string} cookie
|
||||
* @return {hash}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.parseCookie = function(cookie) {
|
||||
return cookie.replace(/^ *| *$/g, '').split(/ *; */).reduce(function(hash, pair){
|
||||
var parts = pair.split(/ *= */)
|
||||
hash[parts[0]] = parts[1]
|
||||
return hash
|
||||
}, {})
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile cookie _name_, _val_ and _options_ to a string.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {string} val
|
||||
* @param {hash} options
|
||||
* @return {string}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.compileCookie = function(name, val, options) {
|
||||
if (!options) return name + '=' + val
|
||||
return name + '=' + val + '; ' + options.map(function(val, key){
|
||||
if (val instanceof Date)
|
||||
val = val.toString()
|
||||
.replace(/^(\w+)/, '$1,')
|
||||
.replace(/(\w+) (\d+) (\d+)/, '$2-$1-$3')
|
||||
.replace(/GMT.*$/, 'GMT')
|
||||
return val === true ? key : key + '=' + val
|
||||
}).join('; ')
|
||||
}
|
||||
|
||||
// --- Cookie
|
||||
|
||||
exports.Cookie = Plugin.extend({
|
||||
extend: {
|
||||
|
||||
/**
|
||||
* Initialize extensions.
|
||||
*/
|
||||
|
||||
init: function() {
|
||||
Request.include({
|
||||
|
||||
/**
|
||||
* Get or set cookie values.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - path Cookie path, defaults to '/'
|
||||
* - domain Tail matched domain name such as 'vision-media.ca' or 'blog.vision-media.ca' etc
|
||||
* - expires Date object converted to 'Wdy, DD-Mon-YYYY HH:MM:SS GMT'
|
||||
* when undefined the cookie will last the duration of a the
|
||||
* client's session.
|
||||
* - secure When true the cookie will be sent by the client only when transfering data via HTTPS
|
||||
* - httpOnly When true the cookie will be sent to the server only and will not be accessable via
|
||||
* client-side scripting.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {string} val
|
||||
* @param {hash} options
|
||||
* @return {string}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
cookie: function(name, val, options) {
|
||||
options = options || {}
|
||||
options.path = options.path || '/'
|
||||
return val ?
|
||||
this.response.cookies.push(exports.compileCookie(name, val, options)) :
|
||||
this.cookies[name]
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// --- Events
|
||||
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Parse request cookie data.
|
||||
*/
|
||||
|
||||
request: function(event) {
|
||||
event.request.response.cookies = []
|
||||
event.request.cookies = event.request.headers.cookie
|
||||
? exports.parseCookie(event.request.headers.cookie)
|
||||
: {}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the Set-Cookie header when response cookies are available.
|
||||
*/
|
||||
|
||||
response: function(event) {
|
||||
if (event.response.cookies.length)
|
||||
event.request.header('set-cookie', event.response.cookies.join(', '))
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
// Express - Flash - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
exports.Flash = Plugin.extend({
|
||||
extend: {
|
||||
|
||||
/**
|
||||
* Initialize extensions.
|
||||
*/
|
||||
|
||||
init: function(){
|
||||
Request.include({
|
||||
|
||||
/**
|
||||
* Get / set flash _key_ and _val_.
|
||||
*
|
||||
* When a flash _key_ and _val_ are present,
|
||||
* it will persist in the session until outputted.
|
||||
* The _val_ pushed is returned.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* this.flash('info', 'email sent')
|
||||
* this.flash('info', 'email received')
|
||||
* this.flash('info')
|
||||
* // => ['email sent', 'email received']
|
||||
*
|
||||
* this.flash('info')
|
||||
* // => null
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {string} val
|
||||
* @return {string}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
flash: function(key, val) {
|
||||
if (!this.session.flash) this.session.flash = {}
|
||||
if (!(key in this.session.flash)) this.session.flash[key] = []
|
||||
if (val)
|
||||
return this.session.flash[key].push(val), val
|
||||
else if (key) {
|
||||
var vals = this.session.flash[key]
|
||||
delete this.session.flash[key]
|
||||
if (vals.length) return vals
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,73 +0,0 @@
|
||||
|
||||
// Express - Hooks - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Callbacks.
|
||||
*/
|
||||
|
||||
exports.callbacks = { before: [], after: [] }
|
||||
|
||||
/**
|
||||
* Add a _fn_ to be excuted before a request.
|
||||
*
|
||||
* @param {function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.before = function(fn) {
|
||||
exports.callbacks.before.push(fn)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a _fn_ to be excuted after a request.
|
||||
*
|
||||
* @param {function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.after = function(fn) {
|
||||
exports.callbacks.after.push(fn)
|
||||
}
|
||||
|
||||
// --- Hooks
|
||||
|
||||
exports.Hooks = Plugin.extend({
|
||||
extend: {
|
||||
|
||||
/**
|
||||
* Initialize extensions.
|
||||
*/
|
||||
|
||||
init: function() {
|
||||
global.merge({
|
||||
before: exports.before,
|
||||
after: exports.after
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// --- Events
|
||||
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Invoke all before handlers.
|
||||
*/
|
||||
|
||||
request: function(event) {
|
||||
exports.callbacks.before.each(function(fn){
|
||||
fn.call(event.request, event.request)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Invoke all after handlers.
|
||||
*/
|
||||
|
||||
response: function(event) {
|
||||
exports.callbacks.after.each(function(fn){
|
||||
fn.call(event.request, event.request)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
// Express - MethodOverride - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
exports.MethodOverride = Plugin.extend({
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Set request method to _method param when present.
|
||||
*/
|
||||
|
||||
request: function(event) {
|
||||
if (event.request.param('_method'))
|
||||
event.request.method = event.request.param('_method').toLowerCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
// Express - Profiler - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
var n = 0
|
||||
|
||||
exports.Profiler = Plugin.extend({
|
||||
extend: {
|
||||
|
||||
/**
|
||||
* Initialize profiler options.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - format 'plot' outputs request duration in milliseconds only
|
||||
*
|
||||
* @param {hash} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
init: function(options) {
|
||||
this.merge(options || {})
|
||||
}
|
||||
},
|
||||
|
||||
// --- Events
|
||||
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Start timer.
|
||||
*/
|
||||
|
||||
request: function(event) {
|
||||
this.start = Number(new Date)
|
||||
},
|
||||
|
||||
/**
|
||||
* Output duration.
|
||||
*/
|
||||
|
||||
response: function(event) {
|
||||
if (exports.Profiler.format === 'plot')
|
||||
puts(Number(new Date) - this.start)
|
||||
else
|
||||
puts(event.request.method + ' ' +
|
||||
event.request.url.pathname + ': ' +
|
||||
(Number(new Date) - this.start) + ' ms' +
|
||||
' #' + ++n)
|
||||
}
|
||||
}
|
||||
})
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário