Comparar commits
801 Commits
2.3.5
...
3.0.0alpha1
| Autor | SHA1 | Data | |
|---|---|---|---|
| d1d3f310e9 | |||
| 089a83363f | |||
| c28e6db428 | |||
| 05253272cb | |||
| 12e087820c | |||
| 8dc001567b | |||
| 9af3256f72 | |||
| cdd333a2e0 | |||
| aa4ec8f3e2 | |||
| 5ea78cf259 | |||
| 600eaea2d1 | |||
| 81b15833f7 | |||
| 9abc221559 | |||
| 7048be2830 | |||
| 91eb27513a | |||
| 04f0682439 | |||
| 36bab5408d | |||
| c483dab4b8 | |||
| f1d759f279 | |||
| 4c1afb2984 | |||
| db9b2bfbe1 | |||
| 377677cf30 | |||
| 24a4e95ffe | |||
| 8fdd9e967a | |||
| acfa6a692e | |||
| 67ca22b6e4 | |||
| ba413ee98d | |||
| acc0e934cb | |||
| 1d485840fd | |||
| dcb147608a | |||
| ddf24d1fd6 | |||
| 886d7e6903 | |||
| 2079ccbf42 | |||
| 5ec88b0f6c | |||
| b0bcd27124 | |||
| 4dfee21e91 | |||
| 18fa2c9c7d | |||
| 04d43d60b7 | |||
| 419731ec41 | |||
| 082ba88084 | |||
| 09a8474521 | |||
| 6d323d3ff7 | |||
| c4e003518a | |||
| 9e251d14af | |||
| 9abba7d69a | |||
| 0377540e2d | |||
| e6a15f66fc | |||
| 1787fd1b52 | |||
| 54c3d5c113 | |||
| 6d0f9a37a2 | |||
| 60dac4d2ff | |||
| dd468fbe9a | |||
| 04ecf04832 | |||
| 6d45616a7a | |||
| 06d2016ee7 | |||
| 984bfadcdd | |||
| f79f3f8b22 | |||
| ba570a9842 | |||
| 365a98d00f | |||
| 4e2677fe2c | |||
| d6d16b7899 | |||
| 86a9e0803a | |||
| fdf96922b5 | |||
| d396761f76 | |||
| 711519361c | |||
| e4827b8d89 | |||
| 7ec7cb94f9 | |||
| 298899d02c | |||
| 43b35a4ae0 | |||
| a7a8dcd617 | |||
| bdf0b26a12 | |||
| 73e87b6a2e | |||
| ac3d002cb2 | |||
| ada2d0c627 | |||
| 286d3a1ff8 | |||
| 937f01a225 | |||
| c9559e03da | |||
| d115798d5b | |||
| b6ee5fafd0 | |||
| 533b31237c | |||
| 812a470122 | |||
| eb3105ef25 | |||
| ffcaa04d2c | |||
| a47660ba67 | |||
| e2291184dc | |||
| 4e332452b7 | |||
| e2f43df5e9 | |||
| 141929cd6e | |||
| ec03968bd4 | |||
| a21435cb05 | |||
| bdfa6d1fe7 | |||
| b565e258cb | |||
| 892b605ab5 | |||
| 4d99352526 | |||
| cbf0eaa429 | |||
| 80e16c8ca3 | |||
| 0ae024afa8 | |||
| 73caacbd42 | |||
| b667bda8f2 | |||
| 463e38cf67 | |||
| 83c8d65e3d | |||
| 9548e7d1e2 | |||
| ee290d82d1 | |||
| b75bb003bd | |||
| 6c2194fdb4 | |||
| da61d8b639 | |||
| 863ba199f6 | |||
| 161ebb354f | |||
| 1516ebf7f9 | |||
| 2820f2227d | |||
| a078f5f5c1 | |||
| d0a83053d3 | |||
| b6bc01abde | |||
| 196a1eb6ad | |||
| 593271f536 | |||
| 0f24f715ba | |||
| bb9bfa5618 | |||
| 8120a06cd6 | |||
| a153082120 | |||
| 970031e267 | |||
| a819856f3f | |||
| 4dbaaa2855 | |||
| 0593cf4379 | |||
| cd0e5dbb4c | |||
| 7cb1c3cabb | |||
| 550b9101b8 | |||
| 9d9564568b | |||
| 7ea7a53e7c | |||
| ac387caf21 | |||
| ad3f1e84aa | |||
| 2432a0dda5 | |||
| 03e5919910 | |||
| 277e35f8c8 | |||
| 0dd5836f3f | |||
| 9290f0d407 | |||
| 9bd3ad846e | |||
| a8c73649ce | |||
| 6368ab49b4 | |||
| 16b6a64ef9 | |||
| e46431ee0e | |||
| 2e4cf0aa5c | |||
| 3f8a7f05e8 | |||
| 3360613bcd | |||
| f8a9cbe074 | |||
| 15f2e0c899 | |||
| 6518e746c1 | |||
| 38b046d6ad | |||
| 28d7750eda | |||
| e5fc85bddc | |||
| 2a40571118 | |||
| f1aa57c57e | |||
| 0b876ece41 | |||
| ca0bd1a0b5 | |||
| 2d31b5df34 | |||
| 10f7ca0ebf | |||
| 85d6964874 | |||
| 76fd462bcc | |||
| c44f01879f | |||
| fe27989a69 | |||
| b04f3eeede | |||
| 6ab61d023f | |||
| 4d87efc771 | |||
| e47d368239 | |||
| 5b1235addc | |||
| 8c2c1240e1 | |||
| 27e696b7b1 | |||
| bfba98f532 | |||
| 8de3ad50b2 | |||
| 2ba343d2b5 | |||
| ff92afa557 | |||
| c3c0fb95a8 | |||
| bb56a094bb | |||
| 2211943170 | |||
| 4eb8bc0857 | |||
| fa51cb8d63 | |||
| 706dec93a4 | |||
| 7a32920448 | |||
| 57a3899c1d | |||
| 374d159e0e | |||
| 4f5a41b84f | |||
| a2f380fdd6 | |||
| 301085e510 | |||
| af5b64a434 | |||
| fa088e37bc | |||
| 613bdc91e5 | |||
| edfe50e713 | |||
| 26fb403ced | |||
| 014fb46449 | |||
| 144a88b109 | |||
| 34c0d2509a | |||
| a12a9e3fd9 | |||
| 8df73f3d83 | |||
| 6dac874ff4 | |||
| 81d25f6861 | |||
| c0c1975da6 | |||
| dd7af29103 | |||
| 85ea5f67f4 | |||
| 8e3cb6174d | |||
| 6c01e9a43a | |||
| 6061670161 | |||
| 7c66db2c45 | |||
| 05e95ae55a | |||
| 416ad564d0 | |||
| 55f8f9bc42 | |||
| 386a9e88b4 | |||
| f6ca25edbe | |||
| 1ea221aa4e | |||
| d72a6666a1 | |||
| b69199f884 | |||
| 65042c86a6 | |||
| d7dccfd56d | |||
| e60f4a5e1e | |||
| fa3d4cbb23 | |||
| 56d303ec09 | |||
| 4600548b4d | |||
| 7d24c2ba40 | |||
| b4ce57caec | |||
| 43c09b2eaa | |||
| b32fd0bee4 | |||
| 3b6e96efa9 | |||
| 29ef828b9c | |||
| 39ae443433 | |||
| c30c2f8d38 | |||
| 5757f875f2 | |||
| e49c482a3f | |||
| a592d6c1aa | |||
| 88f154fecd | |||
| d7dfe3e812 | |||
| 489265e3ca | |||
| 3212a70a0c | |||
| 1cda0a96ca | |||
| 83fb9f7548 | |||
| 43295289bf | |||
| 0f72ca823b | |||
| 41786bc776 | |||
| cca5d7ebbf | |||
| 43c8764465 | |||
| a1e325a2d9 | |||
| 17a831e32f | |||
| 2a13db3bb8 | |||
| eb5a73538a | |||
| 006a6c787b | |||
| c3d96df0f0 | |||
| 15e7218bc4 | |||
| 28f32b9b8e | |||
| 1d0a56b673 | |||
| ad1424681b | |||
| 87b991c076 | |||
| 5d593f26af | |||
| 853c270fce | |||
| fcf34e0587 | |||
| b6611c8a3b | |||
| aab08d774b | |||
| 321aa52384 | |||
| 1334a74ef1 | |||
| 19e3384bb1 | |||
| 6ae32fd596 | |||
| 4c316ba4ce | |||
| f2719411b7 | |||
| 11faf6684e | |||
| 547d18ce46 | |||
| f183a81289 | |||
| e44c874cab | |||
| 9c7380efe4 | |||
| 5e071a2e4b | |||
| ff9b82c4f6 | |||
| a0d0ac6cff | |||
| b605a5de87 | |||
| 36be2b0688 | |||
| 376a5da705 | |||
| c25258b75c | |||
| c685f3a294 | |||
| f63767af0e | |||
| 4fa9a2e54b | |||
| 68bc592a05 | |||
| 543fe2f2a4 | |||
| be52f38d8f | |||
| 722a92f374 | |||
| d771d06e19 | |||
| a5227191b5 | |||
| 499d3d6d78 | |||
| 2adf020753 | |||
| e8c373694c | |||
| a8fd8cb645 | |||
| fd06084106 | |||
| 285500488d | |||
| 29d4ffd089 | |||
| fe5efa597b | |||
| b93629a903 | |||
| 0c72940933 | |||
| 96f5279e3e | |||
| 821fa10203 | |||
| 9082e74971 | |||
| 7a7d77e7bd | |||
| ce2ec94e96 | |||
| d56e5d6923 | |||
| 5221ecc055 | |||
| 6ac2c6f578 | |||
| 772b752fa5 | |||
| 3c002d08c2 | |||
| 2876424240 | |||
| 74a0177ec9 | |||
| da96844e9a | |||
| 81652c8244 | |||
| f17434c95b | |||
| 01e854b5d2 | |||
| 42953c7c44 | |||
| 5e56446d26 | |||
| 61652f4ad9 | |||
| fc1e84941d | |||
| 953eba0376 | |||
| 5c032269e3 | |||
| 1322d5a2c1 | |||
| 114f272906 | |||
| 1286bbb982 | |||
| 9141c649e7 | |||
| ff2242da31 | |||
| 730a419984 | |||
| 25bd7d7997 | |||
| 77c9d9207d | |||
| 1e77629f1f | |||
| 76f65456ab | |||
| 26e20e7ae5 | |||
| 96217cf3fe | |||
| e9c96d8ccd | |||
| 7ae2b968bb | |||
| 83ea42afe5 | |||
| 16587fcce1 | |||
| ffded44f32 | |||
| 92c5284b80 | |||
| f96102224c | |||
| bf87d626eb | |||
| e21a79dc61 | |||
| caec590fe1 | |||
| 61ce6c59c2 | |||
| 205a1a14c7 | |||
| 6709ab5f27 | |||
| 2d77279c94 | |||
| e9d7b6fbad | |||
| 3e6171c7ff | |||
| 04389fd6ff | |||
| a47b599048 | |||
| 58eddd5ab4 | |||
| 7ac857acef | |||
| e27b224933 | |||
| 4f087df286 | |||
| 87f6f6a3e3 | |||
| 94d1e94cf2 | |||
| d249868e07 | |||
| 429e48d873 | |||
| abb414c702 | |||
| 8f45dd4190 | |||
| d9098c5fcd | |||
| b9dee730a8 | |||
| 26c62a667f | |||
| 7d42ad00ff | |||
| 4a5776b513 | |||
| f68ba2ef35 | |||
| a95a0ab5f9 | |||
| 30911f4a75 | |||
| c9f184c8d5 | |||
| 545f1fd07d | |||
| 2f762265a8 | |||
| 7e6d8f39b4 | |||
| bea74b7711 | |||
| 10e8dc57eb | |||
| f7b6dde086 | |||
| 2fa36fa721 | |||
| 40f8202402 | |||
| 4b0b55c1b7 | |||
| 0e395973c9 | |||
| 1f53cdb62d | |||
| c32023d8ed | |||
| d2f98940d8 | |||
| 536b16c7a9 | |||
| 9bfeae2df1 | |||
| 4d450ea25e | |||
| 84f01d1e30 | |||
| 1a5636b199 | |||
| af46df7eae | |||
| 801a1791d6 | |||
| 333cf0b280 | |||
| 52e26697a9 | |||
| fdf620b688 | |||
| 66f8ca52d6 | |||
| f98c1127a6 | |||
| 7e352fe28d | |||
| d3b48e2fd5 | |||
| 23159c094d | |||
| 2e22887f71 | |||
| c9b04b8be7 | |||
| 2c0e13b513 | |||
| 2937309f00 | |||
| 377056a33c | |||
| f42ce5be2b | |||
| ddeee9b6db | |||
| 6bee32c174 | |||
| 11f55a06dd | |||
| 6a2d6b872b | |||
| d8787867c4 | |||
| 43d9f6ea17 | |||
| 1faba1302f | |||
| 55ee0a0934 | |||
| 0653f73779 | |||
| 7a24021dc9 | |||
| 9f2fe94484 | |||
| a3950b5638 | |||
| 8c03428279 | |||
| f4d7ea386d | |||
| bee0496cb1 | |||
| 5960b90efe | |||
| 0f2f3d4e29 | |||
| bc673bef79 | |||
| 3fb7391b97 | |||
| 442cd7515d | |||
| a013ffe547 | |||
| 835558229f | |||
| dce23c79a1 | |||
| 4106bae79e | |||
| b756474d9d | |||
| b0c9209726 | |||
| c96b778771 | |||
| d0d721d80b | |||
| 7b50a78662 | |||
| aa869c637a | |||
| f467fe1cbf | |||
| 15fd639cd9 | |||
| f96f2cf56e | |||
| b0f6278cea | |||
| ae7bac9a6b | |||
| c8997204d4 | |||
| a2c51984a8 | |||
| ed93e33d59 | |||
| 6e15b1cd20 | |||
| cc2513facf | |||
| e303dcc915 | |||
| 8ad17abb7b | |||
| 5b296b5257 | |||
| 1a5c32f3ef | |||
| a15e745d42 | |||
| d17dd3e3d8 | |||
| 51a5c829bb | |||
| 8a91749e12 | |||
| 42fc0f9ee8 | |||
| 17ccd55d11 | |||
| b8a589d76f | |||
| becf6d9413 | |||
| 9efc4b23dc | |||
| 6b1dc31759 | |||
| 9205d632cc | |||
| a751346b20 | |||
| 8111a19307 | |||
| 860b4f1a3b | |||
| a5b1aa9ca7 | |||
| 62257bce18 | |||
| 0ed74aa68b | |||
| e0bd0d6470 | |||
| b433550556 | |||
| 04ebd8875b | |||
| 1a1ed0ae45 | |||
| d6fabb6f8e | |||
| 08e8194db1 | |||
| 0e4e050b21 | |||
| de17b285b1 | |||
| f640d0973d | |||
| 47ff0dc0cc | |||
| 965e1d63dc | |||
| 73f1da2ff7 | |||
| 0f6ad43e91 | |||
| 8d804a6c4a | |||
| 02f48aabbf | |||
| d4b08e9566 | |||
| 9f1f58fd4b | |||
| 4ed92d50e0 | |||
| 8848004cb7 | |||
| 371b381074 | |||
| 6d47011dcf | |||
| 705cdb6368 | |||
| 90fc80fd87 | |||
| 041974ee01 | |||
| 7369d861ca | |||
| e1da383aed | |||
| 6bcf29152f | |||
| 8a38211bd9 | |||
| cb2b9feb5f | |||
| c2d5d5619b | |||
| 76b7d6975f | |||
| 7e9186d1ae | |||
| d1ce4c9923 | |||
| fed7fa4cd2 | |||
| 0d0125fc29 | |||
| 98e2c0522f | |||
| 294bc8c1d7 | |||
| ae11d83684 | |||
| aab9b08ec2 | |||
| 31ff7db019 | |||
| c40c54fbee | |||
| cecbaf2efe | |||
| e90413243e | |||
| a9396efeaf | |||
| 60353c6d05 | |||
| 7b5ed50786 | |||
| 02baa2b17c | |||
| d0585bd910 | |||
| adf7124446 | |||
| 7710db4591 | |||
| ce03cf49d8 | |||
| 65c0d14a4e | |||
| 667ed6fcf5 | |||
| d7da40642d | |||
| d6b5047511 | |||
| 3b5a751b25 | |||
| 8a7491c97a | |||
| b3cab31cf7 | |||
| 021655a10a | |||
| e301d43704 | |||
| 54c1a208c3 | |||
| ad9bbda708 | |||
| 341e167eab | |||
| fb031d1ad5 | |||
| d3937b9a61 | |||
| 2c734e2e4c | |||
| 77d8823261 | |||
| 6f85c14738 | |||
| edb1dc067a | |||
| 6b161d5389 | |||
| c21e3feaa6 | |||
| a25ef01da3 | |||
| 0534266490 | |||
| 71aca3c199 | |||
| 72fab80a74 | |||
| c8ab058842 | |||
| b166fd7d6e | |||
| 9545face97 | |||
| 6dacd51b81 | |||
| 571a182712 | |||
| e3aabdc2bc | |||
| 4d8d5b12f2 | |||
| 5785e7e2e5 | |||
| 81f311105c | |||
| ad3679fcb8 | |||
| 29508f1cc7 | |||
| 426ba62348 | |||
| d2df055abe | |||
| d3ccdbcf72 | |||
| 7a476fc964 | |||
| 5da28be2b2 | |||
| 0932bdea30 | |||
| 75054e17cf | |||
| 664907f02e | |||
| f977272732 | |||
| d10b7b43ea | |||
| e9abe1b846 | |||
| cc21f38664 | |||
| 34606c26f0 | |||
| be9d66a574 | |||
| ed9fcde499 | |||
| 3c2139b0c3 | |||
| 7eeec91ab5 | |||
| fdd43ee448 | |||
| ca75492512 | |||
| a2a7644794 | |||
| 91aebc758c | |||
| ca0d29d811 | |||
| c8c6aa2a1f | |||
| 19a1a22e63 | |||
| c729d62f89 | |||
| 1793b50e6b | |||
| 23dbe6a5f0 | |||
| 509601e617 | |||
| d58beed752 | |||
| fd5d1076dc | |||
| 05b76a1f93 | |||
| f84ec803a4 | |||
| c35cd7fcb7 | |||
| bb9d50579b | |||
| 54d37512f5 | |||
| c516be8c4b | |||
| 82c78ec8f9 | |||
| b1d4b71609 | |||
| 7440c7ddc7 | |||
| 624dad5a78 | |||
| f4080210bd | |||
| c631eb43e3 | |||
| 376bedf624 | |||
| 36e9c02f6f | |||
| 8f798569a8 | |||
| 8c0e47baf9 | |||
| 461473e48e | |||
| 8b1f109c1d | |||
| e005cb31d8 | |||
| 579836e221 | |||
| b977ee6160 | |||
| ddce65b9dd | |||
| e0e1105965 | |||
| 1f520f9f99 | |||
| 05a929deb6 | |||
| 5ac5352e33 | |||
| 787a555253 | |||
| 388b84e858 | |||
| 7ffd17254a | |||
| 00affe187c | |||
| 05844efbd6 | |||
| 3ab37028fc | |||
| 3a04888c5f | |||
| 6bd518241a | |||
| a3cddb856f | |||
| 4b8e08d202 | |||
| 9413d30396 | |||
| 5982fa63c6 | |||
| a4621a6418 | |||
| 7eec21a5e6 | |||
| 96b72fe2f7 | |||
| c7c9606e87 | |||
| 772c135d98 | |||
| 365b3a76ba | |||
| 41568b7f2a | |||
| d853f6cf0e | |||
| bcfcce32d3 | |||
| 986916cf3e | |||
| d689656775 | |||
| 8c56df7322 | |||
| 1dc87761a0 | |||
| cd88b92587 | |||
| eab03fdfc4 | |||
| 9a8b86872d | |||
| 04ce039ba4 | |||
| 9605cbda45 | |||
| 3ec2739925 | |||
| d250bf9b56 | |||
| 6ebccb0518 | |||
| b30efe4e2f | |||
| c275d279fc | |||
| 7237a3c3b6 | |||
| f98896f6d7 | |||
| bcb2cdae4c | |||
| 08159211a3 | |||
| 232b6ab7ef | |||
| 3d2676d013 | |||
| 477d06f990 | |||
| ed19885ba1 | |||
| 297ae6fdb4 | |||
| 456a985666 | |||
| 261203d6c1 | |||
| 31262d2ea9 | |||
| c72abc5293 | |||
| 93189ad0b6 | |||
| a8930b161e | |||
| fa31d45285 | |||
| 914e4a4cf7 | |||
| f36d079f28 | |||
| 17ddeef3ba | |||
| f0c90ce668 | |||
| f19b312c48 | |||
| e899a54ba7 | |||
| a4db994c2f | |||
| f98f46c836 | |||
| 336aaaec9a | |||
| b13ec8526e | |||
| 541020ff1b | |||
| 9c153737b4 | |||
| 7d53bb4064 | |||
| 4670751479 | |||
| 8e058f16e4 | |||
| f519f0a5b3 | |||
| bb61304a49 | |||
| 781d991eac | |||
| d04c1f93a3 | |||
| c0aab36187 | |||
| 5ae994ee8f | |||
| 60d16eab77 | |||
| fc60dfc1a6 | |||
| 45d149c146 | |||
| 4dfc1a69c3 | |||
| 0ae18bca60 | |||
| 2aaf0defe7 | |||
| 73ea5cd7ee | |||
| e7f2d229ec | |||
| 87bc265817 | |||
| 796aaff295 | |||
| 8f87c50320 | |||
| ee4471b345 | |||
| 6815feb8cf | |||
| dbbe7be891 | |||
| 09c9452e5c | |||
| b0e669ba00 | |||
| f46ae9f3b2 | |||
| 9f2b344be8 | |||
| 6b47271679 | |||
| 6f7075be74 | |||
| 4b9cc3d698 | |||
| 3faa790b53 | |||
| 9477c9b516 | |||
| b04be51848 | |||
| 9e4020efd3 | |||
| 6db19db665 | |||
| 1386f80ae5 | |||
| e4342a7097 | |||
| fda31b75f9 | |||
| 8ca0a45b33 | |||
| ce2bcaef68 | |||
| 0db7f26ad3 | |||
| 35370da458 | |||
| fe6c5832c2 | |||
| e8c32df79c | |||
| 652e166462 | |||
| af6385f8e4 | |||
| f0277d3777 | |||
| 6bb100d7fa | |||
| f13ea34de3 | |||
| 48a14a443a | |||
| 1820ea6f59 | |||
| 4d9647923e | |||
| 943e9b3a28 | |||
| 6b2ec50a0b | |||
| 7b813b95b6 | |||
| cdaa2e78d7 | |||
| add53d3222 | |||
| f4f79d2217 | |||
| aa36bc4516 | |||
| 9028cacfd1 | |||
| 40ccb595cd | |||
| 5606d08ecb | |||
| 1888d6fca1 | |||
| 5d16e6b302 | |||
| 96f7574bc1 | |||
| 490584c8bc | |||
| 0cbb1f661c | |||
| 3dc53e105a | |||
| e2cdd760d8 | |||
| 4169202a41 | |||
| 835982c561 | |||
| b67bacea18 | |||
| 3205ee7d75 | |||
| ff7d5ff4e5 | |||
| 723774af27 | |||
| c3fbd3fe10 | |||
| d1d3871550 | |||
| 5462c8c7ec | |||
| 9536341e30 | |||
| 1bb798d963 | |||
| 91997e9c53 | |||
| 1393187040 | |||
| 6e69c880d9 | |||
| 59dcd03972 | |||
| 11482546a2 | |||
| 1ce43dd347 | |||
| d1bfe137d4 | |||
| 9d7452cdc2 | |||
| d9cee90efc | |||
| 175aa08500 | |||
| c9ff6198d3 | |||
| f026218c82 | |||
| 5bc86b9e29 | |||
| 5830ac9936 | |||
| d7c6c9a9f9 | |||
| 9c87eed60e | |||
| f15eb6d5ef | |||
| 5b33788359 | |||
| 11ec3ccd48 | |||
| 9d498ba3f1 | |||
| 15d4047180 | |||
| 44eae73843 | |||
| d5b1c70731 | |||
| e78dc18cfd | |||
| 4d122923e9 | |||
| b1a7310263 | |||
| d6ef90d98d | |||
| 85df59ac31 | |||
| b789a28581 | |||
| 4068e7f444 | |||
| 80e9ffbf5d | |||
| 610fc92ca3 | |||
| 0f5dc9bdb2 | |||
| c24b2faec5 | |||
| c407f58dc2 | |||
| 380da0e202 | |||
| 9e5e7a1526 | |||
| 9016b5aaae | |||
| 45f168e873 | |||
| 799938683d | |||
| 7128f2d11f | |||
| 0634bf0b0d | |||
| f9e48c2972 | |||
| 909960c0b3 | |||
| 8a7876f4d1 | |||
| 286c92b13b | |||
| b9872a278f | |||
| 1b34fd7efa | |||
| f05c351762 | |||
| 8323f19e96 | |||
| 565eda9ee5 | |||
| 7aea7194d1 | |||
| 2f68957c8c | |||
| 4ca848e526 | |||
| 31a8c7c19c | |||
| f1c435e050 | |||
| fac75a9bff | |||
| 4fe03ab223 | |||
| c6122da59b | |||
| 127f77964e |
+7
-1
@@ -1,3 +1,4 @@
|
||||
coverage.html
|
||||
.DS_Store
|
||||
lib-cov
|
||||
*.seed
|
||||
@@ -9,4 +10,9 @@ lib-cov
|
||||
*.swp
|
||||
*.swo
|
||||
benchmarks/graphs
|
||||
testing.js
|
||||
testing
|
||||
node_modules/
|
||||
testing
|
||||
.coverage_data
|
||||
cover_html
|
||||
test.js
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
[submodule "support/expresso"]
|
||||
path = support/expresso
|
||||
url = git://github.com/visionmedia/expresso.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
|
||||
[submodule "support/should"]
|
||||
path = support/should
|
||||
url = git://github.com/visionmedia/should.js.git
|
||||
[submodule "support/formidable"]
|
||||
path = support/formidable
|
||||
url = git://github.com/felixge/node-formidable.git
|
||||
[submodule "support/jade"]
|
||||
path = support/jade
|
||||
url = git://github.com/visionmedia/jade.git
|
||||
[submodule "support/qs"]
|
||||
path = support/qs
|
||||
url = git://github.com/visionmedia/node-querystring.git
|
||||
[submodule "support/mime"]
|
||||
path = support/mime
|
||||
url = https://github.com/bentomas/node-mime.git
|
||||
|
||||
@@ -5,3 +5,4 @@ support/
|
||||
test/
|
||||
testing.js
|
||||
.DS_Store
|
||||
coverage.html
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.6
|
||||
+103
@@ -1,4 +1,107 @@
|
||||
|
||||
2.4.5 / 2011-08-19
|
||||
==================
|
||||
|
||||
* Added support for routes to handle errors. Closes #809
|
||||
* Added `app.routes.all()`. Closes #803
|
||||
* Added "basepath" setting to work in conjunction with reverse proxies etc. * Refactored `Route` to use a single array of callbacks
|
||||
* Added support for multiple callbacks for `app.param()`. Closes #801
|
||||
Closes #805
|
||||
* Changed: removed .call(self) for route callbacks
|
||||
* Dependency: `qs >= 0.3.1`
|
||||
* Fixed `res.redirect()` on windows due to `join()` usage. Closes #808
|
||||
|
||||
2.4.4 / 2011-08-05
|
||||
==================
|
||||
|
||||
* Fixed `res.header()` intention of a set, even when `undefined`
|
||||
* Fixed `*`, value no longer required
|
||||
* Fixed `res.send(204)` support. Closes #771
|
||||
|
||||
2.4.3 / 2011-07-14
|
||||
==================
|
||||
|
||||
* Added docs for `status` option special-case. Closes #739
|
||||
* Fixed `options.filename`, exposing the view path to template engines
|
||||
|
||||
2.4.2. / 2011-07-06
|
||||
==================
|
||||
|
||||
* Revert "removed jsonp stripping" for XSS
|
||||
|
||||
2.4.1 / 2011-07-06
|
||||
==================
|
||||
|
||||
* Added `res.json()` JSONP support. Closes #737
|
||||
* Added _extending-templates_ example. Closes #730
|
||||
* Added "strict routing" setting for trailing slashes
|
||||
* Added support for multiple envs in `app.configure()` calls. Closes #735
|
||||
* Changed: `res.send()` using `res.json()`
|
||||
* Changed: when cookie `path === null` don't default it
|
||||
* Changed; default cookie path to "home" setting. Closes #731
|
||||
* Removed _pids/logs_ creation from express(1)
|
||||
|
||||
2.4.0 / 2011-06-28
|
||||
==================
|
||||
|
||||
* Added chainable `res.status(code)`
|
||||
* Added `res.json()`, an explicit version of `res.send(obj)`
|
||||
* Added simple web-service example
|
||||
|
||||
2.3.12 / 2011-06-22
|
||||
==================
|
||||
|
||||
* \#express is now on freenode! come join!
|
||||
* Added `req.get(field, param)`
|
||||
* Added links to Japanese documentation, thanks @hideyukisaito!
|
||||
* Added; the `express(1)` generated app outputs the env
|
||||
* Added `content-negotiation` example
|
||||
* Dependency: connect >= 1.5.1 < 2.0.0
|
||||
* Fixed view layout bug. Closes #720
|
||||
* Fixed; ignore body on 304. Closes #701
|
||||
|
||||
2.3.11 / 2011-06-04
|
||||
==================
|
||||
|
||||
* Added `npm test`
|
||||
* Removed generation of dummy test file from `express(1)`
|
||||
* Fixed; `express(1)` adds express as a dep
|
||||
* Fixed; prune on `prepublish`
|
||||
|
||||
2.3.10 / 2011-05-27
|
||||
==================
|
||||
|
||||
* Added `req.route`, exposing the current route
|
||||
* Added _package.json_ generation support to `express(1)`
|
||||
* Fixed call to `app.param()` function for optional params. Closes #682
|
||||
|
||||
2.3.9 / 2011-05-25
|
||||
==================
|
||||
|
||||
* Fixed bug-ish with `../' in `res.partial()` calls
|
||||
|
||||
2.3.8 / 2011-05-24
|
||||
==================
|
||||
|
||||
* Fixed `app.options()`
|
||||
|
||||
2.3.7 / 2011-05-23
|
||||
==================
|
||||
|
||||
* Added route `Collection`, ex: `app.get('/user/:id').remove();`
|
||||
* Added support for `app.param(fn)` to define param logic
|
||||
* Removed `app.param()` support for callback with return value
|
||||
* Removed module.parent check from express(1) generated app. Closes #670
|
||||
* Refactored router. Closes #639
|
||||
|
||||
2.3.6 / 2011-05-20
|
||||
==================
|
||||
|
||||
* Changed; using devDependencies instead of git submodules
|
||||
* Fixed redis session example
|
||||
* Fixed markdown example
|
||||
* Fixed view caching, should not be enabled in development
|
||||
|
||||
2.3.5 / 2011-05-20
|
||||
==================
|
||||
|
||||
|
||||
+12
-32
@@ -1,39 +1,19 @@
|
||||
|
||||
DOCS = $(shell find docs/*.md)
|
||||
HTMLDOCS =$(DOCS:.md=.html)
|
||||
REPORTER = dot
|
||||
|
||||
test:
|
||||
@NODE_ENV=test ./support/expresso/bin/expresso \
|
||||
-I lib \
|
||||
-I support \
|
||||
-I support/connect/lib \
|
||||
-I support/haml/lib \
|
||||
-I support/jade/lib \
|
||||
-I support/ejs/lib \
|
||||
$(TESTFLAGS) \
|
||||
test/*.test.js
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER)
|
||||
|
||||
test-cov:
|
||||
@TESTFLAGS=--cov $(MAKE) test
|
||||
test-acceptance:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter spec \
|
||||
test/acceptance/*.js
|
||||
|
||||
docs: $(HTMLDOCS)
|
||||
@ echo "... generating TOC"
|
||||
@./support/toc.js docs/guide.html
|
||||
test-cov: lib-cov
|
||||
@EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
|
||||
|
||||
%.html: %.md
|
||||
@echo "... $< -> $@"
|
||||
@markdown $< \
|
||||
| cat docs/layout/head.html - docs/layout/foot.html \
|
||||
> $@
|
||||
lib-cov:
|
||||
@jscoverage lib lib-cov
|
||||
|
||||
site:
|
||||
rm -fr /tmp/docs \
|
||||
&& cp -fr docs /tmp/docs \
|
||||
&& git checkout gh-pages \
|
||||
&& cp -fr /tmp/docs/* . \
|
||||
&& echo "done"
|
||||
|
||||
docclean:
|
||||
rm -f docs/*.{1,html}
|
||||
|
||||
.PHONY: site test test-cov docs docclean
|
||||
.PHONY: site test test-acceptance
|
||||
|
||||
+129
-53
@@ -1,86 +1,162 @@
|
||||
|
||||
# Express
|
||||
|
||||
Insanely fast (and small) server-side JavaScript web development framework
|
||||
built on [node](http://nodejs.org) and [Connect](http://github.com/senchalabs/connect).
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||

|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
|
||||
|
||||
```js
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
$ npm install express
|
||||
$ npm install -g express
|
||||
|
||||
or to access the `express(1)` executable install globally:
|
||||
## Quick Start
|
||||
|
||||
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:
|
||||
|
||||
Create the app:
|
||||
|
||||
$ npm install -g express
|
||||
$ express /tmp/foo && cd /tmp/foo
|
||||
|
||||
Install dependencies:
|
||||
|
||||
$ npm install
|
||||
|
||||
Start the server:
|
||||
|
||||
$ node app
|
||||
|
||||
## Features
|
||||
|
||||
* Built on [Connect](http://github.com/senchalabs/connect)
|
||||
* Robust routing
|
||||
* Redirection helpers
|
||||
* Dynamic view helpers
|
||||
* HTTP helpers (redirection, caching, etc)
|
||||
* View system supporting 14+ template engines
|
||||
* 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)
|
||||
* High test coverage
|
||||
* Executable for generating applications quickly
|
||||
* Application level view options
|
||||
* High test coverage
|
||||
|
||||
Via Connect:
|
||||
## Philosophy
|
||||
|
||||
* Session support
|
||||
* Cache API
|
||||
* Mime helpers
|
||||
* ETag support
|
||||
* Persistent flash notifications
|
||||
* Cookie support
|
||||
* JSON-RPC
|
||||
* Logging
|
||||
* and _much_ more!
|
||||
|
||||
## 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))
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers. Making
|
||||
it a great solution for single page applications, web sites, hybrids, or public
|
||||
HTTP APIs.
|
||||
|
||||
Built on Connect you can use _only_ what you need, and nothing more, applications
|
||||
can be as big or as small as you like, even a single file. Express does
|
||||
not force you to use any specific ORM or template engine. With support for over
|
||||
14 template engines via [Consolidate.js](github.com/visionmedia/consolidate.js) you
|
||||
can quickly craft your perfect framework.
|
||||
|
||||
## More Information
|
||||
|
||||
* [express-expose](http://github.com/visionmedia/express-expose) expose objects, functions, modules and more to client-side js with ease
|
||||
* [express-configure](http://github.com/visionmedia/express-configuration) async configuration support
|
||||
* [express-messages](http://github.com/visionmedia/express-messages) flash notification rendering helper
|
||||
* [express-namespace](http://github.com/visionmedia/express-namespace) namespaced route support
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* Join #express on freenode
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* Screencast - [Introduction](http://bit.ly/eRYu0O)
|
||||
* Screencast - [View Partials](http://bit.ly/dU13Fx)
|
||||
* Screencast - [Route Specific Middleware](http://bit.ly/hX4IaH)
|
||||
* Screencast - [Route Path Placeholder Preconditions](http://bit.ly/eNqmVs)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* [Русскоязычная документация](http://express-js.ru/)
|
||||
|
||||
## Node Compatibility
|
||||
## Viewing Examples
|
||||
|
||||
Express 1.x is compatible with node 0.2.x and connect < 1.0.
|
||||
First install the dev dependencies to install all the example / test suite deps:
|
||||
|
||||
Express 2.x is compatible with node 0.4.x and connect 1.x
|
||||
$ cd express
|
||||
$ npm install -d
|
||||
|
||||
then run whichever tests you want:
|
||||
|
||||
$ node examples/content-negotiation
|
||||
|
||||
## Running Tests
|
||||
|
||||
To run the test suite first invoke the following command within the repo, installing the development dependencies:
|
||||
|
||||
$ npm install
|
||||
|
||||
then run the tests:
|
||||
|
||||
$ make test
|
||||
|
||||
## Contributors
|
||||
|
||||
```
|
||||
project: express
|
||||
commits: 3559
|
||||
active : 468 days
|
||||
files : 237
|
||||
authors:
|
||||
1891 Tj Holowaychuk 53.1%
|
||||
1285 visionmedia 36.1%
|
||||
182 TJ Holowaychuk 5.1%
|
||||
54 Aaron Heckmann 1.5%
|
||||
34 csausdev 1.0%
|
||||
26 ciaranj 0.7%
|
||||
21 Robert Sköld 0.6%
|
||||
6 Guillermo Rauch 0.2%
|
||||
3 Dav Glass 0.1%
|
||||
3 Nick Poulden 0.1%
|
||||
2 Randy Merrill 0.1%
|
||||
2 Benny Wong 0.1%
|
||||
2 Hunter Loftis 0.1%
|
||||
2 Jake Gordon 0.1%
|
||||
2 Brian McKinney 0.1%
|
||||
2 Roman Shtylman 0.1%
|
||||
2 Ben Weaver 0.1%
|
||||
2 Dave Hoover 0.1%
|
||||
2 Eivind Fjeldstad 0.1%
|
||||
2 Daniel Shaw 0.1%
|
||||
1 Matt Colyer 0.0%
|
||||
1 Pau Ramon 0.0%
|
||||
1 Pero Pejovic 0.0%
|
||||
1 Peter Rekdal Sunde 0.0%
|
||||
1 Raynos 0.0%
|
||||
1 Teng Siong Ong 0.0%
|
||||
1 Viktor Kelemen 0.0%
|
||||
1 ctide 0.0%
|
||||
1 8bitDesigner 0.0%
|
||||
1 isaacs 0.0%
|
||||
1 mgutz 0.0%
|
||||
1 pikeas 0.0%
|
||||
1 shuwatto 0.0%
|
||||
1 tstrimple 0.0%
|
||||
1 ewoudj 0.0%
|
||||
1 Adam Sanderson 0.0%
|
||||
1 Andrii Kostenko 0.0%
|
||||
1 Andy Hiew 0.0%
|
||||
1 Arpad Borsos 0.0%
|
||||
1 Ashwin Purohit 0.0%
|
||||
1 Benjen 0.0%
|
||||
1 Darren Torpey 0.0%
|
||||
1 Greg Ritter 0.0%
|
||||
1 Gregory Ritter 0.0%
|
||||
1 James Herdman 0.0%
|
||||
1 Jim Snodgrass 0.0%
|
||||
1 Joe McCann 0.0%
|
||||
1 Jonathan Dumaine 0.0%
|
||||
1 Jonathan Palardy 0.0%
|
||||
1 Jonathan Zacsh 0.0%
|
||||
1 Justin Lilly 0.0%
|
||||
1 Ken Sato 0.0%
|
||||
1 Maciej Małecki 0.0%
|
||||
1 Masahiro Hayashi 0.0%
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2009-2012 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
|
||||
|
||||
+159
-231
@@ -4,48 +4,52 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, exec = require('child_process').exec;
|
||||
var express = require('../')
|
||||
, exec = require('child_process').exec
|
||||
, program = require('commander')
|
||||
, mkdirp = require('mkdirp')
|
||||
, os = require('os')
|
||||
, fs = require('fs');
|
||||
|
||||
// CLI
|
||||
|
||||
program
|
||||
.version(express.version)
|
||||
.option('-s, --sessions', 'add session support')
|
||||
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
|
||||
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
|
||||
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
|
||||
.option('-f, --force', 'force on non-empty directory')
|
||||
.parse(process.argv);
|
||||
|
||||
// Path
|
||||
|
||||
var path = program.args.shift() || '.';
|
||||
|
||||
// end-of-line code
|
||||
|
||||
var eol = 'win32' == os.platform() ? '\r\n' : '\n'
|
||||
|
||||
// Template engine
|
||||
|
||||
program.template = 'jade';
|
||||
if (program.ejs) program.template = 'ejs';
|
||||
if (program.jshtml) program.template = 'jshtml';
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
* Routes index template.
|
||||
*/
|
||||
|
||||
var version = '2.3.5';
|
||||
|
||||
/**
|
||||
* Add session support.
|
||||
*/
|
||||
|
||||
var sessions = false;
|
||||
|
||||
/**
|
||||
* CSS engine to utilize.
|
||||
*/
|
||||
|
||||
var cssEngine;
|
||||
|
||||
/**
|
||||
* Template engine to utilize.
|
||||
*/
|
||||
|
||||
var templateEngine = 'jade';
|
||||
|
||||
/**
|
||||
* Usage documentation.
|
||||
*/
|
||||
|
||||
var usage = ''
|
||||
+ '\n'
|
||||
+ ' Usage: express [options] [path]\n'
|
||||
+ '\n'
|
||||
+ ' Options:\n'
|
||||
+ ' -s, --sessions add session support\n'
|
||||
+ ' -t, --template <engine> add template <engine> support (jade|ejs). default=jade\n'
|
||||
+ ' -c, --css <engine> add stylesheet <engine> support (less|sass|stylus). default=plain css\n'
|
||||
+ ' -v, --version output framework version\n'
|
||||
+ ' -h, --help output help information\n'
|
||||
;
|
||||
var index = [
|
||||
''
|
||||
, '/*'
|
||||
, ' * GET home page.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.index = function(req, res){'
|
||||
, ' res.render(\'index\', { title: \'Express\' });'
|
||||
, '};'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
@@ -57,23 +61,27 @@ var jadeLayout = [
|
||||
, ' head'
|
||||
, ' title= title'
|
||||
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
|
||||
, ' body!= body'
|
||||
].join('\n');
|
||||
, ' body'
|
||||
, ' block content'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade index template.
|
||||
*/
|
||||
|
||||
var jadeIndex = [
|
||||
'h1= title'
|
||||
, 'p Welcome to #{title}'
|
||||
].join('\n');
|
||||
'extends layout'
|
||||
, ''
|
||||
, 'block content'
|
||||
, ' h1= title'
|
||||
, ' p Welcome to #{title}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* EJS layout template.
|
||||
* EJS index template.
|
||||
*/
|
||||
|
||||
var ejsLayout = [
|
||||
var ejsIndex = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
@@ -81,19 +89,37 @@ var ejsLayout = [
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' <%- body %>'
|
||||
, ' <h1><%= title %></h1>'
|
||||
, ' <p>Welcome to <%= title %></p>'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join('\n');
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* EJS index template.
|
||||
* JSHTML layout template.
|
||||
*/
|
||||
|
||||
var ejsIndex = [
|
||||
'<h1><%= title %></h1>'
|
||||
, '<p>Welcome to <%= title %></p>'
|
||||
].join('\n');
|
||||
var jshtmlLayout = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title> @write(title) </title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' @write(body)'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* JSHTML index template.
|
||||
*/
|
||||
|
||||
var jshtmlIndex = [
|
||||
'<h1>@write(title)</h1>'
|
||||
, '<p>Welcome to @write(title)</p>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default css template.
|
||||
@@ -108,7 +134,7 @@ var css = [
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join('\n');
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default less template.
|
||||
@@ -123,19 +149,7 @@ var less = [
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Default sass template.
|
||||
*/
|
||||
|
||||
var sass = [
|
||||
'body'
|
||||
, ' :padding 50px'
|
||||
, ' :font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' :color #00B7FF'
|
||||
].join('\n');
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default stylus template.
|
||||
@@ -143,38 +157,11 @@ var sass = [
|
||||
|
||||
var stylus = [
|
||||
'body'
|
||||
, ' padding 50px'
|
||||
, ' font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, ' padding: 50px'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' color #00B7FF'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* App test template.
|
||||
*/
|
||||
|
||||
var appTest = [
|
||||
""
|
||||
, "// Run $ expresso"
|
||||
, ""
|
||||
, "/**"
|
||||
, " * Module dependencies."
|
||||
, " */"
|
||||
, ""
|
||||
, "var app = require('../app')"
|
||||
, " , assert = require('assert');"
|
||||
, "",
|
||||
, "module.exports = {"
|
||||
, " 'GET /': function(){"
|
||||
, " assert.response(app,"
|
||||
, " { url: '/' },"
|
||||
, " { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' }},"
|
||||
, " function(res){"
|
||||
, " assert.includes(res.body, '<title>Express</title>');"
|
||||
, " });"
|
||||
, " }"
|
||||
, "};"
|
||||
].join('\n');
|
||||
, ' color: #00B7FF'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* App template.
|
||||
@@ -186,92 +173,43 @@ var app = [
|
||||
, ' * Module dependencies.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'var express = require(\'express\');'
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\')'
|
||||
, ' , http = require(\'http\');'
|
||||
, ''
|
||||
, 'var app = module.exports = express.createServer();'
|
||||
, ''
|
||||
, '// Configuration'
|
||||
, 'var app = express();'
|
||||
, ''
|
||||
, 'app.configure(function(){'
|
||||
, ' app.set(\'views\', __dirname + \'/views\');'
|
||||
, ' app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, ' app.use(express.bodyParser());'
|
||||
, ' app.use(express.methodOverride());{sess}{css}'
|
||||
, ' app.use(app.router);'
|
||||
, ' app.use(express.favicon());'
|
||||
, ' app.use(express.logger(\'dev\'));{css}'
|
||||
, ' app.use(express.static(__dirname + \'/public\'));'
|
||||
, ' app.use(express.bodyParser());'
|
||||
, ' app.use(express.methodOverride());{sess}'
|
||||
, ' app.use(app.router);'
|
||||
, '});'
|
||||
, ''
|
||||
, 'app.configure(\'development\', function(){'
|
||||
, ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); '
|
||||
, ' app.use(express.errorHandler());'
|
||||
, '});'
|
||||
, ''
|
||||
, 'app.configure(\'production\', function(){'
|
||||
, ' app.use(express.errorHandler()); '
|
||||
, '});'
|
||||
, 'app.get(\'/\', routes.index);'
|
||||
, ''
|
||||
, '// Routes'
|
||||
, 'http.createServer(app).listen(3000);'
|
||||
, ''
|
||||
, 'app.get(\'/\', function(req, res){'
|
||||
, ' res.render(\'index\', {'
|
||||
, ' title: \'Express\''
|
||||
, ' });'
|
||||
, '});'
|
||||
, 'console.log("Express server listening on port 3000");'
|
||||
, ''
|
||||
, '// Only listen on $ node app.js'
|
||||
, ''
|
||||
, 'if (!module.parent) {'
|
||||
, ' app.listen(3000);'
|
||||
, ' console.log("Express server listening on port %d", app.address().port);'
|
||||
, '}'
|
||||
, ''
|
||||
].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;
|
||||
case '-s':
|
||||
case '--session':
|
||||
case '--sessions':
|
||||
sessions = true;
|
||||
break;
|
||||
case '-c':
|
||||
case '--css':
|
||||
args.length
|
||||
? (cssEngine = args.shift())
|
||||
: abort('--css requires an argument');
|
||||
break;
|
||||
case '-t':
|
||||
case '--template':
|
||||
args.length
|
||||
? (templateEngine = args.shift())
|
||||
: abort('--template requires an argument');
|
||||
break;
|
||||
default:
|
||||
path = arg;
|
||||
}
|
||||
}
|
||||
].join(eol);
|
||||
|
||||
// Generate application
|
||||
|
||||
(function createApplication(path) {
|
||||
emptyDirectory(path, function(empty){
|
||||
if (empty) {
|
||||
if (empty || program.force) {
|
||||
createApplicationAt(path);
|
||||
} else {
|
||||
confirm('destination is not empty, continue? ', function(ok){
|
||||
program.confirm('destination is not empty, continue? ', function(ok){
|
||||
if (ok) {
|
||||
process.stdin.destroy();
|
||||
createApplicationAt(path);
|
||||
@@ -290,76 +228,101 @@ while (args.length) {
|
||||
*/
|
||||
|
||||
function createApplicationAt(path) {
|
||||
console.log();
|
||||
process.on('exit', function(){
|
||||
console.log();
|
||||
console.log(' install dependencies:');
|
||||
console.log(' $ cd %s && npm install', path);
|
||||
console.log();
|
||||
console.log(' run the app:');
|
||||
console.log(' $ node app');
|
||||
console.log();
|
||||
});
|
||||
|
||||
mkdir(path, function(){
|
||||
mkdir(path + '/pids');
|
||||
mkdir(path + '/logs');
|
||||
mkdir(path + '/public');
|
||||
mkdir(path + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
switch (cssEngine) {
|
||||
case 'stylus':
|
||||
write(path + '/public/stylesheets/style.styl', stylus);
|
||||
break;
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
write(path + '/public/stylesheets/style.less', less);
|
||||
break;
|
||||
case 'sass':
|
||||
write(path + '/public/stylesheets/style.sass', sass);
|
||||
case 'stylus':
|
||||
write(path + '/public/stylesheets/style.styl', stylus);
|
||||
break;
|
||||
default:
|
||||
write(path + '/public/stylesheets/style.css', css);
|
||||
}
|
||||
});
|
||||
|
||||
mkdir(path + '/routes', function(){
|
||||
write(path + '/routes/index.js', index);
|
||||
});
|
||||
|
||||
mkdir(path + '/views', function(){
|
||||
switch (templateEngine) {
|
||||
switch (program.template) {
|
||||
case 'ejs':
|
||||
write(path + '/views/layout.ejs', ejsLayout);
|
||||
write(path + '/views/index.ejs', ejsIndex);
|
||||
break;
|
||||
case 'jade':
|
||||
write(path + '/views/layout.jade', jadeLayout);
|
||||
write(path + '/views/index.jade', jadeIndex);
|
||||
break;
|
||||
case 'jshtml':
|
||||
write(path + '/views/layout.jshtml', jshtmlLayout);
|
||||
write(path + '/views/index.jshtml', jshtmlIndex);
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
mkdir(path + '/test', function(){
|
||||
write(path + '/test/app.test.js', appTest);
|
||||
});
|
||||
|
||||
// CSS Engine support
|
||||
switch (cssEngine) {
|
||||
case 'sass':
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
app = app.replace('{css}', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));');
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
|
||||
break;
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', '\n app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
|
||||
break;
|
||||
default:
|
||||
app = app.replace('{css}', '');
|
||||
}
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', sessions
|
||||
? '\n app.use(express.cookieParser());\n app.use(express.session({ secret: \'your secret here\' }));'
|
||||
app = app.replace('{sess}', program.sessions
|
||||
? eol + ' app.use(express.cookieParser(\'your secret here\'));' + eol + ' app.use(express.session());'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
app = app.replace(':TEMPLATE', templateEngine);
|
||||
app = app.replace(':TEMPLATE', program.template);
|
||||
|
||||
write(path + '/app.js', app);
|
||||
|
||||
// Suggestions
|
||||
process.on('exit', function(){
|
||||
if (cssEngine) {
|
||||
console.log(' - make sure you have installed %s: \x1b[33m$ npm install %s\x1b[0m'
|
||||
, cssEngine
|
||||
, cssEngine);
|
||||
// package.json
|
||||
var pkg = {
|
||||
name: 'application-name'
|
||||
, version: '0.0.1'
|
||||
, private: true
|
||||
, scripts: { start: 'node app' }
|
||||
, dependencies: {
|
||||
express: express.version
|
||||
}
|
||||
console.log(' - make sure you have installed %s: \x1b[33m$ npm install %s\x1b[0m'
|
||||
, templateEngine
|
||||
, templateEngine);
|
||||
});
|
||||
}
|
||||
|
||||
if (program.template) pkg.dependencies[program.template] = '*';
|
||||
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
pkg.dependencies['less-middleware'] = '*';
|
||||
break;
|
||||
default:
|
||||
if (program.css) {
|
||||
pkg.dependencies[program.css] = '*';
|
||||
}
|
||||
}
|
||||
|
||||
write(path + '/package.json', JSON.stringify(pkg, null, 2));
|
||||
write(path + '/app.js', app);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -389,41 +352,6 @@ function write(path, str) {
|
||||
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt confirmation with the given `msg`.
|
||||
*
|
||||
* @param {String} msg
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function confirm(msg, fn) {
|
||||
prompt(msg, function(val){
|
||||
fn(/^ *y(es)?/i.test(val));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt input with the given `msg` and callback `fn`.
|
||||
*
|
||||
* @param {String} msg
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function prompt(msg, fn) {
|
||||
// prompt
|
||||
if (' ' == msg[msg.length - 1]) {
|
||||
process.stdout.write(msg);
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
// stdin
|
||||
process.stdin.setEncoding('ascii');
|
||||
process.stdin.once('data', function(data){
|
||||
fn(data);
|
||||
}).resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mkdir -p.
|
||||
*
|
||||
@@ -432,9 +360,9 @@ function prompt(msg, fn) {
|
||||
*/
|
||||
|
||||
function mkdir(path, fn) {
|
||||
exec('mkdir -p ' + path, function(err){
|
||||
mkdirp(path, 0755, function(err){
|
||||
if (err) throw err;
|
||||
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
|
||||
console.log(' \033[36mcreate\033[0m : ' + path);
|
||||
fn && fn();
|
||||
});
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
var http = require('http');
|
||||
|
||||
var times = 50;
|
||||
|
||||
while (times--) {
|
||||
var req = http.request({
|
||||
port: 3000
|
||||
, method: 'POST'
|
||||
, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
});
|
||||
|
||||
req.on('response', function(res){
|
||||
console.log(res.statusCode);
|
||||
});
|
||||
|
||||
var n = 500000;
|
||||
while (n--) {
|
||||
req.write('foo=bar&bar=baz&');
|
||||
}
|
||||
|
||||
req.write('foo=bar&bar=baz');
|
||||
|
||||
req.end();
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<style>
|
||||
#tagline {
|
||||
|
||||
+3
-3
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<style>
|
||||
#tagline {
|
||||
@@ -192,10 +193,9 @@
|
||||
</ul>
|
||||
<h3>Development Dependencies</h3>
|
||||
|
||||
<p>Express development dependencies are stored within the <em>./support</em> directory. To
|
||||
update them execute:</p>
|
||||
<p>First install the dev dependencies by executing the following command in the repo’s directory:</p>
|
||||
|
||||
<pre><code>$ git submodule update --init
|
||||
<pre><code>$ npm install
|
||||
</code></pre>
|
||||
|
||||
<h3>Running Tests</h3>
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
|
||||
### Development Dependencies
|
||||
|
||||
Express development dependencies are stored within the _./support_ directory. To
|
||||
update them execute:
|
||||
First install the dev dependencies by executing the following command in the repo's directory:
|
||||
|
||||
$ git submodule update --init
|
||||
$ npm install
|
||||
|
||||
### Running Tests
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<style>
|
||||
#tagline {
|
||||
|
||||
+48
-17
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<style>
|
||||
#tagline {
|
||||
@@ -179,6 +180,8 @@
|
||||
</a>
|
||||
<div id="wrapper">
|
||||
<div id="container"><ul id="toc">
|
||||
|
||||
</ul><ul id="toc">
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#creating-a server">Creating A Server</a></li>
|
||||
<li><a href="#creating-an https server">Creating An HTTPS Server</a></li>
|
||||
@@ -202,6 +205,7 @@
|
||||
<li><a href="#req.accepts()">accepts()</a></li>
|
||||
<li><a href="#req.is()">is()</a></li>
|
||||
<li><a href="#req.param()">param()</a></li>
|
||||
<li><a href="#req.get()">get()</a></li>
|
||||
<li><a href="#req.flash()">flash()</a></li>
|
||||
<li><a href="#req.isxmlhttprequest">isXMLHttpRequest</a></li>
|
||||
</ul></li>
|
||||
@@ -255,6 +259,31 @@
|
||||
<pre><code>$ npm install express
|
||||
</code></pre>
|
||||
|
||||
<p>or to access the <code>express(1)</code> executable install globally:</p>
|
||||
|
||||
<pre><code>$ npm install -g express
|
||||
</code></pre>
|
||||
|
||||
<h2>Quick Start</h2>
|
||||
|
||||
<p> The quickest way to get started with express is to utilize the executable <code>express(1)</code> to generate an application as shown below:</p>
|
||||
|
||||
<p> Create the app:</p>
|
||||
|
||||
<pre><code>$ npm install -g express
|
||||
$ express /tmp/foo && cd /tmp/foo
|
||||
</code></pre>
|
||||
|
||||
<p> Install dependencies:</p>
|
||||
|
||||
<pre><code>$ npm install -d
|
||||
</code></pre>
|
||||
|
||||
<p> Start the server:</p>
|
||||
|
||||
<pre><code>$ node app.js
|
||||
</code></pre>
|
||||
|
||||
<h3 id="creating-a server">Creating A Server</h3>
|
||||
|
||||
<p> To create an instance of the <em>express.HTTPServer</em>, simply invoke the <em>createServer()</em> method. With our instance <em>app</em> we can then define routes based on the HTTP verbs, in this example <em>app.get()</em>.</p>
|
||||
@@ -503,9 +532,9 @@ var app = express.createServer(
|
||||
);
|
||||
</code></pre>
|
||||
|
||||
<p>Alternatively we can <em>use()</em> them which is useful when adding middleware within <em>configure()</em> blocks, in a progressive manor.</p>
|
||||
<p>Alternatively we can <em>use()</em> them which is useful when adding middleware within <em>configure()</em> blocks, in a progressive manner.</p>
|
||||
|
||||
<pre><code>app.use(express.logger({ format: ':method :uri' }));
|
||||
<pre><code>app.use(express.logger({ format: ':method :url' }));
|
||||
</code></pre>
|
||||
|
||||
<p>Typically with connect middleware you would <em>require(‘connect’)</em> like so:</p>
|
||||
@@ -629,7 +658,7 @@ app.get('/', all, function(){});
|
||||
|
||||
<h3 id="http-methods">HTTP Methods</h3>
|
||||
|
||||
<p>We have seen <em>app.get()</em> a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as <em>app.post()</em>, <em>app.del()</em>, etc.</p>
|
||||
<p>We have seen <em>app.get()</em> a few times, however Express also exposes other familiar HTTP verbs in the same manner, such as <em>app.post()</em>, <em>app.del()</em>, etc.</p>
|
||||
|
||||
<p> A common example for <em>POST</em> usage, is when “submitting” a form. Below we simply set our form method to “post” in our html, and control will be given to the route we have defined below it.</p>
|
||||
|
||||
@@ -772,16 +801,6 @@ is present, which is useful for developing apps that rely heavily on client-side
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>For simple cases such as route placeholder validation and coercion we can simple pass a callback which has an arity of 1 (accepts one argument). Any errors thrown will be passed to <em>next(err)</em>.</p>
|
||||
|
||||
<pre><code>app.param('number', function(n){ return parseInt(n, 10); });
|
||||
</code></pre>
|
||||
|
||||
<p>We may also apply the same callback to several placeholders, for example a route GET <em>/commits/:from-:to</em> are both numbers, so we may define them as an array:</p>
|
||||
|
||||
<pre><code>app.param(['from', 'to'], function(n){ return parseInt(n, 10); });
|
||||
</code></pre>
|
||||
|
||||
<h3 id="view-rendering">View Rendering</h3>
|
||||
|
||||
<p>View filenames take the form “<name>.<engine>”, where <engine> is the name
|
||||
@@ -916,14 +935,14 @@ app.use(express.session({ secret: "keyboard cat" }));
|
||||
|
||||
<p>By default the <em>session</em> middleware uses the memory store bundled with Connect, however many implementations exist. For example <a href="http://github.com/visionmedia/connect-redis">connect-redis</a> supplies a <a href="http://code.google.com/p/redis/">Redis</a> session store and can be used as shown below:</p>
|
||||
|
||||
<pre><code>var RedisStore = require('connect-redis');
|
||||
<pre><code>var RedisStore = require('connect-redis')(express);
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
|
||||
</code></pre>
|
||||
|
||||
<p>Now the <em>req.session</em> and <em>req.sessionStore</em> properties will be accessible to all routes and subsequent middleware. Properties on <em>req.session</em> are automatically saved on a response, so for example if we wish to shopping cart data:</p>
|
||||
|
||||
<pre><code>var RedisStore = require('connect-redis');
|
||||
<pre><code>var RedisStore = require('connect-redis')(express);
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
|
||||
@@ -1067,6 +1086,18 @@ can perform any request assertion you wish.</p>
|
||||
should be an object. This can be done by using
|
||||
the _express.bodyParser middleware.</p>
|
||||
|
||||
<h3 id="req.get()">req.get(field, param)</h3>
|
||||
|
||||
<p> Get <em>field</em>’s <em>param</em> value, defaulting to ‘’ when the <em>param</em>
|
||||
or <em>field</em> is not present.</p>
|
||||
|
||||
<pre><code> req.get('content-disposition', 'filename');
|
||||
// => "something.png"
|
||||
|
||||
req.get('Content-Type', 'boundary');
|
||||
// => "--foo-bar-baz"
|
||||
</code></pre>
|
||||
|
||||
<h3 id="req.flash()">req.flash(type[, msg])</h3>
|
||||
|
||||
<p>Queue flash <em>msg</em> of the given <em>type</em>.</p>
|
||||
@@ -1420,7 +1451,7 @@ partial('movie', movie)
|
||||
<pre><code> res.local('foo', bar);
|
||||
res.local('bar', baz);
|
||||
|
||||
res.locals({ foo: bar, bar, baz });
|
||||
res.locals({ foo: bar, bar: baz });
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app.set()">app.set(name[, val])</h3>
|
||||
@@ -1773,4 +1804,4 @@ Hello World
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+121
-126
@@ -1,8 +1,28 @@
|
||||
|
||||
### Installation
|
||||
|
||||
$ npm install express
|
||||
|
||||
or to access the `express(1)` executable install globally:
|
||||
|
||||
$ npm install -g express
|
||||
|
||||
## Quick Start
|
||||
|
||||
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:
|
||||
|
||||
Create the app:
|
||||
|
||||
$ npm install -g express
|
||||
$ express /tmp/foo && cd /tmp/foo
|
||||
|
||||
Install dependencies:
|
||||
|
||||
$ npm install -d
|
||||
|
||||
Start the server:
|
||||
|
||||
$ node app.js
|
||||
|
||||
### Creating A Server
|
||||
|
||||
To create an instance of the _express.HTTPServer_, simply invoke the _createServer()_ method. With our instance _app_ we can then define routes based on the HTTP verbs, in this example _app.get()_.
|
||||
@@ -51,6 +71,12 @@ otherwise the first call to _app.get()_, _app.post()_, etc will mount the routes
|
||||
app.use(express.errorHandler());
|
||||
});
|
||||
|
||||
For similar environments you may also pass several env strings:
|
||||
|
||||
app.configure('stage', 'prod', function(){
|
||||
// config
|
||||
});
|
||||
|
||||
For internal and arbitrary settings Express provides the _set(key[, val])_, _enable(key)_, _disable(key)_ methods:
|
||||
|
||||
app.configure(function(){
|
||||
@@ -81,9 +107,11 @@ Express supports the following settings out of the box:
|
||||
* _home_ Application base path used for _res.redirect()_ and transparently handling mounted apps.
|
||||
* _views_ Root views directory defaulting to **CWD/views**
|
||||
* _view engine_ Default view engine name for views rendered without extensions
|
||||
* _view options_ An object specifying global view options
|
||||
* _view cache_ Enable view caching (enabled in production)
|
||||
* _charset_ Alter the default charset of "utf-8"
|
||||
* _case sensitive routes_ Enable case-sensitive routing
|
||||
* _strict routing_ When enabled trailing slashes are no longer ignored
|
||||
* _jsonp callback_ Enable _res.send()_ / _res.json()_ transparent jsonp support
|
||||
|
||||
### Routing
|
||||
|
||||
@@ -217,7 +245,7 @@ The _app.all()_ method is useful for applying the same logic for all HTTP verbs
|
||||
});
|
||||
|
||||
app.get('*', function(req, res){
|
||||
res.send('what???', 404);
|
||||
res.send(404, 'what???');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -234,9 +262,9 @@ passed to _express.createServer()_ as you would with a regular Connect server. F
|
||||
, express.bodyParser()
|
||||
);
|
||||
|
||||
Alternatively we can _use()_ them which is useful when adding middleware within _configure()_ blocks, in a progressive manor.
|
||||
Alternatively we can _use()_ them which is useful when adding middleware within _configure()_ blocks, in a progressive manner.
|
||||
|
||||
app.use(express.logger({ format: ':method :uri' }));
|
||||
app.use(express.logger({ format: ':method :url' }));
|
||||
|
||||
Typically with connect middleware you would _require('connect')_ like so:
|
||||
|
||||
@@ -351,7 +379,7 @@ There are times when we may want to "skip" passed remaining route middleware, bu
|
||||
|
||||
### HTTP Methods
|
||||
|
||||
We have seen _app.get()_ a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as _app.post()_, _app.del()_, etc.
|
||||
We have seen _app.get()_ a few times, however Express also exposes other familiar HTTP verbs in the same manner, such as _app.post()_, _app.del()_, etc.
|
||||
|
||||
A common example for _POST_ usage, is when "submitting" a form. Below we simply set our form method to "post" in our html, and control will be given to the route we have defined below it.
|
||||
|
||||
@@ -393,65 +421,16 @@ The reason that these are not always defaults, is simply because these are not r
|
||||
|
||||
### 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);
|
||||
}
|
||||
|
||||
NotFound.prototype.__proto__ = Error.prototype;
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound;
|
||||
Error handling middleware are simply middleware with an arity of 4, aka
|
||||
the signature _(err, req, res, next)_. When you _next(err)_ an error,
|
||||
only these middleware are executed and have a chance to respond. For example:
|
||||
|
||||
app.use(app.bodyParser());
|
||||
app.use(app.methodOverride());
|
||||
app.use(app.router);
|
||||
app.use(function(err, req, res, next){
|
||||
res.send(500, 'Server error');
|
||||
});
|
||||
|
||||
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.
|
||||
|
||||
Note that these handlers can be defined anywhere, as they
|
||||
will be placed below the route handlers on _listen()_. This
|
||||
allows for definition within _configure()_ blocks so we can
|
||||
handle exceptions in different ways based on the environment.
|
||||
|
||||
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. For example when node performs filesystem syscalls, you may receive an error object with the _error.code_ of _ENOENT_, meaning "no such file or directory", we can utilize this in our error handling and display a page specific to this if desired.
|
||||
|
||||
app.error(function(err, req, res){
|
||||
res.render('500.jade', {
|
||||
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(express.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(express.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.
|
||||
|
||||
### Route Param Pre-conditions
|
||||
|
||||
@@ -481,14 +460,6 @@ Doing so, as mentioned drastically improves our route readability, and allows us
|
||||
res.send('user ' + req.user.name);
|
||||
});
|
||||
|
||||
For simple cases such as route placeholder validation and coercion we can simple pass a callback which has an arity of 1 (accepts one argument). Any errors thrown will be passed to _next(err)_.
|
||||
|
||||
app.param('number', function(n){ return parseInt(n, 10); });
|
||||
|
||||
We may also apply the same callback to several placeholders, for example a route GET _/commits/:from-:to_ are both numbers, so we may define them as an array:
|
||||
|
||||
app.param(['from', 'to'], function(n){ return parseInt(n, 10); });
|
||||
|
||||
### View Rendering
|
||||
|
||||
View filenames take the form "<name>.<engine>", where <engine> is the name
|
||||
@@ -522,13 +493,11 @@ mix and match template engines:
|
||||
|
||||
res.render('another-page.ejs');
|
||||
|
||||
Express also provides the _view options_ setting, which is applied each time a view is rendered, so for example if you rarely use layouts you may set:
|
||||
To apply application-level locals, or view engine options may be set using _app.local()_ or _app.locals()_, for example if we don't want layouts for most of our templates we may do:
|
||||
|
||||
app.set('view options', {
|
||||
layout: false
|
||||
});
|
||||
app.local('layout', false);
|
||||
|
||||
Which can then be overridden within the _res.render()_ call if need be:
|
||||
Which can then be overridden within the _res.render()_ call if desired, and is otherwise functionally equivalent to passing directly to `res.render()`:
|
||||
|
||||
res.render('myview.ejs', { layout: true });
|
||||
|
||||
@@ -544,13 +513,6 @@ These paths may also be absolute:
|
||||
|
||||
res.render('page', { layout: __dirname + '/../../mylayout.jade' });
|
||||
|
||||
A good example of this is specifying custom _ejs_ opening and closing tags:
|
||||
|
||||
app.set('view options', {
|
||||
open: '{{',
|
||||
close: '}}'
|
||||
});
|
||||
|
||||
### View Partials
|
||||
|
||||
The Express view system has built-in support for partials and collections, which are "mini" views representing a document fragment. For example rather than iterating
|
||||
@@ -603,13 +565,13 @@ Sessions support can be added by using Connect's _session_ middleware. To do so
|
||||
|
||||
By default the _session_ middleware uses the memory store bundled with Connect, however many implementations exist. For example [connect-redis](http://github.com/visionmedia/connect-redis) supplies a [Redis](http://code.google.com/p/redis/) session store and can be used as shown below:
|
||||
|
||||
var RedisStore = require('connect-redis');
|
||||
var RedisStore = require('connect-redis')(express);
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
|
||||
|
||||
Now the _req.session_ and _req.sessionStore_ properties will be accessible to all routes and subsequent middleware. Properties on _req.session_ are automatically saved on a response, so for example if we wish to shopping cart data:
|
||||
|
||||
var RedisStore = require('connect-redis');
|
||||
var RedisStore = require('connect-redis')(express);
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
|
||||
@@ -627,7 +589,7 @@ Now the _req.session_ and _req.sessionStore_ properties will be accessible to al
|
||||
// we could check req.session.items && req.session.items.length
|
||||
// to print out a message
|
||||
if (req.session.items && req.session.items.length) {
|
||||
req.flash('info', 'You have %s items in your cart', req.session.items.length);
|
||||
req.notify('info', 'You have %s items in your cart', req.session.items.length);
|
||||
}
|
||||
res.render('shopping-cart');
|
||||
});
|
||||
@@ -741,27 +703,40 @@ To utilize urlencoded request bodies, _req.body_
|
||||
should be an object. This can be done by using
|
||||
the _express.bodyParser middleware.
|
||||
|
||||
### req.flash(type[, msg])
|
||||
### req.get(field, param)
|
||||
|
||||
Get _field_'s _param_ value, defaulting to '' when the _param_
|
||||
or _field_ is not present.
|
||||
|
||||
req.get('content-disposition', 'filename');
|
||||
// => "something.png"
|
||||
|
||||
req.get('Content-Type', 'boundary');
|
||||
// => "--foo-bar-baz"
|
||||
|
||||
### req.notify(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');
|
||||
req.notify('info', 'email sent');
|
||||
req.notify('error', 'email delivery failed');
|
||||
req.notify('info', 'email re-sent');
|
||||
// => 2
|
||||
|
||||
req.flash('info');
|
||||
req.notify('info');
|
||||
// => ['email sent', 'email re-sent']
|
||||
|
||||
req.flash('info');
|
||||
req.notify('info');
|
||||
// => []
|
||||
|
||||
req.flash();
|
||||
req.notify();
|
||||
// => { error: ['email delivery failed'], info: [] }
|
||||
|
||||
Flash notification message may also utilize formatters, by default only the %s string formatter is available:
|
||||
Flash notification message may also utilize formatters, by default only the %s string and %d integer formatters is available:
|
||||
|
||||
req.flash('info', 'email delivery to _%s_ from _%s_ failed.', toUser, fromUser);
|
||||
req.notify('info', 'email delivery to <em>%s</em> from <em>%s</em> failed.', toUser, fromUser);
|
||||
|
||||
Argument HTML is escaped, to prevent XSS, however HTML notification format is valid.
|
||||
|
||||
### req.isXMLHttpRequest
|
||||
|
||||
@@ -824,6 +799,21 @@ Sets the _Content-Disposition_ response header to "attachment", with optional _f
|
||||
|
||||
res.attachment('path/to/my/image.png');
|
||||
|
||||
### res.status(code)
|
||||
|
||||
Sets the `res.statusCode` property to `code` and returns for chaining:
|
||||
|
||||
res.status(500).send('Something bad happened');
|
||||
|
||||
is equivalent to:
|
||||
|
||||
res.statusCode = 500;
|
||||
res.send('Something bad happened');
|
||||
|
||||
and:
|
||||
|
||||
res.send(500, 'Something bad happened');
|
||||
|
||||
### res.sendfile(path[, options[, callback]])
|
||||
|
||||
Used by `res.download()` to transfer an arbitrary file.
|
||||
@@ -873,25 +863,32 @@ An optional second callback, _callback2_ may be given to allow you to act on con
|
||||
// connection related error
|
||||
});
|
||||
|
||||
### res.send(body|status[, headers|status[, status]])
|
||||
### res.send(body|status[, body])
|
||||
|
||||
The _res.send()_ method is a high level response utility allowing you to pass
|
||||
objects to respond with json, strings for html, Buffer instances, or numbers representing the status code. The following are all valid uses:
|
||||
|
||||
res.send(); // 204
|
||||
res.send(new Buffer('wahoo'));
|
||||
res.send({ some: 'json' });
|
||||
res.send(201, { message: 'User created' });
|
||||
res.send('<p>some html</p>');
|
||||
res.send('Sorry, cant find that', 404);
|
||||
res.send('text', { 'Content-Type': 'text/plain' }, 201);
|
||||
res.send(404);
|
||||
res.send(404, 'Sorry, cant find that');
|
||||
res.send(404); // "Not Found"
|
||||
res.send(500); // "Internal Server Error"
|
||||
|
||||
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.
|
||||
The _Content-Type_ response header is defaulted appropriately unless previously defined via `res.header()` / `res.contentType()` etc.
|
||||
|
||||
Note that this method _end()_s the response, so you will want to use node's _res.write()_ for multiple writes or streaming.
|
||||
|
||||
### res.json(obj|status[, obj])
|
||||
|
||||
Send an explicit JSON response. This method is ideal for JSON-only APIs, while it is much like _res.send(obj)_, send is not ideal for cases when you want to send for example a single string as JSON, since the default for _res.send(string)_ is text/html.
|
||||
|
||||
res.json(null);
|
||||
res.json({ user: 'tj' });
|
||||
res.json(500, 'oh noes!');
|
||||
res.json(404, 'I dont have that');
|
||||
|
||||
### res.redirect(url[, status])
|
||||
|
||||
Redirect to the given _url_ with a default response _status_ of 302.
|
||||
@@ -908,7 +905,8 @@ the "home" setting and defaults to "/".
|
||||
|
||||
### res.cookie(name, val[, options])
|
||||
|
||||
Sets the given cookie _name_ to _val_, with options _httpOnly_, _secure_, _expires_ etc.
|
||||
Sets the given cookie _name_ to _val_, with options _httpOnly_, _secure_, _expires_ etc. The _path_ option defaults to the app's "home" setting, which
|
||||
is typically "/".
|
||||
|
||||
// "Remember me" for 15 minutes
|
||||
res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||
@@ -927,7 +925,8 @@ To parse incoming _Cookie_ headers, use the _cookieParser_ middleware, which pro
|
||||
|
||||
### res.clearCookie(name[, options])
|
||||
|
||||
Clear cookie _name_ by setting "expires" far in the past.
|
||||
Clear cookie _name_ by setting "expires" far in the past. Much like
|
||||
_res.cookie()_ the _path_ option also defaults to the "home" setting.
|
||||
|
||||
res.clearCookie('rememberme');
|
||||
|
||||
@@ -942,6 +941,15 @@ The _options_ passed are the local variables as well, for example if we want to
|
||||
var user = { name: 'tj' };
|
||||
res.render('index', { layout: false, user: user });
|
||||
|
||||
This _options_ object is also considered an "options" object. For example
|
||||
when you pass the _status_ local, it's not only available to the view, it
|
||||
sets the response status to this number. This is also useful if a template
|
||||
engine accepts specific options, such as _debug_, or _compress_. Below
|
||||
is an example of how one might render an error page, passing the _status_ for
|
||||
display, as well as it setting _res.statusCode_.
|
||||
|
||||
res.render('error', { status: 500, message: 'Internal Server Error' });
|
||||
|
||||
### res.partial(view[, options])
|
||||
|
||||
Render _view_ partial with the given _options_. This method is always available
|
||||
@@ -1155,21 +1163,11 @@ When mounted, _res.redirect()_ will respect the mount-point. For example if a bl
|
||||
|
||||
res.redirect('/posts');
|
||||
|
||||
### app.error(function)
|
||||
### app.locals(obj)
|
||||
|
||||
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:
|
||||
Registers static view locals.
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
res.send(err.message, 500);
|
||||
});
|
||||
|
||||
### app.helpers(obj)
|
||||
|
||||
Registers static view helpers.
|
||||
|
||||
app.helpers({
|
||||
app.locals({
|
||||
name: function(first, last){ return first + ', ' + last }
|
||||
, firstName: 'tj'
|
||||
, lastName: 'holowaychuk'
|
||||
@@ -1183,19 +1181,16 @@ as well as the _name()_ function exposed.
|
||||
Express also provides a few locals by default:
|
||||
|
||||
- `settings` the app's settings object
|
||||
- `filename` the view's filename
|
||||
- `layout(path)` specify the layout from within a view
|
||||
|
||||
This method is aliased as _app.locals()_.
|
||||
### app.dynamicLocals(obj)
|
||||
|
||||
### app.dynamicHelpers(obj)
|
||||
|
||||
Registers dynamic view helpers. Dynamic view helpers
|
||||
Registers dynamic view locals. Dynamic locals
|
||||
are simply functions which accept _req_, _res_, and are
|
||||
evaluated against the _Server_ instance before a view is rendered. The _return value_ of this function
|
||||
evaluated against the _Server_ instance before a view is rendered, and are unique to that specific request. The _return value_ of this function
|
||||
becomes the local variable it is associated with.
|
||||
|
||||
app.dynamicHelpers({
|
||||
app.dynamicLocals({
|
||||
session: function(req, res){
|
||||
return req.session;
|
||||
}
|
||||
|
||||
+12
-6
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<style>
|
||||
#tagline {
|
||||
@@ -239,19 +240,24 @@ app.listen(3000);
|
||||
<li><a href="http://github.com/visionmedia/express-messages">express-messages</a> flash message notification rendering</li>
|
||||
<li><a href="http://github.com/visionmedia/express-configuration">express-configure</a> async configuration support (load settings from redis etc)</li>
|
||||
<li><a href="http://github.com/visionmedia/express-namespace">express-namespace</a> namespaced routing support</li>
|
||||
<li><a href="http://github.com/visionmedia/express-expose">express-expose</a> expose objects, functions, modules and more to client-side js</li>
|
||||
<li><a href="https://github.com/visionmedia/express-params">express-params</a> app.param() extensions</li>
|
||||
<li><a href="https://github.com/LearnBoost/express-mongoose">express-mongoose</a> plugin for easy rendering of Mongoose async Query results</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>More Information</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://groups.google.com/group/express-js">Google Group</a> for discussion</li>
|
||||
<li>#express on freenode</li>
|
||||
<li>Follow <a href="http://twitter.com/tjholowaychuk">tjholowaychuk</a> on twitter for updates</li>
|
||||
<li>View the <a href="http://senchalabs.github.com/connect">Connect</a> documentation</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>
|
||||
<li>View the <a href="contrib.html">contrib guide</a></li>
|
||||
<li><a href="http://groups.google.com/group/express-js">Google Group</a> for discussion</li>
|
||||
<li>Visit the <a href="http://github.com/visionmedia/express/wiki">Wiki</a></li>
|
||||
<li><a href="http://hideyukisaito.com/doc/expressjs/">日本語ドキュメンテーション</a> by <a href="https://github.com/hideyukisaito">hideyukisaito</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/eRYu0O">Introduction</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/dU13Fx">View Partials</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/hX4IaH">Route Specific Middleware</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/eNqmVs">Route Path Placeholder Preconditions</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
+8
-6
@@ -40,13 +40,15 @@ The following modules compliment or extend Express directly:
|
||||
* [express-messages](http://github.com/visionmedia/express-messages) flash message notification rendering
|
||||
* [express-configure](http://github.com/visionmedia/express-configuration) async configuration support (load settings from redis etc)
|
||||
* [express-namespace](http://github.com/visionmedia/express-namespace) namespaced routing support
|
||||
* [express-expose](http://github.com/visionmedia/express-expose) expose objects, functions, modules and more to client-side js
|
||||
* [express-params](https://github.com/visionmedia/express-params) app.param() extensions
|
||||
* [express-mongoose](https://github.com/LearnBoost/express-mongoose) plugin for easy rendering of Mongoose async Query results
|
||||
|
||||
## More Information
|
||||
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* \#express on freenode
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* View the [Connect](http://senchalabs.github.com/connect) documentation
|
||||
* 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)
|
||||
* View the [contrib guide](contrib.html)
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* [Русскоязычная документация](http://express-js.ru/)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<style>
|
||||
#tagline {
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<style>
|
||||
#tagline {
|
||||
@@ -326,7 +327,7 @@
|
||||
|
||||
<h3>partial() locals</h3>
|
||||
|
||||
<p> Both <em>res.partial()</em> and the <em>partial()</em> functions accept an single object consisting of both the options and the locals. Previously with Express 1.x you may pass <em>user</em> to a partial, along with <em>date</em> like so:</p>
|
||||
<p> Both <em>res.partial()</em> and the <em>partial()</em> functions accept a single object consisting of both the options and the locals. Previously with Express 1.x you may pass <em>user</em> to a partial, along with <em>date</em> like so:</p>
|
||||
|
||||
<pre><code> partial('user', { object: user, locals: { date: new Date }})
|
||||
</code></pre>
|
||||
@@ -367,7 +368,7 @@
|
||||
|
||||
<h3>View Partial Lookup</h3>
|
||||
|
||||
<p> Previously partials were loaded relative to the now removed <em>view partials</em> directory setting, or by default <em>views/partials</em>, now they are relative to the view calling them, read more on <a href="guide.html#View-Lookup">view lookup</a>.</p>
|
||||
<p> Previously partials were loaded relative to the now removed <em>view partials</em> directory setting, or by default <em>views/partials</em>, now they are relative to the view calling them, read more on <a href="guide.html#view-lookup">view lookup</a>.</p>
|
||||
|
||||
<h3>Mime Types</h3>
|
||||
|
||||
|
||||
+3
-3
@@ -123,7 +123,7 @@ However now we have the alternative _maxAge_ property which may be used to set _
|
||||
|
||||
### partial() locals
|
||||
|
||||
Both _res.partial()_ and the _partial()_ functions accept an single object consisting of both the options and the locals. Previously with Express 1.x you may pass _user_ to a partial, along with _date_ like so:
|
||||
Both _res.partial()_ and the _partial()_ functions accept a single object consisting of both the options and the locals. Previously with Express 1.x you may pass _user_ to a partial, along with _date_ like so:
|
||||
|
||||
partial('user', { object: user, locals: { date: new Date }})
|
||||
|
||||
@@ -157,7 +157,7 @@ or perhaps if you preferred not to use the inferred name _user_ you may used a l
|
||||
|
||||
### View Partial Lookup
|
||||
|
||||
Previously partials were loaded relative to the now removed _view partials_ directory setting, or by default _views/partials_, now they are relative to the view calling them, read more on [view lookup](guide.html#View-Lookup).
|
||||
Previously partials were loaded relative to the now removed _view partials_ directory setting, or by default _views/partials_, now they are relative to the view calling them, read more on [view lookup](guide.html#view-lookup).
|
||||
|
||||
### Mime Types
|
||||
|
||||
@@ -174,4 +174,4 @@ or perhaps if you preferred not to use the inferred name _user_ you may used a l
|
||||
Previously when using options the `root` option would be used for this:
|
||||
|
||||
app.use(express.staticProvider({ root: __dirname + '/public', maxAge: oneYear }));
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<style>
|
||||
#tagline {
|
||||
|
||||
+36
-41
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -9,55 +6,56 @@ require.paths.unshift(__dirname + '/../../support');
|
||||
var express = require('../../lib/express')
|
||||
, crypto = require('crypto');
|
||||
|
||||
var app = express.createServer(
|
||||
express.bodyParser()
|
||||
, express.cookieParser()
|
||||
, express.session({ secret: 'keyboard cat' })
|
||||
);
|
||||
var app = module.exports = express();
|
||||
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.cookieParser('shhhh, very secret'));
|
||||
app.use(express.session());
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Message helper, ideally we would use req.flash()
|
||||
// however this is more light-weight for an example
|
||||
// Session-persisted message middleware
|
||||
|
||||
app.dynamicHelpers({
|
||||
message: function(req){
|
||||
var err = req.session.error
|
||||
, msg = req.session.success;
|
||||
delete req.session.error;
|
||||
delete req.session.success;
|
||||
if (err) return '<p class="msg error">' + err + '</p>';
|
||||
if (msg) return '<p class="msg success">' + msg + '</p>';
|
||||
}
|
||||
});
|
||||
app.locals.use(function(req,res){
|
||||
var err = req.session.error
|
||||
, msg = req.session.success;
|
||||
delete req.session.error;
|
||||
delete req.session.success;
|
||||
res.locals.message = '';
|
||||
if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
|
||||
if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
|
||||
})
|
||||
|
||||
// Generate a salt for the user to prevent rainbow table attacks
|
||||
|
||||
// for better security take a look at the bcrypt c++ addon:
|
||||
// https://github.com/ncb000gt/node.bcrypt.js
|
||||
var users = {
|
||||
tj: {
|
||||
name: 'tj'
|
||||
name: 'tj'
|
||||
, salt: 'randomly-generated-salt'
|
||||
, pass: md5('foobar' + 'randomly-generated-salt')
|
||||
, pass: hash('foobar', 'randomly-generated-salt')
|
||||
}
|
||||
};
|
||||
|
||||
// Used to generate a hash of the plain-text password + salt
|
||||
|
||||
function md5(str) {
|
||||
return crypto.createHash('md5').update(str).digest('hex');
|
||||
function hash(msg, key) {
|
||||
return crypto
|
||||
.createHmac('sha256', key)
|
||||
.update(msg)
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
// Authenticate using our plain-object database of doom!
|
||||
|
||||
function authenticate(name, pass, fn) {
|
||||
console.log('authenticating %s:%s', name, pass);
|
||||
var user = users[name];
|
||||
// query the db for the given username
|
||||
if (!user) return fn(new Error('cannot find user'));
|
||||
// apply the same algorithm to the POSTed password, applying
|
||||
// the md5 against the pass / salt, if there is a match we
|
||||
// the hash against the pass / salt, if there is a match we
|
||||
// found the user
|
||||
if (user.pass == md5(pass + user.salt)) return fn(null, user);
|
||||
if (user.pass == hash(pass, user.salt)) return fn(null, user);
|
||||
// Otherwise password is invalid
|
||||
fn(new Error('invalid password'));
|
||||
}
|
||||
@@ -71,16 +69,11 @@ function restrict(req, res, next) {
|
||||
}
|
||||
}
|
||||
|
||||
function accessLogger(req, res, next) {
|
||||
console.log('/restricted accessed by %s', req.session.user.name);
|
||||
next();
|
||||
}
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.redirect('/login');
|
||||
res.redirect('login');
|
||||
});
|
||||
|
||||
app.get('/restricted', restrict, accessLogger, function(req, res){
|
||||
app.get('/restricted', restrict, function(req, res){
|
||||
res.send('Wahoo! restricted area');
|
||||
});
|
||||
|
||||
@@ -88,7 +81,7 @@ app.get('/logout', function(req, res){
|
||||
// destroy the user's session to log them out
|
||||
// will be re-created next request
|
||||
req.session.destroy(function(){
|
||||
res.redirect('home');
|
||||
res.redirect('/');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -117,10 +110,12 @@ app.post('/login', function(req, res){
|
||||
req.session.error = 'Authentication failed, please check your '
|
||||
+ ' username and password.'
|
||||
+ ' (use "tj" and "foobar")';
|
||||
res.redirect('back');
|
||||
res.redirect('login');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<h1>Login</h1>
|
||||
<%- message %>
|
||||
Try accessing <a href="/restricted">/restricted</a>.
|
||||
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
|
||||
<form method="post" action="/login">
|
||||
<p>
|
||||
<label>Username:</label>
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, messages = require('express-messages');
|
||||
|
||||
var app = module.exports = express.createServer();
|
||||
|
||||
// Config
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// mount hook
|
||||
|
||||
app.mounted(function(other){
|
||||
console.log('ive been mounted!');
|
||||
});
|
||||
|
||||
// Flash message helper provided by express-messages
|
||||
// $ npm install express-messages
|
||||
|
||||
app.dynamicHelpers({
|
||||
messages: messages
|
||||
, base: function(){
|
||||
// return the app's mount-point
|
||||
// so that urls can adjust. For example
|
||||
// if you run this example /post/add works
|
||||
// however if you run the mounting example
|
||||
// it adjusts to /blog/post/add
|
||||
return '/' == app.route ? '' : app.route;
|
||||
}
|
||||
});
|
||||
|
||||
// Middleware
|
||||
|
||||
app.configure(function(){
|
||||
app.use(express.logger('\x1b[33m:method\x1b[0m \x1b[32m:url\x1b[0m :response-time'));
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: 'keyboard cat' }));
|
||||
app.use(app.router);
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
// Routes
|
||||
|
||||
require('./routes/site')(app);
|
||||
require('./routes/post')(app);
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
|
||||
// config
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// middleware
|
||||
|
||||
app.configure('development',function(){
|
||||
app.use(express.logger('dev'));
|
||||
})
|
||||
|
||||
app.configure(function(){
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(express.cookieParser('keyboard cat'));
|
||||
app.use(express.session());
|
||||
app.use(app.router);
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
// Locals
|
||||
|
||||
app.locals.use(function(req, res){
|
||||
// expose "error" and "message" to all
|
||||
// views that are rendered.
|
||||
res.locals.error = req.session.error || '';
|
||||
res.locals.message = req.session.message || '';
|
||||
// remove them so they're not displayed on subsequent renders
|
||||
delete req.session.error;
|
||||
delete req.session.message;
|
||||
});
|
||||
|
||||
// Routes
|
||||
|
||||
require('./routes/site')(app);
|
||||
require('./routes/post')(app);
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -17,11 +17,11 @@ Post.prototype.save = function(fn){
|
||||
};
|
||||
|
||||
Post.prototype.validate = function(fn){
|
||||
if (!this.title) return fn(new Error('_title_ required'));
|
||||
if (!this.body) return fn(new Error('_body_ required'));
|
||||
if (!this.title) return fn(new Error('title required'));
|
||||
if (!this.body) return fn(new Error('body required'));
|
||||
if (this.body.length < 10) {
|
||||
return fn(new Error(
|
||||
'_body_ should be at least **10** characters long, was only _' + this.title.length + '_'));
|
||||
'body should be at least 10 characters long, was only ' + this.title.length));
|
||||
}
|
||||
fn();
|
||||
};
|
||||
|
||||
@@ -41,18 +41,16 @@ a.edit {
|
||||
.date {
|
||||
font-size: 11px;
|
||||
}
|
||||
#messages ul {
|
||||
p.error,
|
||||
p.message {
|
||||
padding: 10px;
|
||||
border: 1px solid;
|
||||
}
|
||||
#messages ul li {
|
||||
list-style: none;
|
||||
p.error {
|
||||
background: #FDEAE7;
|
||||
color: #E4250C;
|
||||
}
|
||||
#messages ul.info {
|
||||
p.message {
|
||||
color: #2EBBE6;
|
||||
background: #F7FBFD;
|
||||
}
|
||||
#messages ul.error {
|
||||
color: #E4250C;
|
||||
background: #FDEAE7;
|
||||
}
|
||||
@@ -42,17 +42,17 @@ module.exports = function(app){
|
||||
*/
|
||||
|
||||
app.post('/post', function(req, res){
|
||||
var data = req.body.post
|
||||
var data = req.body.post || {}
|
||||
, post = new Post(data.title, data.body);
|
||||
|
||||
|
||||
post.validate(function(err){
|
||||
if (err) {
|
||||
req.flash('error', err.message);
|
||||
req.session.error = err.message;
|
||||
return res.redirect('back');
|
||||
}
|
||||
|
||||
post.save(function(err){
|
||||
req.flash('info', 'Successfully created post _%s_', post.title);
|
||||
req.session.message = 'Successfully created the post.';
|
||||
res.redirect('/post/' + post.id);
|
||||
});
|
||||
});
|
||||
@@ -82,12 +82,13 @@ module.exports = function(app){
|
||||
var post = req.post;
|
||||
post.validate(function(err){
|
||||
if (err) {
|
||||
req.flash('error', err.message);
|
||||
req.session.error = err.message;
|
||||
return res.redirect('back');
|
||||
}
|
||||
|
||||
post.update(req.body.post, function(err){
|
||||
if (err) return next(err);
|
||||
req.flash('info', 'Successfully updated post');
|
||||
req.session.message = 'Successfully updated post';
|
||||
res.redirect('back');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
h1 Blog
|
||||
extends layout
|
||||
|
||||
!= messages()
|
||||
block content
|
||||
h1 Blog
|
||||
|
||||
- if (count)
|
||||
p Display all #{count} post(s)
|
||||
#posts!= partial('post', posts)
|
||||
- else
|
||||
p
|
||||
| It looks like you have no posts!
|
||||
p
|
||||
| Click
|
||||
a(href=base + '/post/add') here
|
||||
| to create a post. Login
|
||||
| as
|
||||
em "admin"
|
||||
| and
|
||||
em "express"
|
||||
| .
|
||||
if count
|
||||
p Display all #{count} post(s)
|
||||
#posts
|
||||
each post in posts
|
||||
include post/index
|
||||
else
|
||||
p
|
||||
| It looks like you have no posts!
|
||||
p
|
||||
| Click
|
||||
a(href='/post/add') here
|
||||
| to create a post. Login
|
||||
| as
|
||||
em "admin"
|
||||
| and
|
||||
em "express"
|
||||
| .
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
html
|
||||
head
|
||||
title Blog
|
||||
link(rel='stylesheet', href=base + '/style.css')
|
||||
link(rel='stylesheet', href='/style.css')
|
||||
body
|
||||
#container!= body
|
||||
#container
|
||||
block content
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
if error
|
||||
p.error= error
|
||||
|
||||
if message
|
||||
p.message= message
|
||||
@@ -1,20 +1,22 @@
|
||||
extends ../layout
|
||||
|
||||
- if (post.title)
|
||||
h1 Editing #{post.title}
|
||||
- else
|
||||
h1 New Post
|
||||
block content
|
||||
if post.title
|
||||
h1 Editing #{post.title}
|
||||
else
|
||||
h1 New Post
|
||||
|
||||
!= messages()
|
||||
include ../messages
|
||||
|
||||
form#post(action=base + '/post' + (post.title ? '/' + post.id : ''), method='post')
|
||||
- if (post.title)
|
||||
input(type='hidden', name='_method', value='put')
|
||||
p
|
||||
label(for='post[title]') Title:
|
||||
input(type='text', name='post[title]', value=post.title)
|
||||
p
|
||||
label(for='post[body]') Body:
|
||||
textarea(name='post[body]')= post.body || ''
|
||||
p
|
||||
input(type='submit', value=post.title ? 'Update' : 'Create')
|
||||
|
||||
form#post(action='/post' + (post.title ? '/' + post.id : ''), method='post')
|
||||
if post.title
|
||||
input(type='hidden', name='_method', value='put')
|
||||
p
|
||||
label(for='post[title]') Title:
|
||||
input(type='text', name='post[title]', value=post.title)
|
||||
p
|
||||
label(for='post[body]') Body:
|
||||
textarea(name='post[body]')= post.body || ''
|
||||
p
|
||||
input(type='submit', value=post.title ? 'Update' : 'Create')
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
.post
|
||||
// title
|
||||
h2
|
||||
= post.title
|
||||
a.edit(href=base + '/post/' + post.id + '/edit') Edit
|
||||
|
||||
// flash messages
|
||||
!= messages()
|
||||
|
||||
// dates
|
||||
p.date.created Created at #{post.createdAt}
|
||||
- if (post.updatedAt)
|
||||
p.date.updated Updated at #{post.updatedAt}
|
||||
|
||||
// body
|
||||
pre.body= post.body
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
.post
|
||||
// title
|
||||
h2
|
||||
= post.title
|
||||
a.edit(href='/post/' + post.id + '/edit') Edit
|
||||
|
||||
include ../messages
|
||||
|
||||
// dates
|
||||
p.date.created Created at #{post.createdAt}
|
||||
if post.updatedAt
|
||||
p.date.updated Updated at #{post.updatedAt}
|
||||
|
||||
// body
|
||||
pre.body= post.body
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
|
||||
var users = [];
|
||||
|
||||
users.push({ name: 'Tobi' });
|
||||
users.push({ name: 'Loki' });
|
||||
users.push({ name: 'Jane' });
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.format({
|
||||
html: function(){
|
||||
res.send('<ul>' + users.map(function(user){
|
||||
return '<li>' + user.name + '</li>';
|
||||
}).join('') + '</ul>');
|
||||
},
|
||||
|
||||
text: function(){
|
||||
res.send(users.map(function(user){
|
||||
return ' - ' + user.name + '\n';
|
||||
}).join(''));
|
||||
},
|
||||
|
||||
json: function(){
|
||||
res.json(users);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('listening on port 3000');
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// pass a secret to cookieParser() for signed cookies
|
||||
app.use(express.cookieParser('manny is cool'));
|
||||
|
||||
// add req.session cookie support
|
||||
app.use(express.cookieSessions());
|
||||
|
||||
// do something with the session
|
||||
app.use(count);
|
||||
|
||||
// custom middleware
|
||||
function count(req, res) {
|
||||
req.session.count = req.session.count || 0;
|
||||
var n = req.session.count++;
|
||||
res.send('viewed ' + n + ' times\n');
|
||||
}
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
}
|
||||
+25
-20
@@ -1,27 +1,31 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
|
||||
var app = express.createServer(
|
||||
// Place default Connect favicon above logger so it is not in
|
||||
// the logging output
|
||||
express.favicon(),
|
||||
|
||||
// Custom logger format
|
||||
express.logger({ format: '\x1b[1m:method\x1b[0m \x1b[33m:url\x1b[0m :response-time' }),
|
||||
// add favicon() before logger() so
|
||||
// GET /favicon.ico requests are not
|
||||
// logged, because this middleware
|
||||
// reponds to /favicon.ico and does not
|
||||
// call next()
|
||||
app.use(express.favicon());
|
||||
|
||||
// Provides req.cookies
|
||||
express.cookieParser(),
|
||||
// custom log format
|
||||
if ('test' != process.env.NODE_ENV)
|
||||
app.use(express.logger(':method :url'));
|
||||
|
||||
// Parses x-www-form-urlencoded request bodies (and json)
|
||||
express.bodyParser()
|
||||
);
|
||||
// parses request cookies, populating
|
||||
// req.cookies and req.signedCookies
|
||||
// when the secret is passed, used
|
||||
// for signing the cookies.
|
||||
app.use(express.cookieParser('my secret here'));
|
||||
|
||||
// parses json, x-www-form-urlencoded, and multipart/form-data
|
||||
app.use(express.bodyParser());
|
||||
|
||||
app.get('/', function(req, res){
|
||||
if (req.cookies.remember) {
|
||||
@@ -39,11 +43,12 @@ app.get('/forget', function(req, res){
|
||||
});
|
||||
|
||||
app.post('/', function(req, res){
|
||||
if (req.body.remember) {
|
||||
res.cookie('remember', '1', { path: '/', expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||
}
|
||||
var minute = 60000;
|
||||
if (req.body.remember) res.cookie('remember', 1, { maxAge: minute });
|
||||
res.redirect('back');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
if (!module.parent){
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
+18
-21
@@ -1,14 +1,10 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('<ul>'
|
||||
@@ -22,26 +18,27 @@ app.get('/', function(req, res){
|
||||
app.get('/files/:file(*)', function(req, res, next){
|
||||
var file = req.params.file
|
||||
, path = __dirname + '/files/' + file;
|
||||
// either res.download(path) and let
|
||||
// express handle failures, or provide
|
||||
// a callback
|
||||
res.download(path, function(err){
|
||||
if (err) return next(err);
|
||||
// the response has invoked .end()
|
||||
// so you cannnot respond here (of course)
|
||||
// but the callback is handy for statistics etc.
|
||||
console.log('transferred %s', path);
|
||||
});
|
||||
|
||||
res.download(path);
|
||||
});
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
if ('ENOENT' == err.code) {
|
||||
// error handling middleware. Because it's
|
||||
// below our routes, you will be able to
|
||||
// "intercept" errors, otherwise Connect
|
||||
// will respond with 500 "Internal Server Error".
|
||||
app.use(function(err, req, res, next){
|
||||
// special-case 404s,
|
||||
// remember you could
|
||||
// render a 404 template here
|
||||
if (404 == err.status) {
|
||||
res.statusCode = 404;
|
||||
res.send('Cant find that file, sorry!');
|
||||
} else {
|
||||
// Not a 404
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Register ejs as .html
|
||||
|
||||
app.register('.html', require('ejs'));
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// 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', { users: users });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// Register ejs as .html. If we did
|
||||
// not call this, we would need to
|
||||
// name our views foo.ejs instead
|
||||
// of foo.html. The __express method
|
||||
// is simply a function that engines
|
||||
// use to hook into the Express view
|
||||
// system by default, so if we want
|
||||
// to change "foo.ejs" to "foo.html"
|
||||
// we simply pass _any_ function, in this
|
||||
// case `ejs.__express`.
|
||||
|
||||
app.engine('.html', require('ejs').__express);
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Without this you would need to
|
||||
// supply the extension to res.render()
|
||||
// ex: res.render('users.html').
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tobi', email: 'tobi@learnboost.com' }
|
||||
, { name: 'loki', email: 'loki@learnboost.com' }
|
||||
, { name: 'jane', email: 'jane@learnboost.com' }
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users', { users: users });
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Users</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
<h1>Users</h1>
|
||||
<ul id="users">
|
||||
<% users.forEach(function(user){ %>
|
||||
<li><%= user.name %> <%= user.email %></li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
@@ -1,3 +0,0 @@
|
||||
<ul id="users">
|
||||
<%- partial('user', users) %>
|
||||
</ul>
|
||||
@@ -1 +0,0 @@
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
@@ -1,81 +1,72 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
var express = require('../../')
|
||||
, app = module.exports = express()
|
||||
, silent = 'test' == process.env.NODE_ENV;
|
||||
|
||||
var app = express.createServer();
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// Serve default connect favicon
|
||||
app.use(express.favicon());
|
||||
|
||||
// Logger is placed below favicon, so favicon.ico
|
||||
// requests will not be logged
|
||||
app.use(express.logger({ format: '":method :url" :status' }));
|
||||
silent || app.use(express.logger('dev'));
|
||||
|
||||
// "app.router" positions our routes
|
||||
// specifically above the middleware
|
||||
// assigned below
|
||||
// above the middleware defined below,
|
||||
// this means that Express will attempt
|
||||
// to match & call routes _before_ continuing
|
||||
// on, at which point we assume it's a 404 because
|
||||
// no route has handled the request.
|
||||
|
||||
app.use(app.router);
|
||||
|
||||
// When no more middleware require execution, aka
|
||||
// our router is finished and did not respond, we
|
||||
// can assume that it is "not found". Instead of
|
||||
// letting Connect deal with this, we define our
|
||||
// custom middleware here to simply pass a NotFound
|
||||
// exception
|
||||
// Since this is the last non-error-handling
|
||||
// middleware use()d, we assume 404, as nothing else
|
||||
// responded.
|
||||
|
||||
// $ curl http://localhost:3000/notfound
|
||||
// $ curl http://localhost:3000/notfound -H "Accept: application/json"
|
||||
// $ curl http://localhost:3000/notfound -H "Accept: text/plain"
|
||||
|
||||
app.use(function(req, res, next){
|
||||
next(new NotFound(req.url));
|
||||
// respond with html page
|
||||
if (req.accepts('html')) {
|
||||
res.status(404);
|
||||
res.render('404', { url: req.url });
|
||||
return;
|
||||
}
|
||||
|
||||
// respond with json
|
||||
if (req.accepts('json')) {
|
||||
res.send({ error: 'Not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
// default to plain-text. send()
|
||||
res.type('txt').send('Not found');
|
||||
});
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
// error-handling middleware, take the same form
|
||||
// as regular middleware, however they require an
|
||||
// arity of 4, aka the signature (err, req, res, next).
|
||||
// when connect has an error, it will invoke ONLY error-handling
|
||||
// middleware.
|
||||
|
||||
// Provide our app with the notion of NotFound exceptions
|
||||
// If we were to next() here any remaining non-error-handling
|
||||
// middleware would then be executed, or if we next(err) to
|
||||
// continue passing the error, only error-handling middleware
|
||||
// would remain being executed, however here
|
||||
// we simply respond with an error page.
|
||||
|
||||
function NotFound(path){
|
||||
this.name = 'NotFound';
|
||||
if (path) {
|
||||
Error.call(this, 'Cannot find ' + path);
|
||||
this.path = path;
|
||||
} else {
|
||||
Error.call(this, 'Not Found');
|
||||
}
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Error.prototype`.
|
||||
*/
|
||||
|
||||
NotFound.prototype.__proto__ = Error.prototype;
|
||||
|
||||
// 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.
|
||||
|
||||
// These handlers could potentially be defined within
|
||||
// configure() blocks to provide introspection when
|
||||
// in the development environment.
|
||||
|
||||
app.error(function(err, req, res, next){
|
||||
if (err instanceof NotFound) {
|
||||
res.render('404.jade', { status: 404, error: err });
|
||||
} 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', { status: 500, error: err });
|
||||
app.use(function(err, req, res, next){
|
||||
// we may use properties of the error object
|
||||
// here and next(err) appropriately, or if
|
||||
// we possibly recovered from the error, simply next().
|
||||
res.status(err.status || 500);
|
||||
res.render('500', { error: err });
|
||||
});
|
||||
|
||||
// Routes
|
||||
@@ -84,13 +75,21 @@ app.get('/', function(req, res){
|
||||
res.render('index.jade');
|
||||
});
|
||||
|
||||
app.get('/404', function(req, res){
|
||||
throw new NotFound(req.url);
|
||||
app.get('/404', function(req, res, next){
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/403', function(req, res, next){
|
||||
var err = new Error('not allowed!');
|
||||
err.status = 403;
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res, next){
|
||||
next(new Error('keyboard cat!'));
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
silent || console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
- if (error.path)
|
||||
h2 Cannot find #{error.path}
|
||||
- else
|
||||
h2 Page Not Found
|
||||
|
||||
extends error
|
||||
|
||||
block content
|
||||
h2 Cannot find #{url}
|
||||
@@ -1,2 +1,10 @@
|
||||
h1 Error: #{error.message}
|
||||
pre= error.stack
|
||||
|
||||
// note that we extend a different
|
||||
// layout with jade for 4xx & 5xx
|
||||
// responses
|
||||
|
||||
extends error
|
||||
|
||||
block content
|
||||
h1 Error: #{error.message}
|
||||
pre= error.stack
|
||||
@@ -0,0 +1,6 @@
|
||||
html
|
||||
head
|
||||
title Error
|
||||
body
|
||||
h1 An error occurred!
|
||||
block content
|
||||
@@ -1,8 +1,15 @@
|
||||
h2 Pages Example
|
||||
ul
|
||||
li
|
||||
| visit
|
||||
a(href="/500") 500
|
||||
li
|
||||
| visit
|
||||
a(href="/404") 404
|
||||
|
||||
extends layout
|
||||
|
||||
block content
|
||||
h2 Pages Example
|
||||
ul
|
||||
li
|
||||
| visit
|
||||
a(href="/500") 500
|
||||
li
|
||||
| visit
|
||||
a(href="/404") 404
|
||||
li
|
||||
| visit
|
||||
a(href='/403') 403
|
||||
@@ -3,4 +3,4 @@ html
|
||||
title Custom Pages Example
|
||||
body
|
||||
h1 My Site
|
||||
!= body
|
||||
block content
|
||||
+33
-12
@@ -1,14 +1,35 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
|
||||
var app = express.createServer();
|
||||
if ('test' != process.env.NODE_ENV)
|
||||
app.use(express.logger('dev'));
|
||||
app.use(app.router);
|
||||
|
||||
// the error handler is strategically
|
||||
// placed *below* the app.router; if it
|
||||
// were above it would not receive errors
|
||||
// from app.get() etc
|
||||
app.use(error);
|
||||
|
||||
// error handling middleware have an arity of 4
|
||||
// instead of the typical (req, res, next),
|
||||
// otherwise they behave exactly like regular
|
||||
// middleware, you may have several of them,
|
||||
// in different orders etc.
|
||||
|
||||
function error(err, req, res, next) {
|
||||
// log it
|
||||
if ('test' != process.env.NODE_ENV)
|
||||
console.error(err.stack);
|
||||
|
||||
// respond with 500 "Internal Server Error".
|
||||
res.send(500);
|
||||
}
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// Caught and passed down to the errorHandler middleware
|
||||
@@ -17,12 +38,12 @@ app.get('/', function(req, res){
|
||||
|
||||
app.get('/next', function(req, res, next){
|
||||
// We can also pass exceptions to next()
|
||||
next(new Error('oh no!'))
|
||||
process.nextTick(function(){
|
||||
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('/', express.errorHandler({ dump: true, stack: true }));
|
||||
|
||||
app.listen(3000);
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
// App with session support
|
||||
|
||||
var app = express.createServer(
|
||||
express.cookieParser()
|
||||
, express.session({ secret: 'keyboard cat' })
|
||||
);
|
||||
|
||||
// View settings
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
app.dynamicHelpers({
|
||||
// express-messages is a dynamicHelper that
|
||||
// renders the flash messages to HTML for you
|
||||
// $ npm install express-messages
|
||||
messages: require('express-messages')
|
||||
});
|
||||
|
||||
app.dynamicHelpers({
|
||||
// Another dynamic helper example. Since dynamic
|
||||
// helpers resolve at view rendering time, we can
|
||||
// "inject" the "page" local variable per request
|
||||
// providing us with the request url.
|
||||
page: function(req, res){
|
||||
return req.url;
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// Not very realistic notifications but illustrates usage
|
||||
req.flash('info', 'email queued');
|
||||
req.flash('info', 'email sent');
|
||||
req.flash('error', 'delivery failed');
|
||||
res.render('index');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -1,3 +0,0 @@
|
||||
<h1>Flash Message Example</h1>
|
||||
<p>on page <%- page %></p>
|
||||
<%- messages() %>
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,14 +1,10 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
var express = require('../../');
|
||||
|
||||
var app = express.createServer();
|
||||
var app = module.exports = express();
|
||||
|
||||
// Here we use the bodyDecoder middleware
|
||||
// to parse urlencoded request bodies
|
||||
@@ -77,5 +73,7 @@ app.put('/', function(req, res){
|
||||
res.redirect('/?name=' + req.body.name);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
var express = require('../../');
|
||||
|
||||
var app = express.createServer();
|
||||
var app = module.exports = express();
|
||||
|
||||
// Fake items
|
||||
|
||||
@@ -48,8 +45,7 @@ app.get('/item/:id.:format?', function(req, res, next){
|
||||
+ '<items>'
|
||||
+ '<item>' + item.name + '</item>'
|
||||
+ '</items>';
|
||||
res.contentType('.xml');
|
||||
res.send(xml);
|
||||
res.type('xml').send(xml);
|
||||
break;
|
||||
case 'html':
|
||||
default:
|
||||
@@ -65,7 +61,9 @@ app.get('/item/:id.:format?', function(req, res, next){
|
||||
|
||||
// Middleware
|
||||
|
||||
app.use(express.errorHandler({ showStack: true }));
|
||||
app.use(express.errorHandler());
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
silent || console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -9,7 +6,7 @@ require.paths.unshift(__dirname + '/../../support');
|
||||
var express = require('../../lib/express')
|
||||
, http = require('http');
|
||||
|
||||
var app = express.createServer();
|
||||
var app = express();
|
||||
|
||||
// Expose our views
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
- 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)
|
||||
|
||||
extends layout
|
||||
|
||||
block content
|
||||
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
|
||||
for repo in user.repos
|
||||
include repo
|
||||
@@ -4,4 +4,5 @@ html
|
||||
title Github Example
|
||||
link(rel="stylesheet", href="/style.css")
|
||||
body
|
||||
#container!= body
|
||||
#container
|
||||
block content
|
||||
@@ -3,12 +3,13 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
var express = require('../../');
|
||||
|
||||
var app = express.createServer();
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
head
|
||||
title Jade Example
|
||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||
@@ -1,6 +1,4 @@
|
||||
!!!
|
||||
html
|
||||
head
|
||||
title Jade Example
|
||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||
include header
|
||||
body!= body
|
||||
@@ -1,33 +1,51 @@
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
var express = require('../../lib/express')
|
||||
, url = require('url');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// set default layout, usually "layout"
|
||||
app.set('view options', { layout: 'layouts/default' });
|
||||
// map .html to ejs module
|
||||
app.register('html', require('ejs'));
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// Set our default template engine to "ejs"
|
||||
// which prevents the need for extensions
|
||||
// (although you can still mix and match)
|
||||
app.set('view engine', 'ejs');
|
||||
// set default layout, usually "layout"
|
||||
app.locals.layout = 'layouts/default';
|
||||
|
||||
app.use(function(req, res, next){
|
||||
// expose the current path as a view local
|
||||
res.locals.path = url.parse(req.url).pathname;
|
||||
|
||||
// assign content str for section
|
||||
res.locals.contentFor = function(section, str){
|
||||
res.locals[section] = str;
|
||||
};
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('pages/default');
|
||||
res.render('page');
|
||||
});
|
||||
|
||||
app.get('/alternate', function(req, res){
|
||||
res.render('page', { layout: 'layouts/alternate' });
|
||||
});
|
||||
|
||||
app.get('/alternate2', function(req, res){
|
||||
res.render('page2');
|
||||
});
|
||||
|
||||
app.get('/defined-in-view', function(req, res){
|
||||
// note that we do not explicitly
|
||||
// state the layout here, the view does,
|
||||
// although we could do it here as well.
|
||||
res.render('pages/alternate');
|
||||
res.render('pages');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<p>Moar sidebar here</p>
|
||||
@@ -1,6 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Alternate Layout</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<html>
|
||||
<title>Alternate</title>
|
||||
<style>
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 14px "helvetica neue", helvetica, sans-serif;
|
||||
color: #333;
|
||||
}
|
||||
#sidebar {
|
||||
float: left;
|
||||
width: 150px;
|
||||
}
|
||||
#content {
|
||||
float: left;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1>Alternate Layout</h1>
|
||||
<div id="sidebar">
|
||||
<%- sidebar %>
|
||||
</div>
|
||||
<div id="content">
|
||||
<%- body %>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Default Layout</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Default</title>
|
||||
<style>
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 14px "helvetica neue", helvetica, sans-serif;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Default Layout</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<h1>Page</h1>
|
||||
<% if (path == '/alternate') { %>
|
||||
<% contentFor('sidebar', partial('alternate-sidebar')) %>
|
||||
<p>Click <a href="/">here</a> to view the default layout.</p>
|
||||
<p>Click <a href="/alternate2">here</a> to view another alternate page.</p>
|
||||
<% } else { %>
|
||||
<p>Click <a href="/alternate">here</a> to view the alternate layout.</p>
|
||||
<% } %>
|
||||
@@ -0,0 +1,4 @@
|
||||
<% layout('layouts/alternate') %>
|
||||
<% contentFor('sidebar', '<p>Another sidebar here</p>') %>
|
||||
<h1>Page</h1>
|
||||
<p>Click <a href="/">here</a> to view the default layout.</p>
|
||||
@@ -1,2 +0,0 @@
|
||||
<% layout('layouts/alternate') %>
|
||||
<h1>Page</h1>
|
||||
@@ -1 +0,0 @@
|
||||
<h1>Page</h1>
|
||||
@@ -1,41 +0,0 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
// $ npm install markdown
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, md = require('markdown').markdown;
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// register .md so that markdown may comply
|
||||
// with the express view system by implementing
|
||||
// a .compile() method
|
||||
|
||||
app.register('.md', {
|
||||
compile: function(str, options){
|
||||
var html = md.toHTML(str);
|
||||
return function(locals){
|
||||
return html.replace(/\{([^}]+)\}/g, function(_, name){
|
||||
return locals[name];
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'md');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index', { layout: false, title: 'Markdown Example' });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, fs = require('fs')
|
||||
, md = require('github-flavored-markdown').parse;
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// register .md as an engine in express view system
|
||||
|
||||
app.engine('md', function(path, options, fn){
|
||||
fs.readFile(path, 'utf8', function(err, str){
|
||||
if (err) return fn(err);
|
||||
try {
|
||||
var html = md(str);
|
||||
html = html.replace(/\{([^}]+)\}/g, function(_, name){
|
||||
return options[name] || '';
|
||||
})
|
||||
fn(null, html);
|
||||
} catch(err) {
|
||||
fn(err);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// make it the default so we dont need .md
|
||||
app.set('view engine', 'md');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index', { title: 'Markdown Example' });
|
||||
})
|
||||
|
||||
app.get('/fail', function(req, res){
|
||||
res.render('missing', { title: 'Markdown Example' });
|
||||
})
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, blog = require('../blog/app');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: 'keyboard cat' }));
|
||||
|
||||
// mount the blog. the blog app is written using the "base"
|
||||
// local variable, allowing it's urls to adjust to wherever
|
||||
// we wish to mount it.
|
||||
app.use('/blog', blog);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Visit <a href="/blog">/blog</a>');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Server listening on port 3000');
|
||||
+19
-34
@@ -1,51 +1,36 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, form = require('connect-form');
|
||||
var express = require('../../')
|
||||
, format = require('util').format;
|
||||
|
||||
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({ keepExtensions: true })
|
||||
);
|
||||
var app = module.exports = express()
|
||||
|
||||
// bodyParser in connect 2.x uses node-formidable to parse
|
||||
// the multipart form data.
|
||||
app.use(express.bodyParser())
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('<form method="post" enctype="multipart/form-data">'
|
||||
+ '<p>Title: <input type="text" name="title" /></p>'
|
||||
+ '<p>Image: <input type="file" name="image" /></p>'
|
||||
+ '<p><input type="submit" value="Upload" /></p>'
|
||||
+ '</form>');
|
||||
});
|
||||
|
||||
app.post('/', function(req, res, 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 {
|
||||
console.log('\nuploaded %s to %s'
|
||||
, files.image.filename
|
||||
, files.image.path);
|
||||
res.redirect('back');
|
||||
}
|
||||
});
|
||||
|
||||
// We can add listeners for several form
|
||||
// events such as "progress"
|
||||
req.form.on('progress', function(bytesReceived, bytesExpected){
|
||||
var percent = (bytesReceived / bytesExpected * 100) | 0;
|
||||
process.stdout.write('Uploading: %' + percent + '\r');
|
||||
});
|
||||
// the uploaded file can be found as `req.files.image` and the
|
||||
// title field as `req.body.title`
|
||||
res.send(format('\nuploaded %s (%d Kb) to %s as %s'
|
||||
, req.files.image.name
|
||||
, req.files.image.size / 1024 | 0
|
||||
, req.files.image.path
|
||||
, req.body.title));
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -23,8 +23,7 @@ function bootApplication(app) {
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// Example 500 page
|
||||
app.error(function(err, req, res){
|
||||
console.dir(err)
|
||||
app.use(function(err, req, res, next){
|
||||
res.render('500');
|
||||
});
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, app = express.createServer();
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
|
||||
// Faux database
|
||||
|
||||
@@ -21,7 +18,14 @@ var users = [
|
||||
|
||||
// Convert :to and :from to integers
|
||||
|
||||
app.param(['to', 'from'], function(n){ return parseInt(n, 10); });
|
||||
app.param(['to', 'from'], function(req, res, next, num, name){
|
||||
req.params[name] = num = parseInt(num, 10);
|
||||
if( isNaN(num) ){
|
||||
next(new Error('failed to parseInt '+num));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
// Load user by id
|
||||
|
||||
@@ -60,5 +64,7 @@ app.get('/users/:from-:to', function(req, res, next){
|
||||
res.send('users ' + names.slice(from, to).join(', '));
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express application listening on port 3000');
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
var express = require('../../');
|
||||
|
||||
var app = express.createServer();
|
||||
var app = module.exports = express();
|
||||
|
||||
// Ad-hoc example resource method
|
||||
|
||||
@@ -88,5 +85,7 @@ app.get('/', function(req, res){
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, redis = require('redis')
|
||||
, app = express.createServer()
|
||||
, db = { users: [] };
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
app.use(express.bodyParser());
|
||||
|
||||
// pretend db is a database, could be
|
||||
// whatever you like
|
||||
require('./boot')(app, db);
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var vm = require('vm')
|
||||
, fs = require('fs');
|
||||
|
||||
module.exports = function(app, db){
|
||||
var dir = __dirname + '/routes';
|
||||
// grab a list of our route files
|
||||
fs.readdirSync(dir).forEach(function(file){
|
||||
var str = fs.readFileSync(dir + '/' + file, 'utf8');
|
||||
// inject some pseudo globals by evaluating
|
||||
// the file with vm.runInNewContext()
|
||||
// instead of loading it with require(). require's
|
||||
// internals use similar, so dont be afraid of "boot time".
|
||||
var context = { app: app, db: db };
|
||||
// we have to merge the globals for console, process etc
|
||||
for (var key in global) context[key] = global[key];
|
||||
// note that this is essentially no different than ... just using
|
||||
// global variables, though it's only YOUR code that could influence
|
||||
// them, which is a bonus.
|
||||
vm.runInNewContext(str, context, file);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index');
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
app.redirect('user list', '/users');
|
||||
|
||||
app.get('/users', function(req, res){
|
||||
res.render('user/list', { users: db.users });
|
||||
});
|
||||
|
||||
app.get('/user/add', function(req, res){
|
||||
res.render('user/add');
|
||||
});
|
||||
|
||||
app.post('/user', function(req, res){
|
||||
var user = req.body.user;
|
||||
db.users.push(user);
|
||||
res.redirect('user list');
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res){
|
||||
res.render('user');
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
h2 Route sharing example
|
||||
ul
|
||||
li: a(href='/user/add') Add user
|
||||
li: a(href='/users') User list
|
||||
@@ -0,0 +1,11 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title Route loading example
|
||||
style
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 14px/1.5 solid helvetica, arial, sans-serif;
|
||||
}
|
||||
body
|
||||
#content!= body
|
||||
@@ -0,0 +1,5 @@
|
||||
h2 Add a user
|
||||
form(action='/user', method='post')
|
||||
p: input(type='text', name='user[name]', placeholder='Username')
|
||||
p: input(type='text', name='user[email]', placeholder='Email')
|
||||
p: input(type='submit', value='Add')
|
||||
@@ -0,0 +1,6 @@
|
||||
h1= user.name
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
td Email
|
||||
td= user.email
|
||||
@@ -0,0 +1,5 @@
|
||||
h1 Users
|
||||
- if (users.length)
|
||||
!= partial('user', users)
|
||||
- else
|
||||
p No users, head over to <a href='/user/add'>/user/add</a> to create one.
|
||||
@@ -1,7 +1,3 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -43,7 +39,7 @@ function andRestrictToSelf(req, res, next) {
|
||||
} else {
|
||||
// You may want to implement specific exceptions
|
||||
// such as UnauthorizedError or similar so that you
|
||||
// can handle these in app.error() specifically
|
||||
// can handle these can be special-cased in an error handler
|
||||
// (view ./examples/pages for this)
|
||||
next(new Error('Unauthorized'));
|
||||
}
|
||||
@@ -62,7 +58,7 @@ function andRestrictTo(role) {
|
||||
// Middleware for faux authentication
|
||||
// you would of course implement something real,
|
||||
// but this illustrates how an authenticated user
|
||||
// may interacte with middleware
|
||||
// may interact with middleware
|
||||
|
||||
app.use(function(req, res, next){
|
||||
req.authenticatedUser = users[0];
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
+17
-15
@@ -1,28 +1,30 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
// $ npm install connect-redis
|
||||
var RedisStore = require('connect-redis');
|
||||
// pass the express to the connect redis module
|
||||
// allowing it to inherit from express.session.Store
|
||||
var RedisStore = require('connect-redis')(express);
|
||||
|
||||
var app = express.createServer(
|
||||
express.logger(),
|
||||
var app = express.createServer();
|
||||
|
||||
// Required by session() middleware
|
||||
express.cookieDecoder(),
|
||||
app.use(express.favicon());
|
||||
|
||||
// Populates:
|
||||
// - req.session
|
||||
// - req.sessionStore
|
||||
// - req.sessionID (or req.session.id)
|
||||
express.session({ secret: 'keyboard cat', store: new RedisStore })
|
||||
);
|
||||
// request logging
|
||||
app.use(express.logger());
|
||||
|
||||
// required to parse the session cookie
|
||||
app.use(express.cookieParser());
|
||||
|
||||
// Populates:
|
||||
// - req.session
|
||||
// - req.sessionStore
|
||||
// - req.sessionID (or req.session.id)
|
||||
|
||||
app.use(express.session({ secret: 'keyboard cat', store: new RedisStore }));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
var body = '';
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// create an error with .status. we
|
||||
// can then use the property in our
|
||||
// custom error handler (Connect repects this prop as well)
|
||||
|
||||
function error(status, msg) {
|
||||
var err = new Error(msg);
|
||||
err.status = status;
|
||||
return err;
|
||||
}
|
||||
|
||||
// if we wanted to supply more than JSON, we could
|
||||
// use something similar to the content-negotiation
|
||||
// example.
|
||||
|
||||
// here we validate the API key,
|
||||
// by mounting this middleware to /api
|
||||
// meaning only paths prefixed with "/api"
|
||||
// will cause this middleware to be invoked
|
||||
|
||||
app.use('/api', function(req, res, next){
|
||||
var key = req.query['api-key'];
|
||||
|
||||
// key isnt present
|
||||
if (!key) return next(error(400, 'api key required'));
|
||||
|
||||
// key is invalid
|
||||
if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));
|
||||
|
||||
// all good, store req.key for route access
|
||||
req.key = key;
|
||||
next();
|
||||
});
|
||||
|
||||
// position our routes above the error handling middleware,
|
||||
// and below our API middleware, since we want the API validation
|
||||
// to take place BEFORE our routes
|
||||
app.use(app.router);
|
||||
|
||||
// middleware with an arity of 4 are considered
|
||||
// error handling middleware. When you next(err)
|
||||
// it will be passed through the defined middleware
|
||||
// in order, but ONLY those with an arity of 4, ignoring
|
||||
// regular middleware.
|
||||
app.use(function(err, req, res, next){
|
||||
// whatever you want here, feel free to populate
|
||||
// properties on `err` to treat it differently in here.
|
||||
res.send(err.status || 500, { error: err.message });
|
||||
});
|
||||
|
||||
// our custom JSON 404 middleware. Since it's placed last
|
||||
// it will be the last middleware called, if all others
|
||||
// invoke next() and do not respond.
|
||||
app.use(function(req, res){
|
||||
res.send(404, { error: "Lame, can't find that" });
|
||||
});
|
||||
|
||||
// map of valid api keys, typically mapped to
|
||||
// account info with some sort of database like redis.
|
||||
// api keys do _not_ serve as authentication, merely to
|
||||
// track API usage or help prevent malicious behavior etc.
|
||||
|
||||
var apiKeys = ['foo', 'bar', 'baz'];
|
||||
|
||||
// these two objects will serve as our faux database
|
||||
|
||||
var repos = [
|
||||
{ name: 'express', url: 'http://github.com/visionmedia/express' }
|
||||
, { name: 'stylus', url: 'http://github.com/learnboost/stylus' }
|
||||
, { name: 'cluster', url: 'http://github.com/learnboost/cluster' }
|
||||
];
|
||||
|
||||
var users = [
|
||||
{ name: 'tobi' }
|
||||
, { name: 'loki' }
|
||||
, { name: 'jane' }
|
||||
];
|
||||
|
||||
var userRepos = {
|
||||
tobi: [repos[0], repos[1]]
|
||||
, loki: [repos[1]]
|
||||
, jane: [repos[2]]
|
||||
};
|
||||
|
||||
// we now can assume the api key is valid,
|
||||
// and simply expose the data
|
||||
|
||||
app.get('/api/users', function(req, res, next){
|
||||
res.send(users);
|
||||
});
|
||||
|
||||
app.get('/api/repos', function(req, res, next){
|
||||
res.send(repos);
|
||||
});
|
||||
|
||||
app.get('/api/user/:name/repos', function(req, res, next){
|
||||
var name = req.params.name
|
||||
, user = userRepos[name];
|
||||
|
||||
if (user) res.send(user);
|
||||
else next();
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
}
|
||||
+3
-1
@@ -1,2 +1,4 @@
|
||||
|
||||
module.exports = require('./lib/express');
|
||||
module.exports = process.env.EXPRESS_COV
|
||||
? require('./lib-cov/express')
|
||||
: require('./lib/express');
|
||||
@@ -0,0 +1,535 @@
|
||||
|
||||
/*!
|
||||
* Express - proto
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var connect = require('connect')
|
||||
, Router = require('./router')
|
||||
, methods = Router.methods.concat('del', 'all')
|
||||
, middleware = require('./middleware')
|
||||
, debug = require('debug')('express:application')
|
||||
, View = require('./view')
|
||||
, url = require('url')
|
||||
, utils = connect.utils
|
||||
, path = require('path')
|
||||
, http = require('http')
|
||||
, join = path.join
|
||||
, fs = require('fs');
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
*/
|
||||
|
||||
var app = exports = module.exports = {};
|
||||
|
||||
/**
|
||||
* Initialize the server.
|
||||
*
|
||||
* - setup default configuration
|
||||
* - setup default middleware
|
||||
* - setup route reflection methods
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.init = function(){
|
||||
var self = this;
|
||||
this.cache = {};
|
||||
this.settings = {};
|
||||
this.engines = {};
|
||||
this.viewCallbacks = [];
|
||||
this.defaultConfiguration();
|
||||
|
||||
// route reflection methods
|
||||
methods.forEach(function(method){
|
||||
self.lookup[method] = function(path){
|
||||
return self._router.lookup(method, path);
|
||||
};
|
||||
|
||||
self.remove[method] = function(path){
|
||||
return self._router.lookup(method, path).remove();
|
||||
};
|
||||
});
|
||||
|
||||
// del -> delete
|
||||
self.lookup.del = self.lookup.delete;
|
||||
self.remove.del = self.remove.delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize application configuration.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.defaultConfiguration = function(){
|
||||
var self = this;
|
||||
|
||||
// default settings
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
|
||||
// implicit middleware
|
||||
this.use(connect.query());
|
||||
this.use(middleware.init(this));
|
||||
|
||||
// app locals
|
||||
this.locals = function(obj){
|
||||
for (var key in obj) self.locals[key] = obj[key];
|
||||
return self;
|
||||
};
|
||||
|
||||
// response locals
|
||||
this.locals.use = function(fn){
|
||||
if (3 == fn.length) {
|
||||
self.viewCallbacks.push(fn);
|
||||
} else {
|
||||
self.viewCallbacks.push(function(req, res, done){
|
||||
fn(req, res);
|
||||
done();
|
||||
});
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// router
|
||||
this._router = new Router(this);
|
||||
this.routes = this._router.routes;
|
||||
this.__defineGetter__('router', function(){
|
||||
this._usedRouter = true;
|
||||
this._router.caseSensitive = this.enabled('case sensitive routing');
|
||||
this._router.strict = this.enabled('strict routing');
|
||||
return this._router.middleware;
|
||||
});
|
||||
|
||||
// default locals
|
||||
this.locals.settings = this.settings;
|
||||
|
||||
// default configuration
|
||||
this.enable('jsonp callback');
|
||||
|
||||
this.configure('development', function(){
|
||||
this.set('json spaces', 2);
|
||||
});
|
||||
|
||||
this.configure('production', function(){
|
||||
this.enable('view cache');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove routes matching the given `path`.
|
||||
*
|
||||
* @param {Route} path
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.remove = function(path){
|
||||
return this._router.lookup('all', path).remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup routes defined with a path
|
||||
* equivalent to `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.lookup = function(path){
|
||||
return this._router.lookup('all', path);
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy `connect#use()` to apply settings to
|
||||
* mounted applications.
|
||||
*
|
||||
* @param {String|Function|Server} route
|
||||
* @param {Function|Server} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.use = function(route, fn){
|
||||
var app, home, handle;
|
||||
|
||||
// default route to '/'
|
||||
if ('string' != typeof route) fn = route, route = '/';
|
||||
|
||||
// express app
|
||||
if (fn.handle && fn.set) app = fn;
|
||||
|
||||
// restore .app property on req and res
|
||||
if (app) {
|
||||
app.route = route;
|
||||
fn = function(req, res, next) {
|
||||
var orig = req.app;
|
||||
app.handle(req, res, function(err){
|
||||
req.app = res.app = orig;
|
||||
next(err);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
connect.proto.use.call(this, route, fn);
|
||||
|
||||
// mounted an app
|
||||
if (app) {
|
||||
app.parent = this;
|
||||
app.emit('mount', this);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given template engine callback `fn`
|
||||
* as `ext`. For example we may wish to map ".html"
|
||||
* files to ejs rather than using the ".ejs" extension.
|
||||
*
|
||||
* app.engine('.html', require('ejs').render);
|
||||
*
|
||||
* or
|
||||
*
|
||||
* app.engine('html', require('ejs').render);
|
||||
*
|
||||
* @param {String} ext
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.engine = function(ext, fn){
|
||||
if ('function' != typeof fn) throw new Error('callback function required');
|
||||
if ('.' != ext[0]) ext = '.' + ext;
|
||||
this.engines[ext] = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map the given param placeholder `name`(s) to the given callback(s).
|
||||
*
|
||||
* Param mapping is used to provide pre-conditions to routes
|
||||
* which us normalized placeholders. This callback has the same
|
||||
* signature as regular middleware, for example below when ":userId"
|
||||
* is used this function will be invoked in an attempt to load the user.
|
||||
*
|
||||
* app.param('userId', function(req, res, next, id){
|
||||
* User.find(id, function(err, user){
|
||||
* if (err) {
|
||||
* next(err);
|
||||
* } else if (user) {
|
||||
* req.user = user;
|
||||
* next();
|
||||
* } else {
|
||||
* next(new Error('failed to load user'));
|
||||
* }
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* Passing a single function allows you to map logic
|
||||
* to the values passed to `app.param()`, for example
|
||||
* this is useful to provide coercion support in a concise manner.
|
||||
*
|
||||
* The following example maps regular expressions to param values
|
||||
* ensuring that they match, otherwise passing control to the next
|
||||
* route:
|
||||
*
|
||||
* app.param(function(name, regexp){
|
||||
* if (regexp instanceof RegExp) {
|
||||
* return function(req, res, next, val){
|
||||
* var captures;
|
||||
* if (captures = regexp.exec(String(val))) {
|
||||
* req.params[name] = captures;
|
||||
* next();
|
||||
* } else {
|
||||
* next('route');
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* We can now use it as shown below, where "/commit/:commit" expects
|
||||
* that the value for ":commit" is at 5 or more digits. The capture
|
||||
* groups are then available as `req.params.commit` as we defined
|
||||
* in the function above.
|
||||
*
|
||||
* app.param('commit', /^\d{5,}$/);
|
||||
*
|
||||
* For more of this useful functionality take a look
|
||||
* at [express-params](http://github.com/visionmedia/express-params).
|
||||
*
|
||||
* @param {String|Array|Function} name
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.param = function(name, fn){
|
||||
var self = this
|
||||
, fns = [].slice.call(arguments, 1);
|
||||
|
||||
// array
|
||||
if (Array.isArray(name)) {
|
||||
name.forEach(function(name){
|
||||
fns.forEach(function(fn){
|
||||
self.param(name, fn);
|
||||
});
|
||||
});
|
||||
// param logic
|
||||
} else if ('function' == typeof name) {
|
||||
this._router.param(name);
|
||||
// single
|
||||
} else {
|
||||
if (':' == name[0]) name = name.substr(1);
|
||||
fns.forEach(function(fn){
|
||||
self._router.param(name, fn);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign `setting` to `val`, or return `setting`'s value.
|
||||
* Mounted servers inherit their parent server's settings.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @param {String} val
|
||||
* @return {Server|Mixed} for chaining, or the setting value
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.set = function(setting, val){
|
||||
if (1 == arguments.length) {
|
||||
if (this.settings.hasOwnProperty(setting)) {
|
||||
return this.settings[setting];
|
||||
} else if (this.parent) {
|
||||
return this.parent.set(setting);
|
||||
}
|
||||
} else {
|
||||
this.settings[setting] = val;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the app's absolute pathname
|
||||
* based on the parent(s) that have
|
||||
* mounted it.
|
||||
*
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.path = function(){
|
||||
return this.parent
|
||||
? this.parent.path() + this.route
|
||||
: '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `setting` is enabled.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.enabled = function(setting){
|
||||
return !!this.set(setting);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `setting` is disabled.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.disabled = function(setting){
|
||||
return !this.set(setting);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable `setting`.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.enable = function(setting){
|
||||
return this.set(setting, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable `setting`.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.disable = function(setting){
|
||||
return this.set(setting, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure callback for zero or more envs,
|
||||
* when no env is specified that callback will
|
||||
* be invoked for all environments. Any combination
|
||||
* can be used multiple times, in any order desired.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* app.configure(function(){
|
||||
* // executed for all envs
|
||||
* });
|
||||
*
|
||||
* app.configure('stage', function(){
|
||||
* // executed staging env
|
||||
* });
|
||||
*
|
||||
* app.configure('stage', 'production', function(){
|
||||
* // executed for stage and production
|
||||
* });
|
||||
*
|
||||
* @param {String} env...
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.configure = function(env, fn){
|
||||
var envs = 'all'
|
||||
, args = [].slice.call(arguments);
|
||||
fn = args.pop();
|
||||
if (args.length) envs = args;
|
||||
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Listen for connections.
|
||||
*
|
||||
* This method takes the same arguments
|
||||
* as node's `http.Server#listen()`.
|
||||
*
|
||||
* @return {http.Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.listen = function(){
|
||||
var server = http.createServer(this);
|
||||
return server.listen.apply(server, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Delegate `.VERB(...)` calls to `.route(VERB, ...)`.
|
||||
*/
|
||||
|
||||
methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
if ('get' == method && 1 == arguments.length) return this.set(path);
|
||||
var args = [method].concat([].slice.call(arguments));
|
||||
if (!this._usedRouter) this.use(this.router);
|
||||
return this._router.route.apply(this._router, args);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Special-cased "all" method, applying the given route `path`,
|
||||
* middleware, and callback to _every_ HTTP method.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} ...
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.all = function(path){
|
||||
var args = arguments;
|
||||
methods.forEach(function(method){
|
||||
if ('all' == method || 'del' == method) return;
|
||||
app[method].apply(this, args);
|
||||
}, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
// del -> delete alias
|
||||
|
||||
app.del = app.delete;
|
||||
|
||||
/**
|
||||
* Render the given view `name` name with `options`
|
||||
* and a callback accepting an error and the
|
||||
* rendered template string.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String|Function} options or fn
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.render = function(name, options, fn){
|
||||
var self = this
|
||||
, opts = {}
|
||||
, cache = this.cache
|
||||
, engines = this.engines
|
||||
, view;
|
||||
|
||||
// support callback function as second arg
|
||||
if ('function' == typeof options) {
|
||||
fn = options, options = {};
|
||||
}
|
||||
|
||||
// merge app.locals
|
||||
utils.merge(opts, this.locals);
|
||||
|
||||
// merge options.locals
|
||||
if (options.locals) utils.merge(opts, options.locals);
|
||||
|
||||
// merge options
|
||||
utils.merge(opts, options);
|
||||
|
||||
// set .cache unless explicitly provided
|
||||
opts.cache = null == opts.cache
|
||||
? this.enabled('view cache')
|
||||
: opts.cache;
|
||||
|
||||
// primed cache
|
||||
if (opts.cache) view = cache[name];
|
||||
|
||||
// view
|
||||
if (!view) {
|
||||
view = new View(name, {
|
||||
defaultEngine: this.get('view engine')
|
||||
, root: this.get('views') || process.cwd() + '/views'
|
||||
, engines: engines
|
||||
});
|
||||
|
||||
if (!view.path) {
|
||||
return fn(new Error('Failed to lookup view "' + name + '"'));
|
||||
}
|
||||
|
||||
// prime the cache
|
||||
if (opts.cache) cache[name] = view;
|
||||
}
|
||||
|
||||
// render
|
||||
try {
|
||||
view.render(opts, fn);
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
};
|
||||
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