Compare commits
2775 Commits
2.0.0-alph
...
2.0.0-beta
Author | SHA1 | Date | |
---|---|---|---|
185c679563 | |||
b3f4e05b57 | |||
abd1e6e680 | |||
f1f5b45361 | |||
50548fb565 | |||
8f47aa3530 | |||
df7885c9f5 | |||
0f10624b08 | |||
6f1ef33e32 | |||
231773ea76 | |||
e725542703 | |||
2337469753 | |||
55122cd57a | |||
7e0f02f96e | |||
e7ad03cba6 | |||
74be3d3fde | |||
a15ca23469 | |||
de77700da0 | |||
e73fee7156 | |||
72ab35bceb | |||
0f22dce036 | |||
c6036435f0 | |||
d86be245b8 | |||
a26053d3ff | |||
24d5b665e1 | |||
aa98fad338 | |||
9cb6dbbbab | |||
e21718faa9 | |||
b0f7d59e64 | |||
b86829f492 | |||
22929a1671 | |||
86c40f8474 | |||
16b521794c | |||
2a70f4e4c7 | |||
2f31c4c1c5 | |||
1435763383 | |||
05238df89b | |||
772d60d9fe | |||
24086bf0bb | |||
9b0e10e9a7 | |||
995a9e0cf8 | |||
b55f1764b5 | |||
5e9daed2e8 | |||
aa8c5aa2e2 | |||
f2c7946cca | |||
da1fcfd820 | |||
dbeff6f548 | |||
26e60d658a | |||
c2ceb7fba4 | |||
4bfe49cd42 | |||
cee2318110 | |||
cfef76f683 | |||
f56df65d48 | |||
3a40cd79f0 | |||
6acc99729c | |||
99e6500a2d | |||
5c782d6ba8 | |||
4e43d6f769 | |||
3529ee9973 | |||
29aa6a6c1c | |||
7918f3c1fc | |||
2f4e176054 | |||
d4565fdaf3 | |||
2a302aa73a | |||
31b819e9c2 | |||
27daeaff5e | |||
3e9b532409 | |||
c5aa6d17ef | |||
e480b0798e | |||
8a645d5e44 | |||
321193889f | |||
566d3ede04 | |||
8c36aa866a | |||
ed2dbf2db7 | |||
36a0e04604 | |||
8867afdaab | |||
a199772508 | |||
b008f542fa | |||
a78dcfa5f3 | |||
e1bf3d33f8 | |||
ae7d2ab515 | |||
c6adbf602c | |||
1f7a41c963 | |||
f4f614f3a9 | |||
94139c351f | |||
fc5b128b43 | |||
68a799af2e | |||
16d9c60a0e | |||
c0b5e7a672 | |||
6932b29acb | |||
c2a38c05aa | |||
8bea667a0b | |||
800c8f196f | |||
42231f5719 | |||
db87baeb98 | |||
c4c43f5a77 | |||
0ae77753f3 | |||
5f0baaac73 | |||
b5b6ece65a | |||
4282297c24 | |||
9c96b8affc | |||
132829e5e2 | |||
4a414420e9 | |||
fb6335ab60 | |||
89bd008445 | |||
caafb41eb5 | |||
31b81a7439 | |||
f7b1973358 | |||
32f01da49a | |||
59684c97b0 | |||
a32a0a3a97 | |||
96f5b0929d | |||
8e6cf7fca8 | |||
fdbe8741c9 | |||
775fb2c340 | |||
b60f594798 | |||
cc49790bdb | |||
a4bc19c530 | |||
f7985dbdb7 | |||
0bdcb5c1e0 | |||
a0d25db4a5 | |||
625474c4e2 | |||
1cd2a6328a | |||
d6bafe4fe3 | |||
6a2ef15355 | |||
a8ca560503 | |||
ad361808ec | |||
c47639f2b1 | |||
ba90a85f7b | |||
d3b569557f | |||
c9090ffa31 | |||
341bf39d23 | |||
3778ac26aa | |||
6cfc6f5bb2 | |||
47a3b4d56b | |||
c72ed991ad | |||
78bfdf78ea | |||
a24ee6add4 | |||
df3074fdfe | |||
f7424d5aeb | |||
a593ffa6f3 | |||
761c6d0df7 | |||
3e65d1458e | |||
a4b5cb8376 | |||
c785a1e474 | |||
3adc472f06 | |||
e7081b8b7c | |||
9b3a548f6f | |||
90b3502bb8 | |||
e19b31db29 | |||
bd015f14e8 | |||
ca7ba12fc6 | |||
ae05ec69c4 | |||
92dc3b91d8 | |||
8bd697b316 | |||
eda4c3eb4c | |||
4d0c2ed1f6 | |||
eda6a5d52a | |||
c1c54ed0f2 | |||
6b73d09ba1 | |||
ac85cbb28a | |||
b0cebdba6b | |||
933a9112da | |||
8c37b7e8f2 | |||
c8e909f8c9 | |||
69ae3634c7 | |||
95248f46a1 | |||
b3c7df1783 | |||
c56679e8e1 | |||
041c599511 | |||
6343f71be5 | |||
89f32f808f | |||
7ae23adaff | |||
a08f50badd | |||
0b6e75a85e | |||
4291758079 | |||
b44d36cf95 | |||
a038bb9ae3 | |||
9d28147acb | |||
d116861c8e | |||
9a70f1a1d9 | |||
8516473340 | |||
cab69f689f | |||
822e83ebb0 | |||
b2bc50dbd1 | |||
e748adda2e | |||
630d93150a | |||
76f1f9f1e3 | |||
c47d85b038 | |||
197cf09689 | |||
e67ebb7f70 | |||
3524946581 | |||
9276dad42c | |||
2a2f9a9a19 | |||
909e70bd61 | |||
8ac9719832 | |||
3eff7c6f59 | |||
17fbbfba91 | |||
b232dded77 | |||
f50affaf9c | |||
463754bf16 | |||
a45b27e7f9 | |||
af3ea16acb | |||
fc75220d63 | |||
00822c3415 | |||
3dca9d522a | |||
de996ec50b | |||
059e09c3be | |||
d5e4686e7e | |||
d55655f5a3 | |||
61b9468596 | |||
c6f52e3282 | |||
42ccff859c | |||
29600c0c87 | |||
5b63b6764f | |||
2835265916 | |||
e950dd6a2a | |||
321ed7d099 | |||
42b74f524a | |||
77b7caeceb | |||
b803ecf7e7 | |||
d3a79db48d | |||
e891baeea4 | |||
2aaef81b1b | |||
3191fd1440 | |||
80a5e47e61 | |||
5a04ffec3e | |||
1c779d8b9e | |||
a79fe057f9 | |||
b88a6d983f | |||
19396d14cc | |||
2983558e5e | |||
0f8e40bb42 | |||
006a96dd20 | |||
4deaf0bdd3 | |||
9917d7f8af | |||
1607ef8782 | |||
539c5633bf | |||
f83f4ace2d | |||
283962f810 | |||
892f9e19bc | |||
cacfb214b6 | |||
4e5cd1e558 | |||
43f42d9c6e | |||
a885f37dfa | |||
ed2c25eb2f | |||
b1b0593ddf | |||
200dc00dbb | |||
20c6eebb29 | |||
8c69497d8e | |||
44c648fc04 | |||
979162d324 | |||
2934b82113 | |||
92ddc62bed | |||
0cb32c2fef | |||
2ca5e38a78 | |||
b8e69a21a9 | |||
3fd898e91f | |||
a66cc50168 | |||
eb296756fb | |||
f1a9a537cb | |||
080469f8e6 | |||
7c13372721 | |||
778677ba75 | |||
f0d876a873 | |||
e9e2a4152e | |||
398f024b24 | |||
4a17e6906c | |||
8d3e5596dc | |||
df6d2d1e23 | |||
d26c338aa0 | |||
edcb34dc9f | |||
693d9dce5d | |||
194dc7da78 | |||
79399e1c51 | |||
fe1dd77d94 | |||
24dcd267b8 | |||
cf3ce171a5 | |||
06d076a6f2 | |||
3190c5941a | |||
30e25acb9f | |||
4975cb92ae | |||
c8d6ad2718 | |||
cde6726e25 | |||
b3d10af89a | |||
4724cc664e | |||
4e16feaf72 | |||
9e44dd85ad | |||
da9b46a071 | |||
b386d1134a | |||
1e740581ee | |||
f1741b10f2 | |||
7bce1477ef | |||
01ba94ba56 | |||
51cb7586e0 | |||
796eee1e6f | |||
c39828f0f2 | |||
28860d35b2 | |||
5f0ce30ee6 | |||
f4d937ad8d | |||
db096a5e22 | |||
bf484b19b3 | |||
56a254e6a5 | |||
793098bcce | |||
d6d759d722 | |||
61e8b60506 | |||
2f0744b089 | |||
ca73852746 | |||
72444c40a7 | |||
214148d58a | |||
cc8f1f9552 | |||
cbf788869d | |||
c1ae49d91e | |||
4432cf5438 | |||
869a392357 | |||
90c67b4b11 | |||
7d15e19f2b | |||
a4ba46cb99 | |||
0df8bc4e52 | |||
0d9a1de4d9 | |||
d58f017226 | |||
1d825eb685 | |||
b3c91b163b | |||
aa85856e1c | |||
fb4f1e8dc9 | |||
8657ca4298 | |||
80b025ae53 | |||
11f98c58b3 | |||
c1e3ea9f7f | |||
21542ed069 | |||
c39f4c3b38 | |||
1f35048d54 | |||
eb0ea931d0 | |||
47f1d12731 | |||
aecf68117a | |||
3a438615c3 | |||
9850e68703 | |||
daaa8ee1cd | |||
50490b55eb | |||
86c74cf3f3 | |||
7f0925eb2b | |||
85d89babce | |||
ad481694e1 | |||
2d313c4d1d | |||
e6170e8ac3 | |||
4b1618cb03 | |||
0a44fc69fe | |||
c6d6b75691 | |||
f664a9c4d5 | |||
a090843b84 | |||
d10224d21a | |||
7e18d4c539 | |||
22e9590981 | |||
d388c0ae62 | |||
56604468e0 | |||
b925ff5b8d | |||
654496b315 | |||
c6a5d9bc84 | |||
19b61b1cf3 | |||
5e50859a03 | |||
4ea5b6e57f | |||
e67e1952d0 | |||
0614797d84 | |||
0a3a17ff10 | |||
680f7e0299 | |||
688469c221 | |||
7a1fbf1c3a | |||
478a25ed27 | |||
1edb17b8d0 | |||
1710272b3c | |||
93a1ec29e1 | |||
d90a2269f9 | |||
69996b1740 | |||
35e32bbea1 | |||
e9f873a365 | |||
25a2d7b5db | |||
c635a73ed9 | |||
f76eea4f9b | |||
5514dc19d9 | |||
a16ac84840 | |||
ad99199d50 | |||
c7242a39d2 | |||
4fa1809f80 | |||
2a4ac63a34 | |||
c5ed2d219a | |||
fb16c39496 | |||
62c2ed7c43 | |||
9c6b929c7b | |||
070d818e68 | |||
7f783289ab | |||
1417e12f28 | |||
9a65ea7ea7 | |||
c58e7e0e91 | |||
bdfed9d850 | |||
b9b14dc731 | |||
cf3ceba2cc | |||
c08d76c7f8 | |||
d1c284a3da | |||
442d6866da | |||
093b7948be | |||
706990c65d | |||
f77ca7b5e2 | |||
922da62720 | |||
87449ab43c | |||
6b2ef25c69 | |||
3e364b0d41 | |||
47d0942f3f | |||
87ac36f65b | |||
015faeeaf2 | |||
909426e37d | |||
c4c4d045fb | |||
2ada3ecad5 | |||
fcc7ce225e | |||
604c8bbad5 | |||
4215afc639 | |||
909031e688 | |||
b7b3c85033 | |||
0c9596ae2b | |||
a8c3b9d67c | |||
65bdf42903 | |||
7f3223bd2c | |||
87ddc8fb6a | |||
6ddfff5cd5 | |||
a3253210b7 | |||
0dbd0b340c | |||
8c670822ce | |||
b90de66535 | |||
1bec4f6c61 | |||
b6ec2387b3 | |||
cf157b99d3 | |||
2cd0f076cc | |||
fa725b4512 | |||
5a27ffb5f5 | |||
d59c20c315 | |||
019cb41dd8 | |||
b4de41b74e | |||
87d56acdaa | |||
8daa9b202d | |||
89eefcd7b5 | |||
9ae171e0c8 | |||
cee67e6fe0 | |||
a3353a5e28 | |||
c5294c77d9 | |||
ba64b5ea5a | |||
230aad4047 | |||
564642d859 | |||
87549c77d4 | |||
fad354904d | |||
e1d7bdcfe7 | |||
46fc153f39 | |||
4332ccf72c | |||
201f189d0e | |||
a35a93d0da | |||
163164cb79 | |||
31f85f0297 | |||
225b9d306b | |||
9ca8a35553 | |||
5806babb0b | |||
30d35b5046 | |||
88afae15a8 | |||
cf7292fcb1 | |||
422a7b18f6 | |||
0b1ff2db9e | |||
a43ed79ee7 | |||
125fa3885e | |||
ae58934d52 | |||
3c8fa8c50d | |||
4d59985b74 | |||
4e12b0831e | |||
5ba9ced1ab | |||
36a423fac8 | |||
adb87562bb | |||
0db02523d3 | |||
3c43a8c549 | |||
3fa287aae2 | |||
929abb9aa3 | |||
837efc2a0f | |||
3eced6e1a9 | |||
c53a63acca | |||
621fa490c7 | |||
9691c045a7 | |||
c855c5ddc2 | |||
2c8fcec432 | |||
60a2bbb226 | |||
d013fc7604 | |||
dd1e212402 | |||
ac38812809 | |||
b571baab68 | |||
a31e2f5f47 | |||
bcd926adc5 | |||
b22eddf1cb | |||
857bef9e4f | |||
4e585bca28 | |||
94cf671c15 | |||
ad6fb067e9 | |||
c03fb36e11 | |||
bccd8a719d | |||
4e1d9c93df | |||
0611239a0e | |||
c5045ac8fe | |||
41dfaf393b | |||
96076862cf | |||
a8edc1eb58 | |||
86aeb8be0a | |||
e274ff8a69 | |||
9985968d89 | |||
bb9cfe6f36 | |||
406ace9b25 | |||
6d70cd78ec | |||
a70a919d14 | |||
b16fa45d83 | |||
1d9c44b34f | |||
2ecbd0eaaf | |||
8ab7781b2d | |||
cf0183ac7f | |||
2ce9e95fc1 | |||
49e261efd8 | |||
9c94ab1e8e | |||
d1d88c32c3 | |||
63639895ad | |||
0eab4fc72c | |||
d9f362a713 | |||
7f6289c1bf | |||
78280a48af | |||
f80321fd26 | |||
8f91ff84c7 | |||
3f4628c0b0 | |||
4e02e00373 | |||
9b3b721f08 | |||
756727b930 | |||
533b722c66 | |||
029c0534f3 | |||
d29563fdd3 | |||
4a43230de4 | |||
01ebff4080 | |||
344776f864 | |||
a3e6406b38 | |||
64bd9639a1 | |||
1ff1792642 | |||
e6bf33efbf | |||
5fecb3b3f2 | |||
ee07646059 | |||
e27665c368 | |||
2618becaa5 | |||
0dcca1a28e | |||
e667ad3e6b | |||
fb8b8157ff | |||
a8d9dbf110 | |||
2645fb0d6c | |||
18b508d14a | |||
b0009f03d5 | |||
79472b77ca | |||
3593d85807 | |||
6133f2c08b | |||
63e853dcd7 | |||
2d0c8f1b0e | |||
c6ad269f43 | |||
a0a627f2f9 | |||
c5693f07dc | |||
253e2b2285 | |||
aa70275b01 | |||
0b11051ac1 | |||
4bb9c46cf1 | |||
7343ef04ae | |||
4439106a1f | |||
2c201d3f34 | |||
fc50829481 | |||
695923dcd6 | |||
6edd964a83 | |||
f39bbff7bc | |||
b354b79b50 | |||
bcfb0732f9 | |||
febcde99fa | |||
0fbbce7a43 | |||
a98c27d974 | |||
ca3391525e | |||
a8f45a6b43 | |||
9d0b61bad5 | |||
f21e78244f | |||
fee5dea826 | |||
b84855f394 | |||
7e92d2e6b7 | |||
b91351469f | |||
c56efc0c5f | |||
5d9b1e90dc | |||
4909feddde | |||
adc0e32cff | |||
c70e07fd1f | |||
f54ba3cc1b | |||
f1989e7e1c | |||
a69e7fe297 | |||
a9b1270a5a | |||
31687efd64 | |||
69e4b62809 | |||
fd92dc0701 | |||
c9a3ba0f48 | |||
d0c65c144a | |||
686457890d | |||
a16214c614 | |||
c262bda1d3 | |||
62402457a2 | |||
5948abab7a | |||
0931195695 | |||
2cc6927d1a | |||
bff9dc26c7 | |||
2f047887d3 | |||
9220b0bbc1 | |||
16bc238f10 | |||
045919b595 | |||
6f1a89e3a9 | |||
134c6f57d5 | |||
bf07f9c3e1 | |||
c814dfbfa5 | |||
8dc079eee5 | |||
c4129071ef | |||
37c65b74e3 | |||
1c322f13e5 | |||
31c12af81f | |||
cf449ddaa9 | |||
53bd6e1642 | |||
d6e7a51d9c | |||
13447e3198 | |||
84fe0c9d3e | |||
1b78342e23 | |||
54f7e62c43 | |||
0ebe283b37 | |||
23784a2eca | |||
d8775e0e1f | |||
53bddec1d2 | |||
cb2b690471 | |||
7d154e38d1 | |||
78875d57c8 | |||
45b33c5a90 | |||
860e88c5be | |||
ebd15a7855 | |||
1dc8a0a95d | |||
fa44da16c8 | |||
56e736439b | |||
9d58f46ea5 | |||
bb2b961f93 | |||
39626a944d | |||
d1b54d6807 | |||
c930a533d1 | |||
389ed2d941 | |||
0378e55fab | |||
ca3986f31d | |||
72e65d6797 | |||
ef23fe66a0 | |||
993b3d62de | |||
5f2eb3e078 | |||
c17c33ca14 | |||
a87c5d989c | |||
7d83959be5 | |||
cc37d0a7fa | |||
6b40293c0a | |||
eba70736f1 | |||
e37799a2a5 | |||
c4964e7c9b | |||
6815acea32 | |||
b329a58416 | |||
df13e0a581 | |||
ae7f76e91f | |||
edd4b93589 | |||
97c60ed3f3 | |||
35328015b8 | |||
28be0a59cf | |||
8485ef9230 | |||
1de2d29f96 | |||
0abd218eed | |||
7f806f7687 | |||
e6a721d179 | |||
e47a9d9644 | |||
7677dc976e | |||
e7f9924b18 | |||
40586152d1 | |||
2f1f83a186 | |||
7ba426c3e6 | |||
fc016b59dc | |||
e1337dc325 | |||
534db7fe2b | |||
547e011abe | |||
9c63a471bb | |||
127d6b6441 | |||
098201d0b8 | |||
44188b9072 | |||
53fe0fa192 | |||
e3c9397717 | |||
bc10dc3ed0 | |||
5c48236f61 | |||
c90e1920f5 | |||
25ddd8718d | |||
3ed9796425 | |||
bdd031aecc | |||
798be2776d | |||
d69bd021ee | |||
26044026c9 | |||
ca5e31bc77 | |||
e9c4c61986 | |||
563a76304a | |||
c91fc49d01 | |||
a18358d484 | |||
d68955ac6d | |||
b318945680 | |||
150d3686c3 | |||
f9963d3d21 | |||
6514b8ced0 | |||
c02f2bdab0 | |||
4a1b873fad | |||
edfa35b11d | |||
a881f09b77 | |||
137549d010 | |||
5fc28e65ef | |||
1316c3e391 | |||
758062807a | |||
f98faf0702 | |||
42ea31b993 | |||
fdbb505a8a | |||
61e514bf77 | |||
7478105178 | |||
540b8c2a1a | |||
dc6a066fed | |||
ac52bfd80f | |||
27dbd2ded4 | |||
ed4826b08c | |||
689ded5c47 | |||
cd219b92a2 | |||
a31b2175dc | |||
b87da8f47c | |||
fbe748f273 | |||
4fe17923cf | |||
f59adf3fd7 | |||
14f8bcc40a | |||
bfe3efab3b | |||
ea6b316932 | |||
ef7050892e | |||
94274049d4 | |||
2a3e11d32d | |||
280cd33f2e | |||
07cdc2ff44 | |||
7af27f9617 | |||
9f8043e51e | |||
391a6fbc2a | |||
3416984cce | |||
abdd524911 | |||
e1e52c098b | |||
dd2598ccd8 | |||
b90d899408 | |||
d8b3601927 | |||
60bedb43de | |||
c5f490ba43 | |||
2e059dc916 | |||
2674eaca51 | |||
8dd3082ea3 | |||
b2dc5c2c7e | |||
2957b0b32e | |||
28db864690 | |||
28d88c5b12 | |||
c9fba3fa1f | |||
04b4035ecd | |||
608cdc4077 | |||
d29a9a99aa | |||
485c85bfe7 | |||
3118d5cebb | |||
56a9b020d4 | |||
de6774cd97 | |||
84d1f93d83 | |||
785abe5a1d | |||
27ead8c883 | |||
1caccc410a | |||
4639f449cf | |||
77604b8b18 | |||
491e1fdd2c | |||
a7c95ade2e | |||
711dbf4975 | |||
91f71d2c3f | |||
0a940211d5 | |||
fd0ba37734 | |||
6be95ae88a | |||
9d0d33f95a | |||
cf9d4662c9 | |||
be3e7db5db | |||
2c98a0f771 | |||
b09788993d | |||
e4e74ae65c | |||
c3ab20cc87 | |||
05d29a936d | |||
fd9b67537d | |||
5256457144 | |||
169cb5f270 | |||
6c7bc09f70 | |||
8efb49dd2d | |||
c066d696e8 | |||
d896e4350a | |||
486c1eda8e | |||
053b7a50e1 | |||
059e8faae2 | |||
d7ab5d44a5 | |||
65c737fc95 | |||
427860a5bd | |||
a941fb08f7 | |||
cec8b58373 | |||
b89c5bc581 | |||
7dde18b181 | |||
2be9fef86d | |||
a91ae291e4 | |||
b716d2335b | |||
6436f96fd1 | |||
efddc9069c | |||
f5159389b3 | |||
5a505975bf | |||
115ad4d062 | |||
bfbf18d983 | |||
9fc24b9c52 | |||
247479d017 | |||
57649d1839 | |||
e82a35d1fd | |||
50e922f37b | |||
3b036601cc | |||
e15e2428c5 | |||
3a801c16fa | |||
717bd23c37 | |||
d02b794af2 | |||
bb9d299b38 | |||
1bc35208df | |||
ea661fa10f | |||
c0b7bae9d3 | |||
8bc40d3f4d | |||
440fd11c72 | |||
f529236bfc | |||
5a504e6b78 | |||
a1fa2e472f | |||
eb2c15786e | |||
947bf11cb6 | |||
1aeafd31bd | |||
f443ecbfa6 | |||
8667b760f4 | |||
6abed8d996 | |||
eacc8e3803 | |||
da1272f368 | |||
0def28e594 | |||
b96784756c | |||
62005dd127 | |||
52ebb8f0dd | |||
35878c559f | |||
0c1f9dab54 | |||
1eb0162cde | |||
7c6130c2c5 | |||
df09389df8 | |||
90191ce261 | |||
19c1bd7375 | |||
84c3124292 | |||
cd90e6ed8f | |||
867c08ac84 | |||
95f984615b | |||
393b0526b4 | |||
6207b1af88 | |||
a8c34ae290 | |||
aab0c57aee | |||
c178ad476e | |||
597f79e0c7 | |||
31f48ae943 | |||
1272affe5c | |||
431ac33c26 | |||
cd2050b6e0 | |||
075011f2fe | |||
35a61b449a | |||
984b6fc487 | |||
1100c9b1e3 | |||
f3ab527688 | |||
bba0248989 | |||
bc8c194665 | |||
14fa00791e | |||
d60c7a9118 | |||
d63f3c123e | |||
8b725c77fd | |||
5458036de7 | |||
6075509f26 | |||
ee32b1bc37 | |||
6d4bd5d901 | |||
ff77230edb | |||
21b53c3143 | |||
04b3dee667 | |||
6b00b60488 | |||
bffab0f2db | |||
811d4c03bd | |||
af1119063c | |||
fcc6f2c561 | |||
c94f239536 | |||
5600a95e97 | |||
07572652ff | |||
aee176115b | |||
4ed642f921 | |||
a7b2ab771e | |||
a0277f1b3a | |||
aaa215514b | |||
b6537ad609 | |||
62e14dc529 | |||
15ab6f6ea8 | |||
dea6a4593b | |||
d38689677c | |||
a2e7ae568e | |||
bd31b01690 | |||
f7b75330e0 | |||
f7aa890ade | |||
4a36fd8203 | |||
ba6e0e11fa | |||
4ac29621f4 | |||
75187d605b | |||
5040a8e0df | |||
a4869c874b | |||
b6210be648 | |||
8e1d2fb325 | |||
bb4fd2de94 | |||
fd5cd84065 | |||
6117a7037b | |||
4d9de666c8 | |||
4ebb1a9096 | |||
9679fc94f6 | |||
076191cf9d | |||
74c0daab27 | |||
6093e28b61 | |||
ae6f549f10 | |||
74c852b160 | |||
349416ea53 | |||
f638834fcf | |||
09371a3f0b | |||
0b3e4fa090 | |||
0299d4af00 | |||
a9aef8e5e6 | |||
6fe8b85295 | |||
649d310c31 | |||
14b194ea21 | |||
758efba34b | |||
e21bf120b9 | |||
9fa57d06da | |||
9fc9704cdd | |||
39e9bb64ef | |||
a649992ccd | |||
2628631aff | |||
4b0013c7e7 | |||
5ff1eb75d0 | |||
1b20873433 | |||
36562ecaae | |||
fc764b42f6 | |||
9f688d314f | |||
150cc22532 | |||
208f3d4c65 | |||
7c4199cd1c | |||
2ebc74ddcc | |||
c7e9f86557 | |||
75cf0aeaeb | |||
decdbea7d7 | |||
01fb06a377 | |||
c9901c5fe0 | |||
5ea6dc844c | |||
b44c13bc46 | |||
6ae9686a0d | |||
4342a1eb7b | |||
13161ae5aa | |||
6b5d345a2b | |||
2450a3c5b0 | |||
34518f0f2d | |||
a251df9df4 | |||
a110ce95dc | |||
e8e57cdd73 | |||
aa3d94149f | |||
6248a5e846 | |||
9f4fa1ab0a | |||
43cca2de76 | |||
d21c7bdf90 | |||
b154f1a44f | |||
76247b7097 | |||
30ca0434a2 | |||
841f8789fd | |||
52236bd765 | |||
a5622304de | |||
074e289e62 | |||
617acf4cd6 | |||
a87ebb28e2 | |||
adbfd29fd7 | |||
33593cf8a2 | |||
00a4b2e28f | |||
7b2d8fce07 | |||
cec4b36d9b | |||
5557a5716d | |||
eafa482052 | |||
3aa204791b | |||
9b7378d132 | |||
fb9796130d | |||
e1853b33d3 | |||
4731714244 | |||
b4fe590b2d | |||
8ff65a30c7 | |||
cd0e9c9cd4 | |||
a7b8624b55 | |||
7ae74cf91d | |||
6a6396963f | |||
4319563bba | |||
e2f5d87ff7 | |||
7714d6a6eb | |||
1f2302e39e | |||
a88e6f3106 | |||
3dd9919bbd | |||
589ce31dfc | |||
e7d65ad96f | |||
af9f916a9c | |||
d348e5051f | |||
7771ef4873 | |||
7ee295ad94 | |||
0319417a1b | |||
5bf6a3af15 | |||
7a53f82516 | |||
2ee32fb02c | |||
1cf45757cd | |||
0ed6fc4f6b | |||
9c9769047d | |||
5f640c79bb | |||
0a88e7b736 | |||
711ab6d573 | |||
4e5c663b02 | |||
4efc4a5520 | |||
ce6b364dc5 | |||
ef61b81b0c | |||
225eab8f25 | |||
7c2c1a8e03 | |||
9d2d674ef8 | |||
7470ad1bd1 | |||
bffa2cb59b | |||
4f56a01b3b | |||
29f75c3c63 | |||
ea15d6646b | |||
44c171e399 | |||
4087e3115b | |||
4d4d20edb9 | |||
3b609fbae9 | |||
8427863bab | |||
db6d289d82 | |||
ec68074e69 | |||
3d6e3c2551 | |||
0366f317af | |||
8a2370750a | |||
c01f327194 | |||
5c0a9eff62 | |||
9c4ab2b2b8 | |||
5ea9c1e7fd | |||
662a585fc2 | |||
ae3713ef95 | |||
707e6f7671 | |||
a554f1c45d | |||
41b019f5f8 | |||
af2cd4d6f3 | |||
577ee3744a | |||
9dd32d658e | |||
fd3eae9623 | |||
238dfc1e17 | |||
29b56ceb40 | |||
820b30c181 | |||
cc0c30484f | |||
eb7839e0ec | |||
f600d88209 | |||
662ff47627 | |||
da6def3772 | |||
c868f40bef | |||
17af481134 | |||
b2695e46e1 | |||
b0effe8e27 | |||
794e3870c5 | |||
95c8eef97a | |||
b8c4d3e7fb | |||
aed34e1f82 | |||
5205a9e65f | |||
6e0ca7f39a | |||
43f97a951c | |||
a443ea64a1 | |||
c2a60f1624 | |||
2e9de0b169 | |||
5dbe292615 | |||
5809a02624 | |||
3525d8a394 | |||
dd9b3b4ed0 | |||
283415beab | |||
390aacd442 | |||
e166f6fe95 | |||
5a3ce87915 | |||
2acc1ad08b | |||
b9ea394c85 | |||
06f8330cfa | |||
f490565b09 | |||
d05df30a94 | |||
e1c0b1abcb | |||
b2e9da4905 | |||
be6d92c29a | |||
9179afb2a1 | |||
adb3813e85 | |||
563fffd9b0 | |||
a588d4894b | |||
dad40751d4 | |||
19274e744d | |||
608f35b4a7 | |||
457b689bf0 | |||
eaa20f661a | |||
626e1cda5f | |||
34aa1425b7 | |||
241632aaa1 | |||
06f0d6c046 | |||
d276370ba1 | |||
d9776b4112 | |||
53412a71e5 | |||
70586b668c | |||
8f985dd558 | |||
64e8f93f32 | |||
cc1d758eba | |||
045cb90a46 | |||
d6cda15879 | |||
73351ac00f | |||
5bab607f44 | |||
16bf335a4a | |||
7b3161a229 | |||
267121ee17 | |||
045cc8269f | |||
9f999dd8e4 | |||
d890c4f827 | |||
c2043ec681 | |||
0808eeaa0c | |||
bced3aaa17 | |||
105db02e07 | |||
61b6a475a6 | |||
6db9f9013d | |||
f7d46e7159 | |||
5b6d576f93 | |||
255ed69392 | |||
851b1cf013 | |||
dcd2df2486 | |||
5f15363dab | |||
a15b679494 | |||
db098650ee | |||
f7b6ff0520 | |||
df7f59b3a8 | |||
abc4ef31e2 | |||
55290b9b21 | |||
d6464633fa | |||
c83207f231 | |||
3a7b50f244 | |||
e889ec8335 | |||
cb4ff7491a | |||
5298eb0709 | |||
cb4a9a3c04 | |||
97d1844bfc | |||
193792c27f | |||
4f57990d45 | |||
9dc1d6ae81 | |||
e4f94f0678 | |||
bfbce542e6 | |||
d2458866c1 | |||
cac25fe003 | |||
309944931f | |||
63e785902f | |||
83715f06d1 | |||
b42b9fc42d | |||
39ce9d3397 | |||
effbb54f3d | |||
d1dbc973c4 | |||
feddefdc84 | |||
787d1f955f | |||
0246b2a2cb | |||
71cbb49672 | |||
67c79ba3f6 | |||
d9036c6cf3 | |||
acc2722cb8 | |||
5e49d7e624 | |||
4c2fb1f6e8 | |||
de9dc55852 | |||
013811c171 | |||
e34a29dafe | |||
9b009b3159 | |||
d4383af022 | |||
b91a966d05 | |||
958863d038 | |||
fd14460148 | |||
4df0604f09 | |||
a826f22698 | |||
7ccef08715 | |||
716ce08a93 | |||
646b9200a2 | |||
6449c3c1c6 | |||
1fba78b12a | |||
80a04b4323 | |||
41c7c57c65 | |||
f7fb5097b9 | |||
20fbbcc72d | |||
f94a2d86fb | |||
55358a39dc | |||
a2bcf71b6b | |||
18de0ceeb1 | |||
fc82700364 | |||
16ecc7e82d | |||
ed586f0b4a | |||
f66c3a21eb | |||
17eb41ff48 | |||
31e385c70d | |||
cc8a6ebf68 | |||
19408968f3 | |||
efaed076ab | |||
47e09a38e6 | |||
ffd4f06ab7 | |||
3c13f5fd4b | |||
f6cc573687 | |||
892d2b9652 | |||
8d538ff42e | |||
63141ab9ab | |||
6a4a8a60ab | |||
7ec4da40ce | |||
4fd9cc26d5 | |||
1926335b85 | |||
12dd44f7f6 | |||
2daf2eedb6 | |||
2ab8c59ad5 | |||
0653b82048 | |||
77e8304fc4 | |||
8aec215ca0 | |||
f91c087c46 | |||
39a6f85e95 | |||
3dfb7d406b | |||
8810f53435 | |||
998c7c2e03 | |||
5e013c4aef | |||
8dd6c4680b | |||
28a29f5557 | |||
f3da37c92f | |||
3b9c08676a | |||
a8bdb693b9 | |||
5a59e8be82 | |||
26a064ce87 | |||
70f6a46f1c | |||
e36966b83c | |||
f14b212dc9 | |||
6d13cf9b8f | |||
841aa1af5b | |||
2d4f331c63 | |||
86bda288bd | |||
3d38ec8aac | |||
ef88e0f804 | |||
8302afffb4 | |||
67b9414268 | |||
d8c5ab232c | |||
c320240086 | |||
15164a8e6c | |||
4ec4dcabe9 | |||
e9ad100b1f | |||
b025f94351 | |||
df8e15cab7 | |||
855cb16cc7 | |||
5ebeaf7c9b | |||
9d42b52d2c | |||
34b91c62c5 | |||
4bffd97edd | |||
be954115f8 | |||
2384082b5c | |||
2a126f72f3 | |||
896add7d77 | |||
337ce21149 | |||
d78261695b | |||
ad3b9cf232 | |||
34deda594f | |||
f6108c54ec | |||
687e7b565f | |||
ddde7117a7 | |||
44c303aad2 | |||
53d0861372 | |||
696edde17c | |||
3ff321475d | |||
d43bd9b4ca | |||
79994b2abf | |||
7736964a37 | |||
2fea0c2602 | |||
5c9613e084 | |||
01cdd31339 | |||
44a991e245 | |||
46f751bd2f | |||
358908e605 | |||
6532171997 | |||
b9cf945b30 | |||
5b8ce1e42a | |||
7c7888de4f | |||
42e1b07705 | |||
60ce884671 | |||
9934b3ec7f | |||
12a8064c27 | |||
ad1bd5fc11 | |||
fc7068550c | |||
a8028b87c4 | |||
78f11f6333 | |||
3791c4a682 | |||
ecf6ba3974 | |||
b29b045d78 | |||
c349bbbc08 | |||
e916836261 | |||
4415855683 | |||
cebd670a8e | |||
b8be4bfaaf | |||
6c3c6060a5 | |||
46dd5fcbb0 | |||
0f54ed0306 | |||
9619636ba7 | |||
fa2c6791b4 | |||
ad16e9d910 | |||
7de447e4b5 | |||
36eb9d392d | |||
de37729823 | |||
e1a7e0329c | |||
76e1f863a2 | |||
d49bc438e8 | |||
f93cd9ced7 | |||
0f4eb1b524 | |||
3468f7cfd5 | |||
be07390859 | |||
551d9a1688 | |||
ac3f5106e4 | |||
37b042b361 | |||
465f7c95b0 | |||
69926dd002 | |||
e41d7451bf | |||
3bb27deecc | |||
a34d4c6a5f | |||
02d9e18279 | |||
8536df16d9 | |||
a94f051d43 | |||
78200868f4 | |||
256b2dc9b7 | |||
51285666d8 | |||
557d309377 | |||
4ba4427510 | |||
9f576b0233 | |||
343dcfa0c0 | |||
457eb5d69c | |||
5863f50316 | |||
8ed22ce6e7 | |||
10437ab85c | |||
38a5a2a955 | |||
56e88058f1 | |||
5f6b7ffadb | |||
6d2345accb | |||
cc2a2e4bbc | |||
e72305e685 | |||
c2279dd651 | |||
9cc1cd29ed | |||
894af28529 | |||
bf4b75ee9c | |||
21f60c5dce | |||
aeef19e2a6 | |||
64ffd9e99c | |||
944ccc9a94 | |||
9262727ae1 | |||
3963e0ab39 | |||
d2a3b76a71 | |||
377e3ac962 | |||
a191c89193 | |||
5725f71777 | |||
88a5b8da0f | |||
92da5430e7 | |||
50eee42668 | |||
d07b9181fe | |||
5f0a0fd8d2 | |||
a205807191 | |||
b039ec3da3 | |||
5ee9630be1 | |||
c4044102d6 | |||
215c4aa8fb | |||
3871f89119 | |||
d853d19dd7 | |||
5d403966d5 | |||
20acb86ca2 | |||
e8e430e630 | |||
85ec34d1d9 | |||
a9ce454b21 | |||
b6146394ae | |||
764726d78e | |||
65344fcac9 | |||
ebb3236ad5 | |||
9d44ae3d32 | |||
d2d0715568 | |||
b986c54079 | |||
8336881a85 | |||
b0d27ee896 | |||
9ba2ab5cea | |||
1c9be9b5aa | |||
49997ca932 | |||
195c5c21d4 | |||
a0b240884b | |||
9afcb00216 | |||
bde6416b40 | |||
06487237e5 | |||
964884e761 | |||
09e0b0ac6f | |||
984e7b8e17 | |||
abb3bd266b | |||
298f1fb6a6 | |||
cef51a7e0d | |||
ddb62feae6 | |||
fde026a9e4 | |||
78a8ba2307 | |||
ffc63fc6d6 | |||
9757c137db | |||
0b59e664ec | |||
104302a958 | |||
ba2c077b01 | |||
94733069a4 | |||
cba388bb65 | |||
efbd8fca4c | |||
6b38d249c5 | |||
abb0e279a5 | |||
d191ec4c33 | |||
873b6da120 | |||
f0e7f13f30 | |||
ccfadb9b47 | |||
8dc509f688 | |||
72e0b8f7dc | |||
b5c4d8ba79 | |||
5c95b376b5 | |||
f2d3bdb801 | |||
3b9411cbeb | |||
16eb8ced58 | |||
63a94ee941 | |||
ddcfd465ad | |||
3b4965279c | |||
914ca88e5d | |||
675cb87c76 | |||
53df0d8b3f | |||
8a7a783ff2 | |||
e68c978202 | |||
272ad61ab1 | |||
5f7d4faa88 | |||
235dec26fc | |||
52da220016 | |||
cbfc9cb344 | |||
ed81cb94b0 | |||
1f54e64fcf | |||
20cf61756a | |||
ea6673947c | |||
5e6317fecc | |||
823fa4689e | |||
6c9e712c34 | |||
4845583dcf | |||
8b655c7be3 | |||
a06f48e357 | |||
841206c678 | |||
296851797b | |||
ee5df00146 | |||
89a0f2457d | |||
26d2ea8afc | |||
2686316c90 | |||
83b69e8edc | |||
35a83b495a | |||
dfe0130753 | |||
2fcb4cb769 | |||
da4bcd5d91 | |||
512340e39b | |||
284dc67076 | |||
38945955ab | |||
b7837389d7 | |||
5c328adb4b | |||
60af19f0e1 | |||
1d65b38b28 | |||
64ebf278c0 | |||
416fd085b1 | |||
839edaa15b | |||
ac311911c0 | |||
aa480fee72 | |||
b6ee20846b | |||
b5fb05b735 | |||
7b3cca20d2 | |||
8f5360c387 | |||
ed25a29cc8 | |||
a7a1851c0f | |||
f2f4b905e5 | |||
08dbe87819 | |||
218b037d98 | |||
2150a8f9d1 | |||
720a3c8edd | |||
585ea5d600 | |||
5b5d31fa9a | |||
02b7e61ef7 | |||
280d8f3148 | |||
5a405011de | |||
2374e16104 | |||
561066f899 | |||
903a0f0513 | |||
f83289b1a0 | |||
77d3668432 | |||
dfa5103b1d | |||
1f692ae263 | |||
1562bc91ba | |||
6bd95c1455 | |||
4f5e405676 | |||
86eb46af09 | |||
6651aab11f | |||
5a8b1bcaec | |||
ac6227e434 | |||
96e34c1d36 | |||
4038150246 | |||
24eabb9bb1 | |||
574bbea747 | |||
a1c53eec6b | |||
84463cf0bd | |||
2dcf714d2b | |||
06da60f4b7 | |||
ff1b110ae1 | |||
748c2d6c97 | |||
339071cb07 | |||
a37de36fa6 | |||
cf6ffd5469 | |||
d40ff0bb89 | |||
c4296285f3 | |||
106a28b8dc | |||
bd498977bd | |||
7c52bc9768 | |||
643c71740e | |||
40a3cd2ab1 | |||
3db0ae1dac | |||
07b9be798c | |||
b4a062983b | |||
f11f4e0b45 | |||
450d3630cc | |||
166688348a | |||
39ad50657e | |||
a62a6ba40a | |||
0bb78b7ef4 | |||
861be30021 | |||
27aa9187f0 | |||
c58b0ff787 | |||
392de4af67 | |||
c20a5d65d8 | |||
4422819754 | |||
6eaa09ac20 | |||
c0adae69ac | |||
cfedc77ce1 | |||
96eefdfebc | |||
7bf7ec6d9c | |||
60f38eab78 | |||
209aefee57 | |||
be79942ebd | |||
1beaf81e98 | |||
12e4c738c9 | |||
8822460858 | |||
53788ef827 | |||
b8e82e4db3 | |||
94690ec5b0 | |||
77875a270d | |||
6d272cc5f9 | |||
6d280ea31f | |||
7354206c74 | |||
39b0286d6b | |||
dad9338c82 | |||
f6da89f74f | |||
3437d56904 | |||
3c58878b19 | |||
c5cb7009ca | |||
adc27398fd | |||
dd06a871b7 | |||
014b6cb397 | |||
d44827a4c5 | |||
3cda7128d0 | |||
70bc485755 | |||
0a40024995 | |||
985627bd65 | |||
a9ec6b9064 | |||
f5864afdbb | |||
21e2f3c1db | |||
7b94bbf3e4 | |||
71ea19902a | |||
9e7363f686 | |||
2768158eaf | |||
f8fa47e939 | |||
d4ded1a60d | |||
4e76cac5b7 | |||
0dbdd5cd3c | |||
c08403935f | |||
4893002408 | |||
29095766e6 | |||
eee2146735 | |||
5c21af95c7 | |||
cb6fc9c7cb | |||
68a581a04c | |||
7b834e02ec | |||
8e960d4052 | |||
34acef58e7 | |||
c1ee943533 | |||
f7d7789915 | |||
9c19eb906b | |||
73b7d99dc4 | |||
192cf9ddf5 | |||
d894aa9101 | |||
aae5a4cece | |||
16e3d7e96e | |||
e40ff36832 | |||
c5f8c9586f | |||
4cfe92c47a | |||
9d2776183a | |||
2faa89852b | |||
d84993faf1 | |||
a9efc48e71 | |||
8543c347a8 | |||
1d4502944c | |||
448ca384cc | |||
d426af741c | |||
6ab2a871ce | |||
2c9951273a | |||
6fac901151 | |||
74b311a472 | |||
81d298dc6b | |||
35597a8349 | |||
45cbc430e8 | |||
03fc7fe8c2 | |||
8a91d71625 | |||
4dc6d748a9 | |||
99587a9907 | |||
eebd736cfe | |||
bb50cda181 | |||
05c4fb2fac | |||
448264be39 | |||
78fdf9a11f | |||
71bb4b3ee5 | |||
a2bb81c406 | |||
30bd2a3fc7 | |||
7cbaf1076f | |||
a8b57256c8 | |||
329a6e00dc | |||
c83a3f3372 | |||
0906ee8a4e | |||
23cd385f20 | |||
45b10a1f0f | |||
469afda53e | |||
c2bbda02a1 | |||
e744409cb9 | |||
0a8b3816f7 | |||
bc21aa0124 | |||
2577f5eebf | |||
f575ba60fb | |||
5b5de6662f | |||
a8b75c3d41 | |||
19d8b221b4 | |||
345fa521dd | |||
16493e9769 | |||
dbbb7385f5 | |||
3a7c9e4c62 | |||
408618b836 | |||
771c0170d9 | |||
21b988f554 | |||
1438922ffb | |||
f1e4292072 | |||
fd46b49ea6 | |||
46502e4d61 | |||
b44b06c2c9 | |||
5ec67ee2a7 | |||
61b7703406 | |||
49dc819d23 | |||
03c8e7428f | |||
70792c744d | |||
fdf226ab69 | |||
bd65b63c65 | |||
09226cdd75 | |||
3c2b165de1 | |||
76f63bc6a5 | |||
3531bb7118 | |||
55e8dca8de | |||
820c4b9b16 | |||
fdffcaba9b | |||
a9e7c90960 | |||
5a86f85936 | |||
8ecb632d70 | |||
8ad4ad57d1 | |||
854b5b7da8 | |||
231962aaf7 | |||
51e6f33d32 | |||
476988876c | |||
c3d61bc63c | |||
6f4a39c337 | |||
a472eacc07 | |||
078475a082 | |||
de18da2a0d | |||
6d760666a9 | |||
b2a0be87e8 | |||
4c8ea12903 | |||
e94270946a | |||
40d21b808d | |||
095def3845 | |||
153660fe7b | |||
3dd05ef7db | |||
cfc18b5a6f | |||
57496926ca | |||
19e4ee81b9 | |||
f74d97e1f1 | |||
011fab37af | |||
8296dcec09 | |||
3df8363a94 | |||
5cc84ed4bb | |||
2f08ed8d3e | |||
1386977a34 | |||
cdb6c9cda2 | |||
13b1d85058 | |||
c6409cb624 | |||
573c047d50 | |||
f42382db3b | |||
762a94f2cd | |||
5b597de18c | |||
4d28167bc0 | |||
61c73576c8 | |||
116b64de25 | |||
b785503543 | |||
fc8f4688c7 | |||
3f6dd6cd42 | |||
2147ce45c2 | |||
c701664e07 | |||
a4915ad634 | |||
fe3a55966d | |||
f1e8176995 | |||
621604dc66 | |||
5654f2f4e2 | |||
b1231593b6 | |||
b1df54501a | |||
d449ea5ca4 | |||
583c5ffcb5 | |||
7879761a41 | |||
f7dfd2325d | |||
b03560b670 | |||
f25e43fab8 | |||
903ff9047f | |||
66ec4d1f5c | |||
93055f78ea | |||
33500e986b | |||
b26f99787e | |||
9d66b5b09e | |||
8bdca5c03e | |||
ccb41632c7 | |||
cd532b00d4 | |||
81abc39929 | |||
b4cde697b5 | |||
7531b48d02 | |||
2bc1217409 | |||
b73ba68215 | |||
e1e7912ab2 | |||
e988f59c08 | |||
3810e4bed3 | |||
27233cff31 | |||
34993f7691 | |||
7dc1dff816 | |||
5677bf73ca | |||
97ef1c27df | |||
04baa46efe | |||
4bdc91892a | |||
b3a763a718 | |||
7ee6963f5d | |||
1eab4f5f07 | |||
cf103de4a7 | |||
a9a552c112 | |||
f5f85bb528 | |||
bdfef4ed16 | |||
4d80ce5b4a | |||
09bb114a4d | |||
3bf8c18c56 | |||
45994a53ce | |||
875db11822 | |||
2e4a2a0e5a | |||
9fa7d38133 | |||
927454c8fa | |||
0e28297e68 | |||
1eebceab27 | |||
9a70f84e60 | |||
8b3efdf229 | |||
1427d73b66 | |||
62589293aa | |||
749d043258 | |||
a6210466c7 | |||
71c65b47f9 | |||
0ed5dd0d7b | |||
b716046b97 | |||
3143d188ae | |||
b54e7214f0 | |||
d6dadc6efc | |||
546a8f9218 | |||
fe49a7fc40 | |||
447926dc08 | |||
258da88765 | |||
e79dd6aa2d | |||
2c37cc5fcb | |||
206c9bdd74 | |||
4264bd3bd2 | |||
ae5cd51f50 | |||
df877a7d5b | |||
4572157c49 | |||
6596c72131 | |||
f1f578436b | |||
f827e1532e | |||
bab271fcb4 | |||
0792f1a7a1 | |||
ac50ffca5e | |||
caa252e57b | |||
d5edc748d2 | |||
718fa35167 | |||
c177d889a2 | |||
3f7ebde037 | |||
4656c6f5cf | |||
e0fb50cc3c | |||
7d9f5d7538 | |||
2ac8ebd3ef | |||
871267d578 | |||
d050ce20a9 | |||
6c933a4485 | |||
c33e3be735 | |||
3ab8a0c438 | |||
12a427e158 | |||
0052c6b120 | |||
65a767d9b0 | |||
0e945e465d | |||
72257ec87d | |||
e5405e4ba2 | |||
b60d714acf | |||
edf5053bf0 | |||
3869818d8f | |||
abc1580fa9 | |||
286a249a9a | |||
d828664d0c | |||
355ced92eb | |||
9e1158de4f | |||
569766fa8b | |||
e987ac4034 | |||
c2efa23e94 | |||
d2774421e8 | |||
8681f79182 | |||
b10d7a2e51 | |||
a56d33d7ca | |||
2b45bd2a63 | |||
7986e7ce7e | |||
311b47720b | |||
582551bea9 | |||
19a0349681 | |||
883b506445 | |||
d381c5fc8a | |||
ad506a7aaa | |||
ef3cc8e6eb | |||
561b78a5b3 | |||
a7ea2e5566 | |||
1c94c32f4d | |||
d5ace7a562 | |||
2ed251a5db | |||
8d0d05c65f | |||
ac24a301bd | |||
ba440a04d1 | |||
cd65fc2a5e | |||
e69af1a3cd | |||
d1393b0581 | |||
46bb4e37ba | |||
3a8e1661fa | |||
0598226e24 | |||
0b50258814 | |||
600d53c68e | |||
f0e962c55e | |||
73a939e76c | |||
dcdd73065a | |||
34eaf65a79 | |||
27e710019c | |||
c2c361efcf | |||
f020a5cdea | |||
530e742628 | |||
a90063a827 | |||
de05d1bf46 | |||
1fb948461e | |||
27c050be86 | |||
f66ce096d8 | |||
2335075506 | |||
b3fc357a15 | |||
b3d98cba77 | |||
146dbf1270 | |||
55bf0e554f | |||
fa7da0ca5d | |||
d49459750a | |||
d6b56c2380 | |||
7fc1ee67d1 | |||
3e6503789f | |||
8bab6dd239 | |||
a9008eecba | |||
73b3ed18c1 | |||
a93ec73e72 | |||
9a290f0c22 | |||
5de916ecd0 | |||
44891996b5 | |||
bc585f2724 | |||
d629ed7d5b | |||
8c66a25270 | |||
82e8e8c638 | |||
27ad984626 | |||
1f04f70eda | |||
eea989bef8 | |||
d6cef88dd8 | |||
da4de21f28 | |||
eb0fd7967c | |||
56245c6aa2 | |||
ab3f2365fd | |||
66d0e4e656 | |||
0f7dd62f16 | |||
c4e10ea9ac | |||
f1cf5298d8 | |||
22d3943831 | |||
b688dee4c8 | |||
71e0f89594 | |||
5a21dc5340 | |||
d037c082fb | |||
9c768501c4 | |||
b50edfd1f3 | |||
dd7910347a | |||
65769699b0 | |||
8b685466f5 | |||
91d9e8d649 | |||
746efe7eba | |||
ecb2bd0cbe | |||
7e8a2b9cec | |||
1f7296c093 | |||
d1f7900eeb | |||
393f703a97 | |||
7a7b3a6cb9 | |||
0949a4b045 | |||
7a4a3c850f | |||
8a5cf8f6bd | |||
aeb17d8d44 | |||
85d6ae38b9 | |||
d3dda614dd | |||
1c8a58963c | |||
19a9dc67bd | |||
a0e0f3123b | |||
b15474c6f2 | |||
356c927d12 | |||
b89c0672e6 | |||
0a2f6ddc64 | |||
3ea655918e | |||
3875f02a52 | |||
06aaa0c50e | |||
8c993dca03 | |||
2c11205b96 | |||
d800d2f5d7 | |||
24646e7eb8 | |||
6149ce28a7 | |||
c8bdacb195 | |||
5c9e53a25e | |||
ba9fecd068 | |||
2c3c235969 | |||
7b2f757b2b | |||
a67f2314f9 | |||
0a51ccbd68 | |||
2932377769 | |||
e5de1f771a | |||
b48f000657 | |||
d8929c1d73 | |||
92ffc465d6 | |||
c1a494bc37 | |||
783654e6a3 | |||
dee0e008f5 | |||
d7b9345b6d | |||
f158fbd131 | |||
1c4d233fe7 | |||
d575915d7a | |||
ed9d9d5096 | |||
2d2ae9b8d8 | |||
fa7a3e3449 | |||
a057789235 | |||
20a8f0dbe5 | |||
ad7aca631d | |||
c899b0a74c | |||
5ba5da5d25 | |||
4d1ed509e3 | |||
85b8a15374 | |||
920982c4e8 | |||
254e58c28f | |||
f9d72bd85b | |||
b8ef20e353 | |||
c8ef5b5811 | |||
22f4cd26ae | |||
aadaa20706 | |||
f2ef90b240 | |||
f80f97253c | |||
ee8da36d08 | |||
9d4111d69d | |||
180e617866 | |||
bc798b182d | |||
941362014b | |||
dfd30910aa | |||
be7ac9fd41 | |||
35e882e74f | |||
58b38c9201 | |||
ed3af5f751 | |||
5beaf6d735 | |||
b0e2ebda70 | |||
cd21df3572 | |||
c7e48350d3 | |||
6af41a4543 | |||
f9eb8a44d1 | |||
d43394f7b7 | |||
dcc4bc2735 | |||
5dee8e26cc | |||
df6acedd25 | |||
ffd1ac425e | |||
edd01615c3 | |||
9700e80698 | |||
cd735c4837 | |||
f93aae4802 | |||
b2c66949b2 | |||
eb3586d777 | |||
5b5ffe75d0 | |||
e68e69e7e5 | |||
70ffd267f8 | |||
b68e561c0f | |||
93596dff3f | |||
ea27704ea9 | |||
35589a6b3c | |||
598a75ec1c | |||
cdfb635737 | |||
37fceda7e8 | |||
2d499de2bd | |||
91c75f99fe | |||
6e38515402 | |||
d599fd3434 | |||
b2e6ad85ea | |||
d8e2795368 | |||
7a41b19e58 | |||
bc9e482b39 | |||
cab1d0ef0f | |||
0c282e826a | |||
8112b0baa7 | |||
c34cb01404 | |||
f1541e65b3 | |||
9bad70be5e | |||
5bfcca2d5b | |||
73d152506b | |||
3154cea0bf | |||
ac3e624d0f | |||
f065a2ecb7 | |||
a46df6f829 | |||
98fcf8c6ef | |||
da60381c89 | |||
7d32879929 | |||
d64cc8d87d | |||
cebf69933c | |||
c3ae34f066 | |||
4f581671dc | |||
5a542d8ba8 | |||
dd23bab3ad | |||
14d28d7473 | |||
992293a196 | |||
9908def857 | |||
552d1ed61b | |||
5782f063f1 | |||
4ae7df27d2 | |||
c3c2ad1454 | |||
c51aef9f7d | |||
bbfb4e1dcc | |||
e0fbd4b624 | |||
8e3bf3907a | |||
21dcfc89e9 | |||
9613772455 | |||
f3d741854a | |||
c4ecbf0a7f | |||
13466604f9 | |||
cdc7b03e67 | |||
e372cc779d | |||
6834c4992d | |||
1cf807c319 | |||
833048f310 | |||
38e5c3f918 | |||
b4e82b8bc7 | |||
db3d5d4941 | |||
a6e7123995 | |||
1c2abbc61d | |||
7648bb8ee3 | |||
35197acc1a | |||
6622826587 | |||
4fe919335c | |||
a858f6ac42 | |||
cee26826d7 | |||
e89fe0a9ff | |||
d10bbf0cbc | |||
05d02fa90b | |||
796fc66771 | |||
6cafaba993 | |||
60b97b27fa | |||
355ab5b3a6 | |||
ca09701343 | |||
4f27611ae6 | |||
24e647e0f7 | |||
9cd510abaa | |||
d07ed581a9 | |||
5ab92ce844 | |||
76797dfbd4 | |||
591f742d42 | |||
20953ed492 | |||
f3b49378e4 | |||
47b6b05017 | |||
f9745327e6 | |||
659adf83dc | |||
a187c782aa | |||
950f2a38cd | |||
f2371487a1 | |||
6ca81fb98c | |||
af35ab56a3 | |||
15dab7c5b2 | |||
37f8fd6551 | |||
f04b606bb0 | |||
2ccc65d7fd | |||
7501ad11ca | |||
331a051e75 | |||
92f1af86d8 | |||
a6cb86bab3 | |||
76beaa2097 | |||
94272af45b | |||
ad95601e3c | |||
17c6d6a92d | |||
633cf63682 | |||
92d565848b | |||
617d693102 | |||
4530b93a6e | |||
dc45559c17 | |||
efab03274f | |||
f2e2ce15cd | |||
ddd5a235c3 | |||
2cc2196140 | |||
65cbcb2f73 | |||
002101521c | |||
902759e1c7 | |||
c564475251 | |||
4cd29f791f | |||
3eff7be9a6 | |||
e7e82cbee6 | |||
73bce40287 | |||
5fc23caef7 | |||
1a4d23742b | |||
8923103c3b | |||
f34f8df319 | |||
21568106b1 | |||
363b9ba415 | |||
0409b4ca49 | |||
7611f92f5b | |||
7aa9751054 | |||
77b52d65c7 | |||
5df56b47d6 | |||
1eefde7f0d | |||
44b31f326b | |||
b5431e4cc0 | |||
83e99fc72d | |||
cd6175827f | |||
e77710a372 | |||
b6e95bb96e | |||
cd95e078fe | |||
548f3dd5cc | |||
d5195d4097 | |||
fda8b1d87c | |||
7140c9cc34 | |||
4d338a4f5c | |||
6a6b43de07 | |||
309ef0f354 | |||
81fc657356 | |||
29c72abcc4 | |||
79f3f3b456 | |||
d1b35f9174 | |||
f3dd9b5b31 | |||
72736a1b09 | |||
a418397174 | |||
ab8eb4f652 | |||
8d081ea7af | |||
d5c528ac2b | |||
7141c15e65 | |||
5357b1548a | |||
928ec1c5f8 | |||
dc8dac7c35 | |||
c593dfc26c | |||
6b31d82263 | |||
4ee3fdaf7f | |||
41ae8e76f0 | |||
8a52375fb8 | |||
87b3b718e3 | |||
46eeee6b5e | |||
529805508a | |||
851797aecb | |||
13d0815839 | |||
dc6e7eb19b | |||
e5419febe4 | |||
69b75b7fd8 | |||
4eb8c9b2dd | |||
827841ec5b | |||
0a50a3f564 | |||
ce9271739f | |||
2621d6be8b | |||
d76a2ee9c9 | |||
b2596dd302 | |||
4d0973d7ba | |||
1afdb3cbb1 | |||
53694eb64a | |||
31a3a19dac | |||
a50b8a2694 | |||
9e8108ee14 | |||
d53c898499 | |||
552985e305 | |||
20e874d3c6 | |||
471a1b6d12 | |||
f999d5a156 | |||
f74d7727ca | |||
3baf815d76 | |||
96cadcc29e | |||
31b6687894 | |||
381d4cb30a | |||
5030ffb01c | |||
9ce0870f6c | |||
246151b2f9 | |||
83f1856d6a | |||
c280fe816c | |||
b071b66b45 | |||
fde65c7e88 | |||
bae6b91e7d | |||
2b714df64e | |||
c7572ac1f9 | |||
ec3a78289f | |||
f303f0c17a | |||
f543834be9 | |||
6bef1c4169 | |||
652ed0cf6d | |||
559f54e92b | |||
17e1d7f117 | |||
5fa54a92bc | |||
ba7956f521 | |||
c2fa4b7191 | |||
d32f58926d | |||
6a0fe93ba9 | |||
1fae8d6377 | |||
dc060e8b64 | |||
b746e0c9f0 | |||
e67b7e87b2 | |||
0a0b84a07d | |||
927b4d01a9 | |||
5035a42287 | |||
40150379ae | |||
1d24e2cf23 | |||
9e36539052 | |||
0602f68ae3 | |||
2b60d1bae1 | |||
0b43e3cf32 | |||
c9d636aa11 | |||
be88cc7697 | |||
ba07f39347 | |||
4c8e11a577 | |||
3d6c44e2a7 | |||
c60091b949 | |||
a504fa835e | |||
8811337622 | |||
921fb9f2ce | |||
e93b5a1d5b | |||
db7a1f19ba | |||
ef27919f7f | |||
c571b2693e | |||
8bcfb2d465 | |||
93f464a145 | |||
95b7896d9b | |||
ad26bed0ed | |||
62a95823e0 | |||
c8d83dba7d | |||
22f5925202 | |||
cd52d8a3be | |||
a9d6fd9afa | |||
5c53cf6486 | |||
74882c6c38 | |||
c8947d77bf | |||
4f3acdb004 | |||
6404dd8293 | |||
f19970a481 | |||
6f0631c978 | |||
e5d06e479a | |||
d523613329 | |||
cfcae6b293 | |||
000a8e25a2 | |||
8a3b0b366f | |||
383f0a1f30 | |||
e323c07ab9 | |||
f9908cd436 | |||
24bc4b66d0 | |||
2351896cc0 | |||
307011a96c | |||
6f3368ef16 | |||
cdf791f0c5 | |||
75578f41e7 | |||
ffb219fb91 | |||
eb2784eb81 | |||
28ee0612cb | |||
a80921b45d | |||
0db88f34b8 | |||
35f0ee510a | |||
d7df853bde | |||
0387221da8 | |||
c39c8ebcd0 | |||
5d2af54730 | |||
a9be2ebf1b | |||
ec2d8cc2c8 | |||
05d66bba3f | |||
b14417498a | |||
05becf8431 | |||
160c38b5ca | |||
9b0fa0dedc | |||
533c64d4ea | |||
c1157d62a8 | |||
7b1e9286d8 | |||
01fb8e6635 | |||
9d90128463 | |||
34cfc9f474 | |||
ebe1e73b1a | |||
8ce0a67c81 | |||
c065fb1422 | |||
cda35101df | |||
c32dbad747 | |||
30b6542fc8 | |||
2b6a653050 | |||
34d75e8918 | |||
2c25055828 | |||
96f629d441 | |||
a2770c8a52 | |||
4a3fd5e855 | |||
608017776e | |||
0c7f05f56a | |||
c6335c128e | |||
fb42d5908e | |||
8609543ad0 | |||
f83f1ee0ce | |||
1db6870a81 | |||
c19c69f336 | |||
b390f441a1 | |||
79f564be46 | |||
23d59df81a | |||
ef3e12e803 | |||
5fe88d63ef | |||
0f3a8f369a | |||
26d5d17ebe | |||
bb7ffce7eb | |||
551586ced0 | |||
1dc8ba6920 | |||
d773b6a00a | |||
f6cd26b0a6 | |||
5a52c0b71d | |||
662da0d728 | |||
df59e969cf | |||
d27e5512c0 | |||
d48fae3566 | |||
3525c9c074 | |||
05774f6c8a | |||
16447ce75c | |||
15f1eb28a2 | |||
e50f537667 | |||
ed8364741b | |||
6c1cb089b5 | |||
4b98ed114e | |||
d308e55e12 | |||
10bc7e948c | |||
9988471fb8 | |||
05fa9bc9fb | |||
57b88ec2d6 | |||
b1c9bf14b2 | |||
588fbfd848 | |||
b2a24e021f | |||
661a04798e | |||
665ccafd73 | |||
f35dbb99b5 | |||
a393f84fa4 | |||
92c2c33a84 | |||
9802debf71 | |||
2287938f5a | |||
5103f080e9 | |||
1f20ef9787 | |||
1ad6558229 | |||
d61a0dfa22 | |||
ac510b67cc | |||
5ed091e260 | |||
cc2c8f6b00 | |||
c28952c707 | |||
30c3e5a84e | |||
2ff3873881 | |||
aec51d616b | |||
c5996529c3 | |||
00c3693daa | |||
fed86fc8ac | |||
705ee46f31 | |||
f210c41c1f | |||
863eb3c559 | |||
b6b52e62b2 | |||
dd9b08cce8 | |||
e61d82b9be | |||
aabc898f3b | |||
bdeac30a96 | |||
4afd2b4138 | |||
dee4ecbb3f | |||
4210b0e66a | |||
2d6c44b54a | |||
c45283216f | |||
826af401a9 | |||
28c2b8f432 | |||
c9ab8e4be8 | |||
1054f6a9ab | |||
f6eeb9aa66 | |||
91ccc9af98 | |||
ec90fcd290 | |||
a664f5a6de | |||
7643d979c7 | |||
d18463dcdc | |||
f9f917bfa4 | |||
e89bf01c2b | |||
d04a515eb0 | |||
0ae89ac096 | |||
6ec5d5daaf | |||
62b1a08f06 | |||
c54f5e0ba2 | |||
37a8f1037e | |||
4ba81bf3eb | |||
c204835969 | |||
ac28ac324d | |||
8aa3fcfb63 | |||
1beadb8607 | |||
bd8724e652 | |||
73d15edef5 | |||
adaa157317 | |||
791caf0037 | |||
8ab773538b | |||
5c88f662cd | |||
cd7aef2139 | |||
50c6efa187 | |||
302c5d5005 | |||
b6b9ede425 | |||
118f0520a2 | |||
ba80bd43ad | |||
ed6298c33f | |||
db5486a347 | |||
b9b58f7ed9 | |||
33f5aafd6c | |||
4b34ef9036 | |||
8c409e9251 | |||
398e70ad39 | |||
9407c12923 | |||
a4693ef679 | |||
9d5f760597 | |||
8bebcfb844 | |||
8a0eb08745 | |||
1dce4699de | |||
7bff919782 | |||
c6dc78183d | |||
9a72f19b97 | |||
25a952755e | |||
b2da2978ee | |||
8b9400ad92 | |||
3571450b42 | |||
72bb5bdd5a | |||
04a9eb8820 | |||
0f002a5b18 | |||
b066b8d15a | |||
7b511462af | |||
3a53f67911 | |||
155b1e2b35 | |||
aad5795408 | |||
83b97c485b | |||
5db89071d4 | |||
c29ab86d85 | |||
6b02cb9b44 | |||
88c607da03 | |||
f9fd4926ef | |||
986038242a | |||
8e84f8a1c4 | |||
edfbc25768 | |||
05a1c6c183 | |||
534cbb4bf5 | |||
d9ceb42bfe | |||
8d6943227d | |||
3011cd86bd | |||
cfba38b462 | |||
11e4385173 | |||
ad29b12cde | |||
842459aa46 | |||
b033416a45 | |||
7310b09a1a | |||
bb2eda2d15 | |||
0114cd97b6 | |||
fc13cdab3a | |||
3644036693 | |||
c397297eef | |||
1eea2b254e | |||
0e04467b8a | |||
9fbb3adbe2 | |||
b6f29b4448 | |||
421d8916a6 | |||
a38a0d6f87 | |||
7a4a635399 | |||
557d54b3de | |||
c47902a471 | |||
25cd6e4321 | |||
6ad5fa0d9d | |||
666336be1a | |||
77bf90dff1 | |||
8ad0205948 | |||
7ff17db113 | |||
1d11fdecdc | |||
b1ef30aa20 | |||
28659efa69 | |||
6c59894a29 | |||
47b8b48ee7 | |||
3969009fe7 | |||
ecb068019b | |||
5114411749 | |||
08f21dbf51 | |||
d8c7c274e4 | |||
fadabf79e3 | |||
23cec1e8e2 | |||
c36ea0221e | |||
685a6507b6 | |||
846354473d | |||
390cfb793b | |||
17392f663f | |||
8b6fa1cf19 | |||
909233f724 | |||
0e82970a29 | |||
cdbb2473bb | |||
c20060d259 | |||
38926f7123 | |||
0efd89ae5d | |||
718d2ae2ee | |||
af9dcad8e3 | |||
772b529a8e | |||
111fa60a93 | |||
e9f236b70f | |||
78d3f62b6a | |||
d310a9c0b4 | |||
7dc524ed58 | |||
032f8b7840 | |||
4f2b9a4c28 | |||
1ac7bb3bb8 | |||
f302f70330 | |||
555dd93ed9 | |||
96b0a1c75e | |||
c8a0ed40bd | |||
e11c20541a | |||
c75e216871 | |||
fd1d60f03b | |||
e8a6c95e2a | |||
358a6750ed | |||
4320859e1b | |||
98e7a38e50 | |||
229e770a1d | |||
5036086fb3 | |||
97d24563f4 | |||
655ed851f0 | |||
f8f79dc76c | |||
a574154108 | |||
7f976381d5 | |||
ac80df0959 | |||
aff85b5037 | |||
5691063ba0 | |||
7498758584 | |||
92d6aa1f32 | |||
3256ff1c73 | |||
f9c1de46b3 | |||
a9ce0f7afb | |||
1a4ab2c57a | |||
77d1fc149a | |||
c2a42d5d2b | |||
01d5c29513 | |||
7844e3a275 | |||
a5638a940c | |||
4665726f48 | |||
e8ad0d1776 | |||
28022f472d | |||
4f3433b5bd | |||
2185e7cee9 | |||
c82cc47767 | |||
66f5e30d7c | |||
1a0da11e55 | |||
abc8878547 | |||
75e9d3f634 | |||
248caefb7e | |||
853d1de6ec | |||
84dc6ae76b | |||
05219a54cd | |||
4b62a722f0 | |||
61b69c63ed | |||
09b39bf77a | |||
42f6baeaec | |||
8ef183b593 | |||
2cb066215a | |||
200e190f70 | |||
44f829dbc6 | |||
401c9efad7 | |||
900bf8e483 | |||
271ced8ac4 | |||
c5bd3f0773 | |||
ad23921814 | |||
31cbec0857 | |||
d717529e9a | |||
c68fa27444 | |||
d2507ac760 | |||
4ce0d5e024 | |||
5d9e573b3e | |||
51839ca677 | |||
7225416661 | |||
5e4fa5cf07 | |||
fa28b28d0a | |||
f0ef72d6cc | |||
a58c9f83bd | |||
624a33f7f8 | |||
20a033e4c9 | |||
93c331d103 | |||
51c477925a | |||
1daa8aa3a1 | |||
62bf777ef1 | |||
aaf3edd131 | |||
6bba289a3c | |||
b0c735f72c | |||
0e2047f9ca | |||
e30ad2ec2c | |||
c509057f65 | |||
e138add584 | |||
49777648b3 | |||
cb87fa0970 | |||
649e276610 | |||
5ef11774c2 | |||
75db2c5241 | |||
c8ebd11d63 | |||
6651aa1e1d | |||
3f28d08778 | |||
ab28676d02 | |||
577a80371f | |||
01fdb4afc6 | |||
be7504d451 | |||
169e4e862d | |||
abc3de7efe | |||
0b1bb172c9 | |||
0856516ae9 | |||
705d3aacff | |||
1d0078415f | |||
9d1df21d91 | |||
3f36a3c119 | |||
8c15ccecd1 | |||
e966869744 | |||
6b017fb388 | |||
bb6f59e423 | |||
c9cec60007 | |||
f356d03362 | |||
0520ca68b4 | |||
8e1d53b5e9 | |||
f5b56c627b | |||
740d85cad8 | |||
33bba094d2 | |||
f88c4b77ca | |||
75da6e4c4a | |||
1864f60afb | |||
457c15cd6c | |||
28feac9411 | |||
9153331303 | |||
9d5c33f9dd | |||
2713b7877b | |||
2f0fef8ee1 | |||
259f872cea | |||
68ed8f1b6b | |||
ef7014fe19 | |||
46ad3552c7 | |||
4965226f3f | |||
ea546f5069 | |||
cf32213079 | |||
ce6a2ba836 | |||
0f4a089c32 | |||
3c77855b39 | |||
c1579222bd | |||
f863ea0db5 | |||
e4342743c0 | |||
9e8d31d532 | |||
f75a50c1dd | |||
c671706518 | |||
ead21c91a4 | |||
87dcd5eb6f | |||
8faf6364dc | |||
b71fe311fc | |||
bb50fc131b | |||
3aac2fefd7 | |||
fb67e37339 | |||
648c514c28 | |||
511e832ee2 | |||
09f8d8f7ba | |||
1205f54d01 | |||
b5032fd374 | |||
a7a9463624 | |||
59824e40e8 | |||
a51a5c2968 | |||
e3c11045bf | |||
414e58edb5 | |||
3bb3bff1f2 | |||
d2d4e7d783 | |||
ee1b574baf | |||
c0f3778dda | |||
d4925b61ff | |||
5b104936ae | |||
14988d4415 | |||
cd953ceb48 | |||
726fecbfb6 | |||
818bb9b697 | |||
e4586249fa | |||
4c1e978536 | |||
3d62546314 | |||
b9eab463f7 | |||
dff4795e49 | |||
ab74e1ed4e | |||
902984cc10 | |||
ce431f279e | |||
7fb2f2069c | |||
c269bd5d3c | |||
b72eb0783b | |||
a801da6f7c | |||
6fcd3709cf | |||
1b2754dacd | |||
e617ca6323 | |||
15376a6d24 | |||
867705bd2c | |||
6ab19dd095 | |||
99fdb9ac41 | |||
2827ca1559 | |||
8ea03d0380 | |||
d1ec2e18cd | |||
aa58e4bba5 | |||
0a97f0b645 | |||
8a5cf896d0 | |||
22c79df98d | |||
a52798543a | |||
1cbdb9cd17 | |||
4c9b8ebb0c | |||
6aea629cd3 | |||
649fd5a7a9 | |||
40c4eb7240 | |||
cd05ed8de9 | |||
42e7fc5252 | |||
7740fc071c | |||
bdf6af9bd6 | |||
2f83efaac8 | |||
32c5ab956c | |||
b111ca9471 | |||
725f909ff8 | |||
427f0d021c | |||
9fc9d53566 | |||
6dece68bb8 | |||
0676fef61f | |||
1d52cfba13 | |||
bfa381b35a | |||
f78406392b | |||
623edcd2d8 | |||
b5e350b18c | |||
87cf434929 | |||
4bab25b366 | |||
6896305e34 | |||
8ccafb0524 | |||
8a92a1f13e | |||
d0059b5d75 | |||
fa8e059f28 | |||
8e18d6c6cf | |||
afe0e45453 | |||
2e3e41ba64 | |||
d74dd1126b | |||
0ff99081bd | |||
6f4b6783c0 | |||
b1bc792b56 | |||
d4b8a86509 | |||
642e7e5c46 | |||
4650d25a53 | |||
7551a28f1a | |||
e51a48fe4c | |||
22c6c09daf | |||
e70a2f21dd | |||
97e6fb6835 | |||
14a7b9f794 | |||
fa1ec48549 | |||
f7f06c5ad4 | |||
e23004df52 |
12
.gitignore
vendored
12
.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
packages
|
||||
pubspec.lock
|
||||
.pub
|
||||
.packages
|
||||
|
||||
/dist/
|
||||
.buildlog
|
||||
@ -22,12 +23,17 @@ tmp
|
||||
|
||||
# Or type definitions we mirror from github
|
||||
**/typings/**/*.d.ts
|
||||
**/typings/tsd.cached.json
|
||||
|
||||
# Include when developing application packages.
|
||||
pubspec.lock
|
||||
.c9
|
||||
.idea/
|
||||
.settings/
|
||||
*.swo
|
||||
modules/.settings
|
||||
.vscode
|
||||
modules/.vscode
|
||||
|
||||
# Don't check in secret files
|
||||
*secret.js
|
||||
@ -36,3 +42,9 @@ pubspec.lock
|
||||
npm-debug.log
|
||||
|
||||
/docs/bower_components/
|
||||
|
||||
# build-analytics
|
||||
.build-analytics
|
||||
|
||||
# built dart payload tests
|
||||
/modules_dart/payload/**/build
|
||||
|
75
.travis.yml
75
.travis.yml
@ -1,18 +1,29 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '0.10'
|
||||
- '5.4.1'
|
||||
|
||||
branches:
|
||||
except:
|
||||
- g3_v2_0
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- $HOME/.pub-cache
|
||||
|
||||
env:
|
||||
global:
|
||||
- KARMA_BROWSERS=DartiumWithWebPlatform
|
||||
- E2E_BROWSERS=Dartium
|
||||
- LOGS_DIR=/tmp/angular-build/logs
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
- BROWSER_STACK_USERNAME=angularteam1
|
||||
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
|
||||
- ARCH=linux-x64
|
||||
- DART_DEV_VERSION=latest
|
||||
- DART_STABLE_VERSION=latest
|
||||
# Token for tsd to increase github rate limit
|
||||
# See https://github.com/DefinitelyTyped/tsd#tsdrc
|
||||
# This does not use http://docs.travis-ci.com/user/environment-variables/#Secure-Variables
|
||||
@ -20,44 +31,86 @@ env:
|
||||
# This SSO token belongs to github account angular-github-ratelimit-token which has no access
|
||||
# (password is in Valentine)
|
||||
- TSDRC='{"token":"ef474500309daea53d5991b3079159a29520a40b"}'
|
||||
# GITHUB_TOKEN_ANGULAR
|
||||
- secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
|
||||
matrix:
|
||||
- MODE=js DART_CHANNEL=dev
|
||||
- MODE=dart DART_CHANNEL=stable
|
||||
- MODE=dart DART_CHANNEL=dev
|
||||
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
|
||||
- MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
# Disable dart dev build, which is timing out after 2h. #6823
|
||||
# - MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=saucelabs_required DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=browserstack_required DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=saucelabs_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=browserstack_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=dart_ddc DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=js DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=router DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=build_only DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
- MODE=lint DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=payload DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: "MODE=saucelabs_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=browserstack_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
# TODO(alxhub): remove when dartdoc #1039 is in dev channel
|
||||
- env: "MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
|
||||
addons:
|
||||
firefox: "38.0"
|
||||
|
||||
before_install:
|
||||
- npm install -g npm@3.5.3
|
||||
- node tools/analytics/build-analytics start ci job
|
||||
- node tools/analytics/build-analytics start ci before_install
|
||||
- echo ${TSDRC} > .tsdrc
|
||||
- export DISPLAY=:99.0
|
||||
- export GIT_SHA=$(git rev-parse HEAD)
|
||||
- ./scripts/ci/init_android.sh
|
||||
- ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${ARCH}
|
||||
- ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${DART_VERSION} ${ARCH}
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- if [[ -e SKIP_TRAVIS_TESTS ]]; then { cat SKIP_TRAVIS_TESTS ; exit 0; } fi
|
||||
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ] && SAUCE_USERNAME="angular2-ci" && SAUCE_ACCESS_KEY="693ebc16208a-0b5b-1614-8d66-a2662f4e" || true'
|
||||
- node tools/analytics/build-analytics success ci before_install
|
||||
|
||||
install:
|
||||
# Update npm
|
||||
- npm install -g npm@2.7.4
|
||||
- npm --version
|
||||
- node tools/analytics/build-analytics start ci install
|
||||
# Check the size of caches
|
||||
- du -sh ./node_modules || true
|
||||
# Install npm dependecies and ensure that npm cache is not stale
|
||||
- tools/npm/install-dependencies.sh
|
||||
# Install npm dependecies
|
||||
# check-node-modules will exit(1) if we don't need to install
|
||||
# we need to manually kick off the postinstall script if check-node-modules exit(0)s
|
||||
- node tools/npm/check-node-modules --purge && npm install || npm run postinstall
|
||||
- node tools/analytics/build-analytics success ci install
|
||||
|
||||
before_script:
|
||||
- node tools/analytics/build-analytics start ci before_script
|
||||
- mkdir -p $LOGS_DIR
|
||||
- ./scripts/ci/presubmit-queue-setup.sh
|
||||
- node tools/analytics/build-analytics success ci before_script
|
||||
|
||||
script:
|
||||
- node tools/analytics/build-analytics start ci script
|
||||
- ./scripts/ci/build_and_test.sh ${MODE}
|
||||
- node tools/analytics/build-analytics success ci script
|
||||
|
||||
after_script:
|
||||
- node tools/analytics/build-analytics start ci after_script
|
||||
- ./scripts/ci/print-logs.sh
|
||||
- ./scripts/ci/after-script.sh
|
||||
- ./scripts/publish/publish-build-artifacts.sh
|
||||
- node tools/analytics/build-analytics success ci after_script
|
||||
- if [[ $TRAVIS_TEST_RESULT -eq 0 ]]; then node tools/analytics/build-analytics success ci job; else node tools/analytics/build-analytics error ci job; fi
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/1ef62e23078036f9cee4
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
# trigger Buildtime Trend Service to parse Travis CI log
|
||||
- https://buildtimetrend.herokuapp.com/travis
|
||||
on_success: always # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
slack:
|
||||
secure: EP4MzZ8JMyNQJ4S3cd5LEPWSMjC7ZRdzt3veelDiOeorJ6GwZfCDHncR+4BahDzQAuqyE/yNpZqaLbwRWloDi15qIUsm09vgl/1IyNky1Sqc6lEknhzIXpWSalo4/T9ZP8w870EoDvM/UO+LCV99R3wS8Nm9o99eLoWVb2HIUu0=
|
||||
|
||||
|
2225
CHANGELOG.md
Normal file
2225
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
34
COMMITTER.md
Normal file
34
COMMITTER.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Pushing changes into the Angular 2 tree
|
||||
|
||||
Please see [Using git with Angular repositories](https://docs.google.com/document/d/1h8nijFSaa1jG_UE8v4WP7glh5qOUXnYtAtJh_gwOQHI/edit)
|
||||
for details about how we maintain a linear commit history, and the rules for committing.
|
||||
|
||||
As a contributor, just read the instructions in [CONTRIBUTING.md](CONTRIBUTING.md) and send a pull request.
|
||||
Someone with committer access will do the rest.
|
||||
|
||||
## The `PR: merge` label and `presubmit-*` branches
|
||||
|
||||
We have automated the process for merging pull requests into master. Our goal is to minimize the disruption for
|
||||
Angular committers and also prevent breakages on master.
|
||||
|
||||
When a PR has `pr_state: LGTM` and is ready to merge, you should add the `pr_action: merge` label.
|
||||
Currently (late 2015), we need to ensure that each PR will cleanly merge into the Google-internal version control,
|
||||
so the caretaker reviews the changes manually.
|
||||
|
||||
After this review, the caretaker adds `zomg_admin: do_merge` which is restricted to admins only.
|
||||
A robot running as [mary-poppins](https://github.com/mary-poppins)
|
||||
is notified that the label was added by an authorized person,
|
||||
and will create a new branch in the angular project, using the convention `presubmit-{username}-pr-{number}`.
|
||||
|
||||
(Note: if the automation fails, committers can instead push the commits to a branch following this naming scheme.)
|
||||
|
||||
When a Travis build succeeds for a presubmit branch named following the convention,
|
||||
Travis will re-base the commits, merge to master, and close the PR automatically.
|
||||
|
||||
Finally, after merge `mary-poppins` removes the presubmit branch.
|
||||
|
||||
## Administration
|
||||
|
||||
The list of users who can trigger a merge by adding the `zomg_admin: do_merge` label is stored in our appengine app datastore.
|
||||
Edit the contents of the [CoreTeamMember Table](
|
||||
https://console.developers.google.com/project/angular2-automation/datastore/query?queryType=KindQuery&namespace=&kind=CoreTeamMember)
|
@ -18,7 +18,7 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
|
||||
## <a name="question"></a> Got a Question or Problem?
|
||||
|
||||
If you have questions about how to *use* Angular, please direct them to the [Google Group][angular-group]
|
||||
discussion list or [StackOverflow][stackoverflow]. We are also available on [Gitter][gitter].
|
||||
discussion list or [StackOverflow][stackoverflow]. Please note that Angular 2 is still in early developer preview, and the core team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
|
||||
|
||||
## <a name="issue"></a> Found an Issue?
|
||||
If you find a bug in the source code or a mistake in the documentation, you can help us by
|
||||
@ -27,27 +27,16 @@ If you find a bug in the source code or a mistake in the documentation, you can
|
||||
|
||||
## <a name="feature"></a> Want a Feature?
|
||||
You can *request* a new feature by [submitting an issue](#submit-issue) to our [GitHub
|
||||
Repository][github]. If you would like to *implement* a new feature then consider what kind of
|
||||
change it is:
|
||||
Repository][github]. If you would like to *implement* a new feature, please submit an issue with
|
||||
a proposal for your work first, to be sure that we can use it. Angular 2 is in developer preview
|
||||
and we are not ready to accept major contributions ahead of the full release.
|
||||
Please consider what kind of change it is:
|
||||
|
||||
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
|
||||
discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,
|
||||
and help you to craft the change so that it is successfully accepted into the project.
|
||||
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
|
||||
|
||||
## <a name="docs"></a> Want a Doc Fix?
|
||||
If you want to help improve the docs, then consider what kind of improvement it is:
|
||||
|
||||
* For **Major Changes**, it's a good idea to let others know what you're working on to
|
||||
minimize duplication of effort. Before starting, check out the issue queue for
|
||||
issues labeled [#docs](https://github.com/angular/angular/labels/%23docs).
|
||||
Comment on an issue to let others know what you're working on, or [create a new issue](#submit-issue)
|
||||
if your work doesn't fit within the scope of any of the existing doc issues.
|
||||
Please build and test the documentation before [submitting the Pull Request](#submit-pr), to be sure
|
||||
you haven't accidentally introduced any layout or formatting issues. Also ensure that your commit
|
||||
message is labeled "docs" and follows the [Commit Message Guidelines](#commit) given below.
|
||||
* For **Small Changes**, there is no need to file an issue first. Simply [submit a Pull Request](#submit-pr).
|
||||
|
||||
## <a name="submit"></a> Submission Guidelines
|
||||
|
||||
### <a name="submit-issue"></a> Submitting an Issue
|
||||
@ -59,19 +48,22 @@ features, by not reporting duplicate issues. Providing the following informatio
|
||||
chances of your issue being dealt with quickly:
|
||||
|
||||
* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
|
||||
* **Motivation for or Use Case** - explain why this is a bug for you
|
||||
* **Angular Version(s)** - is it a regression?
|
||||
* **Angular Version** - what version of Angular is affected (e.g. 2.0.0-alpha.53)
|
||||
* **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
|
||||
* **Browsers and Operating System** - is this a problem with all browsers?
|
||||
* **Reproduce the Error** - provide a live example (using [Plunker][plunker],
|
||||
[JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps.
|
||||
[JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps
|
||||
* **Related Issues** - has a similar issue been reported before?
|
||||
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
|
||||
causing the problem (line of code or commit)
|
||||
|
||||
You can file new issues by providing the above information [here](https://github.com/angular/angular/issues/new).
|
||||
|
||||
|
||||
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
||||
Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
|
||||
* Search [GitHub](https://github.com/angular/angular.dart/pulls) for an open or closed PR
|
||||
* Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
* Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
||||
We cannot accept code without this.
|
||||
@ -147,9 +139,9 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
|
||||
|
||||
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
|
||||
* All public API methods **must be documented**. (Details TBC).
|
||||
* With the exceptions listed below, we follow the rules contained in
|
||||
[Google's JavaScript Style Guide][js-style-guide]:
|
||||
* Wrap all code at **100 characters**.
|
||||
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
|
||||
**100 characters**. An automated formatter is available, see
|
||||
[DEVELOPER.md](DEVELOPER.md#clang-format).
|
||||
|
||||
## <a name="commit"></a> Commit Message Guidelines
|
||||
|
||||
@ -169,9 +161,14 @@ format that includes a **type**, a **scope** and a **subject**:
|
||||
<footer>
|
||||
```
|
||||
|
||||
The **header** is mandatory and the **scope** of the header is optional.
|
||||
|
||||
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
|
||||
to read on GitHub as well as in various git tools.
|
||||
|
||||
### Revert
|
||||
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
|
||||
|
||||
### Type
|
||||
Must be one of the following:
|
||||
|
||||
@ -180,14 +177,15 @@ Must be one of the following:
|
||||
* **docs**: Documentation only changes
|
||||
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
|
||||
semi-colons, etc)
|
||||
* **refactor**: A code change that neither fixes a bug or adds a feature
|
||||
* **refactor**: A code change that neither fixes a bug nor adds a feature
|
||||
* **perf**: A code change that improves performance
|
||||
* **test**: Adding missing tests
|
||||
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
|
||||
generation
|
||||
* **test**: Adding missing tests or correcting existing tests
|
||||
* **build**: Changes that affect the build system, CI configuration or external dependencies (example scopes: gulp, broccoli, npm)
|
||||
* **ci**: Any changes to our CI configuration files and scripts (Travis, Circle CI, BrowserStack, SauceLabs)
|
||||
* **chore**: Other changes that don't modify `src` or `test` files
|
||||
|
||||
### Scope
|
||||
The scope could be anything specifying place of the commit change. For example
|
||||
The scope could be anything specifying place of the commit change. For example
|
||||
`Compiler`, `ElementInjector`, etc.
|
||||
|
||||
### Subject
|
||||
@ -205,6 +203,7 @@ The body should include the motivation for the change and contrast this with pre
|
||||
The footer should contain any information about **Breaking Changes** and is also the place to
|
||||
reference GitHub issues that this commit **Closes**.
|
||||
|
||||
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
|
||||
|
||||
A detailed explanation can be found in this [document][commit-message-format].
|
||||
|
||||
|
196
DEVELOPER.md
196
DEVELOPER.md
@ -7,7 +7,9 @@ JS and Dart versions. It also explains the basic mechanics of using `git`, `node
|
||||
* [Getting the Sources](#getting-the-sources)
|
||||
* [Environment Variable Setup](#environment-variable-setup)
|
||||
* [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
|
||||
* [Build commands](#build-commands)
|
||||
* [Running Tests Locally](#running-tests-locally)
|
||||
* [Code Style](#code-style)
|
||||
* [Project Information](#project-information)
|
||||
* [CI using Travis](#ci-using-travis)
|
||||
* [Transforming Dart code](#transforming-dart-code)
|
||||
@ -21,41 +23,40 @@ if you'd like to contribute to Angular.
|
||||
Before you can build and test Angular, you must install and configure the
|
||||
following products on your development machine:
|
||||
|
||||
* [Dart](https://www.dartlang.org) (version ` >=1.9.0 <2.0.0`), specifically the Dart-SDK and
|
||||
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or
|
||||
[Windows](http://windows.github.com)); [GitHub's Guide to Installing
|
||||
Git](https://help.github.com/articles/set-up-git) is a good source of information.
|
||||
|
||||
* [Node.js](http://nodejs.org), (version `>=5.4.1 <6`) which is used to run a development web server,
|
||||
run tests, and generate distributable files. We also use Node's Package Manager, `npm`
|
||||
(version `>=3.5.3 <4.0`), which comes with Node. Depending on your system, you can install Node either from
|
||||
source or as a pre-packaged bundle.
|
||||
|
||||
* *Optional*: [Dart](https://www.dartlang.org) (version ` >=1.13.2 <2.0.0`), specifically the Dart-SDK and
|
||||
Dartium (a version of [Chromium](http://www.chromium.org) with native support for Dart through
|
||||
the Dart VM). One of the **simplest** ways to get both is to install the **Dart Editor bundle**,
|
||||
which includes the editor, SDK and Dartium. See the [Dart tools](https://www.dartlang.org/tools)
|
||||
download [page for instructions](https://www.dartlang.org/tools/download.html); note that you can
|
||||
download both **stable** and **dev** channel versions from the [download
|
||||
archive](https://www.dartlang.org/tools/download-archive).
|
||||
download [page for instructions](https://www.dartlang.org/tools/download.html).
|
||||
You can also download both **stable** and **dev** channel versions from the [download
|
||||
archive](https://www.dartlang.org/tools/download-archive). In that case, on Windows, Dart must be added
|
||||
to the `Path` (e.g. `path-to-dart-sdk-folder\bin`) and a new `DARTIUM_BIN` environment variable must be
|
||||
created, pointing to the executable (e.g. `path-to-dartium-folder\chrome.exe).`
|
||||
|
||||
* [Git](http://git-scm.com) and/or the **Github app** (for [Mac](http://mac.github.com) or
|
||||
[Windows](http://windows.github.com)): the [Github Guide to Installing
|
||||
Git](https://help.github.com/articles/set-up-git) is a good source of information.
|
||||
|
||||
* [Node.js](http://nodejs.org) which is used to run a development web server, run tests, and
|
||||
generate distributable files. We also use Node's Package Manager (`npm`). Depending on your
|
||||
system, you can install Node either from source or as a pre-packaged bundle.
|
||||
|
||||
* [Chrome Canary](https://www.google.com/chrome/browser/canary.html), a version of Chrome with
|
||||
bleeding edge functionality, built especially for developers (and early adopters).
|
||||
|
||||
* [Bower](http://bower.io/).
|
||||
|
||||
|
||||
## Getting the Sources
|
||||
|
||||
Forking and cloning the Angular repository:
|
||||
Fork and clone the Angular repository:
|
||||
|
||||
1. Login to your Github account or create one by following the instructions given
|
||||
1. Login to your GitHub account or create one by following the instructions given
|
||||
[here](https://github.com/signup/free).
|
||||
2. [Fork](http://help.github.com/forking) the [main Angular
|
||||
repository](https://github.com/angular/angular).
|
||||
3. Clone your fork of the Angular repository and define an `upstream` remote pointing back to
|
||||
the Angular repository that you forked in the first place:
|
||||
the Angular repository that you forked in the first place.
|
||||
|
||||
```shell
|
||||
# Clone your Github repository:
|
||||
# Clone your GitHub repository:
|
||||
git clone git@github.com:<github username>/angular.git
|
||||
|
||||
# Go to the Angular directory:
|
||||
@ -91,9 +92,17 @@ export DART_SDK="$DART_EDITOR_DIR/dart-sdk"
|
||||
PATH+=":$DART_SDK/bin"
|
||||
```
|
||||
|
||||
And specify where the pub’s dependencies are downloaded. By default, this directory is located under .pub_cache
|
||||
in your home directory (on Mac and Linux), or in AppData\Roaming\Pub\Cache (on Windows).
|
||||
|
||||
```shell
|
||||
# PUB_CACHE: location of pub dependencies
|
||||
export PUB_CACHE="/Users/<user>/.pub-cache"
|
||||
```
|
||||
|
||||
## Installing NPM Modules and Dart Packages
|
||||
|
||||
Next, install the modules and packages needed to build Angular and run tests:
|
||||
Next, install the JavaScript modules and Dart packages needed to build and test Angular:
|
||||
|
||||
```shell
|
||||
# Install Angular project dependencies (package.json)
|
||||
@ -117,7 +126,7 @@ use in these instructions.
|
||||
|
||||
## Build commands
|
||||
|
||||
To build Angular and prepare tests run:
|
||||
To build Angular and prepare tests, run:
|
||||
|
||||
```shell
|
||||
$(npm bin)/gulp build
|
||||
@ -126,14 +135,15 @@ $(npm bin)/gulp build
|
||||
Notes:
|
||||
* Results are put in the `dist` folder.
|
||||
* This will also run `pub get` for the subfolders in `modules` and run `dartanalyzer` for
|
||||
every file that matches `<module>/src/<module>.dart`, e.g. `di/src/di.dart`
|
||||
every file that matches `<module>/src/<module>.dart`, e.g. `di/src/di.dart`.
|
||||
|
||||
You can selectively build either the JS or Dart versions as follows:
|
||||
|
||||
* `$(npm bin)/gulp build.js`
|
||||
* `$(npm bin)/gulp build.dart`
|
||||
|
||||
To clean out the `dist` folder use:
|
||||
To clean out the `dist` folder, run:
|
||||
|
||||
```shell
|
||||
$(npm bin)/gulp clean
|
||||
```
|
||||
@ -142,8 +152,8 @@ $(npm bin)/gulp clean
|
||||
|
||||
### Full test suite
|
||||
|
||||
* `npm test`: full test suite for both JS and Dart versions of Angular. These are the same tests as
|
||||
those run on Travis.
|
||||
* `npm test`: full test suite for both JS and Dart versions of Angular. These are the same tests
|
||||
that run on Travis.
|
||||
|
||||
You can selectively run either the JS or Dart versions as follows:
|
||||
|
||||
@ -154,7 +164,7 @@ You can selectively run either the JS or Dart versions as follows:
|
||||
|
||||
You can run just the unit tests as follows:
|
||||
|
||||
* `$(npm bin)/gulp test.unit.js`: JS tests in a browser; runs in **watch mode** (i.e. karma
|
||||
* `$(npm bin)/gulp test.unit.js`: JS tests in a browser; runs in **watch mode** (i.e.
|
||||
watches the test files for changes and re-runs tests when files are updated).
|
||||
* `$(npm bin)/gulp test.unit.cjs`: JS tests in NodeJS; runs in **watch mode**.
|
||||
* `$(npm bin)/gulp test.unit.dart`: Dart tests in Dartium; runs in **watch mode**.
|
||||
@ -165,21 +175,44 @@ If you prefer running tests in "single-run" mode rather than watch mode use:
|
||||
* `$(npm bin)/gulp test.unit.cjs/ci`
|
||||
* `$(npm bin)/gulp test.unit.dart/ci`
|
||||
|
||||
The task updates the dist folder with transpiled code whenever a source or test file changes, and
|
||||
Karma is run against the new output.
|
||||
|
||||
**Note**: If you want to only run a single test you can alter the test you wish to run by changing
|
||||
`it` to `iit` or `describe` to `ddescribe`. This will only run that individual test and make it
|
||||
much easier to debug. `xit` and `xdescribe` can also be useful to exclude a test and a group of
|
||||
tests respectively.
|
||||
|
||||
**Note for transpiler tests**: The karma preprocessor is setup in a way so that after every test
|
||||
run the transpiler is reloaded. With that it is possible to make changes to the preprocessor and
|
||||
run the tests without exiting karma (just touch a test file that you would like to run).
|
||||
**Note**: **watch mode** needs symlinks to work, so if you're using windows, ensure you have the
|
||||
rights to built them in your operating system.
|
||||
|
||||
### E2e tests
|
||||
### Unit tests with Sauce Labs or Browser Stack
|
||||
|
||||
First, in a terminal, create a tunnel with [Sauce Connect](https://docs.saucelabs.com/reference/sauce-connect/) or [Browser Stack Local](https://www.browserstack.com/local-testing#command-line), and valid credentials.
|
||||
|
||||
Then, in another terminal:
|
||||
- Define the credentials as environment variables, e.g.:
|
||||
```
|
||||
export SAUCE_USERNAME='my_user'; export SAUCE_ACCESS_KEY='my_key';
|
||||
export BROWSER_STACK_USERNAME='my_user'; export BROWSER_STACK_ACCESS_KEY='my_key';
|
||||
```
|
||||
- Then run `gulp test.unit.js.(sauce|browserstack) --browsers=option1,option2,..,optionN`
|
||||
The options are any mix of browsers and aliases which are defined in the [browser-providers.conf.js](https://github.com/angular/angular/blob/master/browser-providers.conf.js) file.
|
||||
They are case insensitive, and the `SL_` or `BS_` prefix must not be added for browsers.
|
||||
|
||||
Some examples of commands:
|
||||
```
|
||||
gulp test.unit.js.sauce --browsers=Safari8,ie11 //run in Sauce Labs with Safari 8 and IE11
|
||||
gulp test.unit.js.browserstack --browsers=Safari,IE //run in Browser Stack with Safari 7, Safari 8, Safari 9, IE 9, IE 10 and IE 11
|
||||
gulp test.unit.js.sauce --browsers=IOS,safari8,android5.1 //run in Sauce Labs with iOS 7, iOS 8, iOs 9, Safari 8 and Android 5.1
|
||||
```
|
||||
|
||||
### E2E tests
|
||||
|
||||
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder).
|
||||
2. `$(npm bin)/gulp serve.js.prod serve.js.dart2js` (runs local webserver).
|
||||
2. `$(npm bin)/gulp serve.js.prod serve.dart` (runs a local webserver).
|
||||
3. `$(npm bin)/protractor protractor-js.conf.js`: JS e2e tests.
|
||||
4. `$(npm bin)/protractor protractor-dart2js.conf.js`: Dart2JS e2e tests.
|
||||
4. `$(npm bin)/protractor protractor-dart2js.conf.js`: dart2js e2e tests.
|
||||
|
||||
Angular specific command line options when running protractor:
|
||||
- `$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
|
||||
@ -187,13 +220,84 @@ Angular specific command line options when running protractor:
|
||||
### Performance tests
|
||||
|
||||
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder)
|
||||
2. `$(npm bin)/gulp serve.js.prod serve.js.dart2js` (runs local webserver)
|
||||
2. `$(npm bin)/gulp serve.js.prod serve.dart` (runs a local webserver)
|
||||
3. `$(npm bin)/protractor protractor-js.conf.js --benchmark`: JS performance tests
|
||||
4. `$(npm bin)/protractor protractor-dart2js.conf.js --benchmark`: Dart2JS performance tests
|
||||
4. `$(npm bin)/protractor protractor-dart2js.conf.js --benchmark`: dart2js performance tests
|
||||
|
||||
Angular specific command line options when running protractor (e.g. force gc, ...):
|
||||
`$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
|
||||
|
||||
## Code Style
|
||||
|
||||
### Formatting with <a name="clang-format">clang-format</a>
|
||||
|
||||
We use [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to automatically enforce code
|
||||
style for our TypeScript code. This allows us to focus our code reviews more on the content, and
|
||||
less on style nit-picking. It also lets us encode our style guide in the `.clang-format` file in the
|
||||
repository, allowing many tools and editors to share our settings.
|
||||
|
||||
To check the formatting of your code, run
|
||||
|
||||
gulp check-format
|
||||
|
||||
Note that the continuous build on Travis runs `gulp enforce-format`. Unlike the `check-format` task,
|
||||
this will actually fail the build if files aren't formatted according to the style guide.
|
||||
|
||||
Your life will be easier if you include the formatter in your standard workflow. Otherwise, you'll
|
||||
likely forget to check the formatting, and waste time waiting for a build on Travis that fails due
|
||||
to some whitespace difference.
|
||||
|
||||
* Use `$(npm bin)/clang-format -i [file name]` to format a file (or multiple).
|
||||
* Use `gulp enforce-format` to check if your code is `clang-format` clean. This also gives
|
||||
you a command line to format your code.
|
||||
* `clang-format` also includes a git hook, run `git clang-format` to format all files you
|
||||
touched.
|
||||
* You can run this as a **git pre-commit hook** to automatically format your delta regions when you
|
||||
commit a change. In the angular repo, run
|
||||
|
||||
```
|
||||
$ echo -e '#!/bin/sh\nexec git clang-format' > .git/hooks/pre-commit
|
||||
$ chmod u+x !$
|
||||
```
|
||||
|
||||
* **WebStorm** can run clang-format on the current file.
|
||||
1. Under Preferences, open Tools > External Tools.
|
||||
1. Plus icon to Create Tool
|
||||
1. Fill in the form:
|
||||
- Name: clang-format
|
||||
- Description: Format
|
||||
- Synchronize files after execution: checked
|
||||
- Open console: not checked
|
||||
- Show in: Editor menu
|
||||
- Program: `$ProjectFileDir$/node_modules/.bin/clang-format`
|
||||
- Parameters: `-i -style=file $FilePath$`
|
||||
- Working directory: `$ProjectFileDir$`
|
||||
* `clang-format` integrations are also available for many popular editors (`vim`, `emacs`,
|
||||
`Sublime Text`, etc.).
|
||||
|
||||
### Linting
|
||||
|
||||
We use [tslint](https://github.com/palantir/tslint) for linting. See linting rules in [gulpfile](gulpfile.js). To lint, run
|
||||
|
||||
```shell
|
||||
$ gulp lint
|
||||
```
|
||||
|
||||
## Generating the API documentation
|
||||
|
||||
The following gulp task will generate the API docs in the `dist/angular.io/partials/api/angular2`:
|
||||
|
||||
```shell
|
||||
$(npm bin)/gulp docs/angular.io
|
||||
```
|
||||
|
||||
You can serve the generated documentation to check how it would render on [angular.io](https://angular.io/):
|
||||
- check out the [angular.io repo](https://github.com/angular/angular.io) locally,
|
||||
- install dependencies as described in the [angular.io README](https://github.com/angular/angular.io/blob/master/README.md),
|
||||
- copy the generated documentation from your local angular repo at `angular/dist/angular.io/partials/api/angular2` to your local angular.io repo at `angular.io/public/docs/js/latest/api`,
|
||||
- run `harp compile` at the root of the angular.io repo to check the generated documentation for errors,
|
||||
- run `harp server` and open a browser at `http://localhost:9000/docs/js/latest/api/` to check the rendered documentation.
|
||||
|
||||
## Project Information
|
||||
|
||||
### Folder structure
|
||||
@ -204,10 +308,8 @@ Angular specific command line options when running protractor (e.g. force gc, ..
|
||||
|
||||
### File suffixes
|
||||
|
||||
* `*.js`: javascript files that get transpiled to Dart and EcmaScript 5
|
||||
* `*.es6`: javascript files that get transpiled only to EcmaScript 5
|
||||
* `*.es5`: javascript files that don't get transpiled
|
||||
* `*.dart`: dart files that don't get transpiled
|
||||
* `*.ts`: TypeScript files that get transpiled to Dart and EcmaScript 5/6
|
||||
* `*.dart`: Dart files that don't get transpiled
|
||||
|
||||
## CI using Travis
|
||||
|
||||
@ -243,16 +345,18 @@ Notes:
|
||||
|
||||
If you need to debug the tests:
|
||||
|
||||
- add a `debugger;` statement to the test you want to debug (oe the source code),
|
||||
- add a `debugger;` statement to the test you want to debug (or the source code),
|
||||
- execute karma `$(npm bin)/gulp test.js`,
|
||||
- press the top right "DEBUG" button,
|
||||
- open the dev tools and press F5,
|
||||
- the execution halt at the `debugger;` statement
|
||||
- open the DevTools and press F5,
|
||||
- the execution halts at the `debugger;` statement
|
||||
|
||||
**Note (WebStorm users)**:
|
||||
You can create a Karma run config from WebStorm.
|
||||
Then in the "Run" menu, press "Debug 'karma-js.conf.js'", WebStorm will stop in the generated code
|
||||
on the `debugger;` statement.
|
||||
You can then step into the code and add watches.
|
||||
|
||||
1. Create a Karma run config from WebStorm.
|
||||
2. Then in the "Run" menu, press "Debug 'karma-js.conf.js'", and WebStorm will stop in the generated
|
||||
code on the `debugger;` statement.
|
||||
3. You can then step into the code and add watches.
|
||||
|
||||
The `debugger;` statement is needed because WebStorm will stop in a transpiled file. Breakpoints in
|
||||
the original source files are not supported at the moment.
|
||||
|
215
LICENSE
215
LICENSE
@ -1,202 +1,21 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
The MIT License
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
Copyright (c) 2014-2016 Google, Inc. http://angular.io
|
||||
|
||||
1. Definitions.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
32
NAMING.md
Normal file
32
NAMING.md
Normal file
@ -0,0 +1,32 @@
|
||||
Naming Conventions in Angular2
|
||||
---
|
||||
|
||||
In general Angular2 should follow TypeScript naming conventions.
|
||||
See: https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines
|
||||
|
||||
|
||||
Classes:
|
||||
- Example: `Compiler`, `ApplicationMetadata`
|
||||
- Camel case with first letter upper-case
|
||||
- In general prefer single words. (This is so that when appending `Proto` or `Factory` the class
|
||||
is still reasonable to work with.)
|
||||
- Should not end with `Impl` or any other word which describes a specific implementation of an
|
||||
interface.
|
||||
|
||||
|
||||
Interfaces:
|
||||
- Follow the same rules as Classes
|
||||
- Should not have `I` or `Interface` in the name or any other way of identifying it as an interface.
|
||||
|
||||
|
||||
Methods and functions:
|
||||
- Example: `bootstrap`, `someMethod`
|
||||
- Should be camel case with first lower case
|
||||
|
||||
|
||||
Constants
|
||||
- Example: `CORE_DIRECTIVES`
|
||||
- Should be all uppercase with SNAKE_CASE
|
||||
|
||||
|
||||
|
49
README.md
49
README.md
@ -1,53 +1,34 @@
|
||||
Angular [](https://travis-ci.org/angular/angular) [](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://travis-ci.org/angular/angular)
|
||||
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](http://badge.fury.io/js/angular2)
|
||||
[](https://npmjs.org/package/angular2)
|
||||
[](https://saucelabs.com/u/angular2-ci)
|
||||
|
||||
Angular
|
||||
=========
|
||||
|
||||
Angular is a development platform for building mobile and desktop web applications. This is the
|
||||
repository for [Angular 2][ng2], both the JavaScript (JS) and [Dart][dart] versions.
|
||||
|
||||
Angular 2 is currently in **Alpha Preview**. We recommend using Angular 1.X for production
|
||||
applications:
|
||||
Angular 2 is currently in **Beta**.
|
||||
|
||||
* [AngularJS][ngJS]: [angular/angular.js](http://github.com/angular/angular.js).
|
||||
* [AngularDart][ngDart]: [angular/angular.dart](http://github.com/angular/angular.dart).
|
||||
## Quickstart
|
||||
|
||||
|
||||
## Setup & Install Angular 2
|
||||
|
||||
Follow the instructions given on the [Angular download page][download].
|
||||
[Get started in 5 minutes][quickstart].
|
||||
|
||||
|
||||
## Want to help?
|
||||
|
||||
Want to file a bug, or contribute some code or improve documentation? Excellent! Read up on our
|
||||
guidelines for [contributing][contributing].
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
|
||||
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
To see the examples, first build the project as described
|
||||
[here](http://github.com/angular/angular/blob/master/DEVELOPER.md).
|
||||
|
||||
### Hello World Example
|
||||
|
||||
This example consists of three basic pieces - a component, a decorator and a
|
||||
service. They are all constructed via injection. For more information see the
|
||||
comments in the source `modules/examples/src/hello_world/index.js`.
|
||||
|
||||
You can build this example as either JS or Dart app:
|
||||
|
||||
* JS:
|
||||
* `$(npm bin)/gulp build.js.dev`, and
|
||||
* `$(npm bin)/gulp serve.js.dev`, and
|
||||
* open `localhost:8000/examples/src/hello_world/` in Chrome.
|
||||
* Dart:
|
||||
* `$(npm bin)/gulp serve/examples.dart`, and
|
||||
* open `localhost:8080/src/hello_world` in Chrome (for dart2js) or
|
||||
[Dartium][dartium] (for Dart VM).
|
||||
|
||||
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
|
||||
[dart]: http://www.dartlang.org
|
||||
[dartium]: http://www.dartlang.org/tools/dartium
|
||||
[download]: http://angular.io/download
|
||||
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
|
||||
[ng2]: http://angular.io
|
||||
[ngDart]: http://angulardart.org
|
||||
[ngJS]: http://angularjs.org
|
||||
|
4
TOOLS.md
Normal file
4
TOOLS.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Developer Tools for Angular 2
|
||||
|
||||
- [JavaScript](TOOLS_JS.md)
|
||||
- [Dart](TOOLS_DART.md)
|
376
TOOLS_DART.md
Normal file
376
TOOLS_DART.md
Normal file
@ -0,0 +1,376 @@
|
||||
# Developer Tools for Dart
|
||||
|
||||
Use these tools and techniques to increase your app's performance
|
||||
and reliability.
|
||||
|
||||
* [Angular debugging tools](#angular-debugging-tools)
|
||||
* [Code size](#code-size)
|
||||
* [Performance](#performance)
|
||||
|
||||
|
||||
## Angular debugging tools
|
||||
|
||||
Starting with alpha.38, Angular provides a set of debugging tools
|
||||
that are accessible from any browser's developer console.
|
||||
In Chrome, you can get to the dev console by pressing
|
||||
Ctrl + Shift + J (on Mac: Cmd + Opt + J).
|
||||
|
||||
### Enabling the debugging tools
|
||||
|
||||
By default the debugging tools are disabled.
|
||||
Enable the debugging tools as follows:
|
||||
|
||||
```dart
|
||||
import 'package:angular2/platform/browser.dart';
|
||||
|
||||
main() async {
|
||||
var appRef = await bootstrap(Application);
|
||||
enableDebugTools(appRef);
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Change function name to enableDebuggingTools? -->
|
||||
|
||||
|
||||
### Using the debugging tools
|
||||
|
||||
In the browser, open the dev console. The top-level object is called `ng` and
|
||||
contains more specific tools inside it.
|
||||
|
||||
For example, to run the change detection profiler on your app:
|
||||
|
||||
```javascript
|
||||
// In the dev console:
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The [Change detection profiler](#change-detection-profiler) section
|
||||
has more details.
|
||||
<!-- Point to API docs when they're published, if they're useful.
|
||||
They should be under
|
||||
http://www.dartdocs.org/documentation/angular2/latest
|
||||
and/or
|
||||
https://angular.io/docs/js/latest/api/. -->
|
||||
|
||||
|
||||
## Code size
|
||||
|
||||
Code must be downloaded, parsed, and executed. Too much code can lead to
|
||||
slow application start-up time, especially on slow networks and low-end devices.
|
||||
The tools and techniques in this section can help you to identify
|
||||
unnecessarily large code and to reduce code size.
|
||||
|
||||
### Finding contributors to code size
|
||||
|
||||
Options for investigating code size include the `--dump-info` dart2js option,
|
||||
ng2soyc, `reflector.trackUsage()`, and code coverage information
|
||||
from the Dart VM.
|
||||
|
||||
#### Use --dump-info
|
||||
|
||||
The `--dump-info` option of `dart2js` outputs information about what happened
|
||||
during compilation. You can specify `--dump-info` in `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
transformers:
|
||||
...
|
||||
- $dart2js:
|
||||
commandLineOptions:
|
||||
- --dump-info
|
||||
```
|
||||
|
||||
The [Dump Info Visualizer](https://github.com/dart-lang/dump-info-visualizer)
|
||||
can help you analyze the output.
|
||||
For more information, see the
|
||||
[dart2js_info API reference](http://dart-lang.github.io/dart2js_info/doc/api/).
|
||||
|
||||
#### Use ng2soyc.dart
|
||||
|
||||
[ng2soyc](https://github.com/angular/ng2soyc.dart) is a utility for analyzing
|
||||
code size contributors in Angular 2 applications. It groups code size by
|
||||
library and, assuming your library names follow
|
||||
[standard naming conventions](https://www.dartlang.org/articles/style-guide/#do-prefix-library-names-with-the-package-name-and-a-dot-separated-path)
|
||||
(package.library.sublibrary...), gives the code size breakdown at
|
||||
each level. To reduce noise in the output of very large apps, ng2soyc provides
|
||||
an option to hide libraries that are too small, so you can focus on the biggest
|
||||
contributors.
|
||||
|
||||
#### Find unused reflection data
|
||||
|
||||
Your app might have types that are annotated with `@Component` or `@Injectable`
|
||||
but never used.
|
||||
To find these unused types, use `reflector.trackUsage()` and then,
|
||||
after exercising your app, `reflector.listUnusedKeys()`.
|
||||
For example:
|
||||
|
||||
```
|
||||
import 'package:angular2/src/core/reflection/reflection.dart';
|
||||
...
|
||||
main() async {
|
||||
reflector.trackUsage();
|
||||
await bootstrap(AppComponent);
|
||||
print('Unused keys: ${reflector.listUnusedKeys()}');
|
||||
}
|
||||
```
|
||||
|
||||
When you run that code (in Dartium or another browser),
|
||||
you'll see a list of types that Angular _can_ inject but hasn't needed to.
|
||||
Consider removing those types or their `@Component`/`@Injectable` annotation
|
||||
to decrease your app's code size.
|
||||
|
||||
Three conditions must be true for `listUnusedKeys()` to return helpful data:
|
||||
|
||||
1. The angular2 transformer must run on the app.
|
||||
2. If you're running a JavaScript version of the app,
|
||||
the app must not be minified, so that the names are readable.
|
||||
3. You must exercise your app in as many ways as possible
|
||||
before calling `listUnusedKeys()`.
|
||||
Otherwise, you might get false positives:
|
||||
keys that haven't been used only because you didn't exercise
|
||||
the relevant feature of the app.
|
||||
|
||||
To run the angular2 transformer, first specify it in `pubspec.yaml`:
|
||||
|
||||
```
|
||||
name: hello_world
|
||||
...
|
||||
transformers:
|
||||
- angular2:
|
||||
entry_points: web/main.dart
|
||||
```
|
||||
|
||||
Then use pub to run the transformer. If you use `pub serve`,
|
||||
it provides both Dart and unminified (by default) JavaScript versions.
|
||||
If you want to serve actual files, then use `pub build` in debug mode
|
||||
to generate Dart and unminified JavaScript files:
|
||||
`pub build --mode=debug`.
|
||||
|
||||
The `reflector.trackUsage()` method makes Angular track the reflection
|
||||
information used by the app. Reflection information (`ReflectionInfo`) is a data
|
||||
structure that stores information that Angular uses for locating DI factories
|
||||
and for generating change detectors and other code related to a
|
||||
given type.
|
||||
|
||||
#### Use code coverage to find dead code
|
||||
|
||||
When running in Dartium (or in the Dart VM, in general) you can request code
|
||||
coverage information from the VM. You can either use
|
||||
[observatory](https://www.dartlang.org/tools/observatory/) or download
|
||||
the coverage file and use your own tools to inspect it. Lines of code that are
|
||||
not covered are top candidates for dead code.
|
||||
|
||||
Keep in mind, however, that uncovered code is not sufficient evidence of dead
|
||||
code, only necessary evidence. It is perfectly possible that you simply didn't
|
||||
exercise your application in a way that triggers the execution of uncovered
|
||||
code. A common example is error handling code. Just because your testing never
|
||||
encountered an error does not mean the error won't happen in production. You
|
||||
therefore don't have to rush and remove all the `catch` blocks.
|
||||
|
||||
### Reducing code size
|
||||
|
||||
To reduce code size, you can disable reflection,
|
||||
enable minification, and manually remove dead code.
|
||||
You can also try less safe options such as
|
||||
telling dart2js to trust type annotations.
|
||||
|
||||
|
||||
#### Disable reflection
|
||||
|
||||
`dart:mirrors` allows discovering program metadata at runtime. However, this
|
||||
means that `dart2js` needs to retain that metadata and thus increase the size
|
||||
of resulting JS output. In practice, however, it is possible to extract most
|
||||
metadata necessary for your metaprogramming tasks statically using a
|
||||
transformer and `package:analyzer`, and act on it before compiling to JS.
|
||||
|
||||
#### Enable minification
|
||||
|
||||
Minification shortens all your `longMethodNames` into 2- or 3-letter long
|
||||
symbols. `dart2js` ensures that this kind of renaming is done safely, without
|
||||
breaking the functionality of your programs. You can enable it in `pubspec.yaml`
|
||||
under `$dart2js` transformer:
|
||||
|
||||
```yaml
|
||||
transformers:
|
||||
...
|
||||
- $dart2js:
|
||||
minify: true
|
||||
```
|
||||
|
||||
#### Manually remove dead code
|
||||
|
||||
`dart2js` comes with dead code elimination out-of-the-box. However, it may not
|
||||
always be able to tell if a piece of code could be used. Consider the following
|
||||
example:
|
||||
|
||||
```dart
|
||||
/// This function decides which serialization format to use
|
||||
void setupSerializers() {
|
||||
if (server.doYouSupportProtocolBuffers()) {
|
||||
useProtobufSerializers();
|
||||
} else {
|
||||
useJsonSerializers();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example the application asks the server what kind of serialization
|
||||
format it uses and dynamically chooses one or the other. `dart2js` can't
|
||||
tell whether the server responds with yes or no, so it must retain both
|
||||
kinds of serializers. However, if you know that your server supports
|
||||
protocol buffers, you can remove that `if` block entirely and default to
|
||||
protocol buffers.
|
||||
|
||||
Code coverage (see above) is a good way to find dead code in your app.
|
||||
|
||||
#### Unsafe options
|
||||
|
||||
Dart also provides more aggressive optimization options. However, you have to
|
||||
be careful when using them and as of today the benefits aren't that clear. If
|
||||
your type annotations are inaccurate you may end up with non-Darty runtime
|
||||
behavior, including the classic "undefined is not a function" tautology, as
|
||||
well as the "keep on truckin'" behavior, e.g. `null + 1 == 1` and
|
||||
`{} + [] == 0`.
|
||||
|
||||
`--trust-type-annotations` tells `dart2js` to trust that your type annotations
|
||||
are correct. So if you have a function `foo(Bar bar)` the compiler can omit the
|
||||
check that `bar` is truly `Bar` when calling methods on it.
|
||||
|
||||
`--trust-primitives` tells `dart2js` that primitive types, such as numbers and
|
||||
booleans are never `null` when performing arithmetic, and that your program
|
||||
does not run into range error when operating on lists, letting the compiler
|
||||
remove some of the error checking code.
|
||||
|
||||
Specify these options in `pubspec.yaml`.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
transformers:
|
||||
...
|
||||
- $dart2js:
|
||||
commandLineOptions:
|
||||
- --trust-type-annotations
|
||||
- --trust-primitives
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
### Change detection profiler
|
||||
|
||||
If your application is janky (it misses frames) or is slow according to other
|
||||
metrics, you need to find out why. This tool helps by measuring the average
|
||||
speed of _change detection_, a phase in Angular's
|
||||
lifecycle that detects changes in values that are bound to the UI.
|
||||
Janky UI updates can result from slowness either in _computing_ the changes or
|
||||
in _applying_ those changes to the UI.
|
||||
|
||||
For your app to be performant, the process of _computing_ changes must be very
|
||||
fast—preferably **under 3 milliseconds**.
|
||||
Fast change computation leaves room for
|
||||
the application logic, UI updates, and browser rendering pipeline
|
||||
to fit within a 16 ms frame (assuming a target frame rate of 60 FPS).
|
||||
|
||||
The change detection profiler repeatedly performs change detection
|
||||
without invoking any user actions, such as clicking buttons or entering
|
||||
text in input fields. It then computes the average amount of time
|
||||
(in milliseconds) to perform a single cycle of change detection and
|
||||
prints that to the console. This number depends on the current state of the UI. You are likely to see different numbers
|
||||
as you go from one screen in your application to another.
|
||||
|
||||
#### Running the profiler
|
||||
|
||||
Before running the profiler, enable the debugging tools
|
||||
and put the app into the state you want to measure:
|
||||
|
||||
1. If you haven't already done so,
|
||||
[enable the debugging tools](#enabling-the-debugging-tools).
|
||||
2. Navigate the app to a screen whose performance you want to profile.
|
||||
3. Make sure the screen is in a state that you want to measure.
|
||||
For example, you might want to profile the screen several times,
|
||||
with different amounts and kinds of data.
|
||||
|
||||
To run the profiler, enter the following in the dev console:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The results are visible in the console.
|
||||
|
||||
|
||||
#### Recording CPU profiles
|
||||
|
||||
To record a profile, pass `{record: true}` to `timeChangeDetection()`:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then open the **Profiles** tab. The recorded profile has the title
|
||||
**Change Detection**. In Chrome, if you record the profile repeatedly, all the
|
||||
profiles are nested under Change Detection.
|
||||
|
||||
|
||||
#### Interpreting the numbers
|
||||
|
||||
In a properly designed application, repeated attempts to detect changes without
|
||||
any user actions result in no changes to the UI. It is
|
||||
also desirable to have the cost of a user action be proportional to the amount
|
||||
of UI changes required. For example, popping up a menu with 5 items should be
|
||||
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
|
||||
change detection with no UI updates should be as fast as possible.
|
||||
|
||||
#### Investigating slow change detection
|
||||
|
||||
So you found a screen in your application on which the profiler reports a very
|
||||
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
|
||||
recording while profiling:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then look for hot spots using
|
||||
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
|
||||
|
||||
#### Reducing change detection cost
|
||||
|
||||
There are many reasons for slow change detection. To gain intuition about
|
||||
possible causes it helps to understand how change detection works. Such a
|
||||
discussion is outside the scope of this document,
|
||||
but here are some key concepts.
|
||||
|
||||
<!-- TODO: link to change detection docs -->
|
||||
|
||||
By default, Angular uses a _dirty checking_ mechanism to find model changes.
|
||||
This mechanism involves evaluating every bound expression that's active on the
|
||||
UI. These usually include text interpolation via `{{expression}}` and property
|
||||
bindings via `[prop]="expression"`. If any of the evaluated expressions are
|
||||
costly to compute, they might contribute to slow change detection. A good way to
|
||||
speed things up is to use plain class fields in your expressions and avoid any
|
||||
kind of computation. For example:
|
||||
|
||||
```dart
|
||||
@View(
|
||||
template: '<button [enabled]="isEnabled">{{title}}</button>'
|
||||
)
|
||||
class FancyButton {
|
||||
// GOOD: no computation, just returns the value
|
||||
bool isEnabled;
|
||||
|
||||
// BAD: computes the final value upon request
|
||||
String _title;
|
||||
String get title => _title.trim().toUpperCase();
|
||||
}
|
||||
```
|
||||
|
||||
Most cases like these can be solved by precomputing the value and storing the
|
||||
final value in a field.
|
||||
|
||||
Angular also supports a second type of change detection: the _push_ model. In
|
||||
this model, Angular does not poll your component for changes. Instead, the
|
||||
component tells Angular when it changes, and only then does Angular perform
|
||||
the update. This model is suitable in situations when your data model uses
|
||||
observable or immutable objects.
|
||||
|
||||
<!-- TODO: link to discussion of push model -->
|
140
TOOLS_JS.md
Normal file
140
TOOLS_JS.md
Normal file
@ -0,0 +1,140 @@
|
||||
# Developer Tools for JavaScript
|
||||
|
||||
Here you will find a collection of tools and tips for keeping your application
|
||||
perform well and contain fewer bugs.
|
||||
|
||||
## Angular debug tools in the dev console
|
||||
|
||||
Angular provides a set of debug tools that are accessible from any browser's
|
||||
developer console. In Chrome the dev console can be accessed by pressing
|
||||
Ctrl + Shift + j.
|
||||
|
||||
### Enabling debug tools
|
||||
|
||||
By default the debug tools are disabled. You can enable debug tools as follows:
|
||||
|
||||
```typescript
|
||||
import {enableDebugTools} from 'angular2/platform/browser';
|
||||
|
||||
bootstrap(Application).then((appRef) => {
|
||||
enableDebugTools(appRef);
|
||||
});
|
||||
```
|
||||
|
||||
### Using debug tools
|
||||
|
||||
In the browser open the developer console (Ctrl + Shift + j in Chrome). The
|
||||
top level object is called `ng` and contains more specific tools inside it.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
### Change detection profiler
|
||||
|
||||
If your application is janky (it misses frames) or is slow according to other
|
||||
metrics it is important to find the root cause of the issue. Change detection
|
||||
is a phase in Angular's lifecycle that detects changes in values that are
|
||||
bound to UI, and if it finds a change it performs the corresponding UI update.
|
||||
However, sometimes it is hard to tell if the slowness is due to the act of
|
||||
computing the changes being slow, or due to the act of applying those changes
|
||||
to the UI. For your application to be performant it is important that the
|
||||
process of computing changes is very fast. For best results it should be under
|
||||
3 milliseconds in order to leave room for the application logic, the UI updates
|
||||
and browser's rendering pipeline to fit withing the 16 millisecond frame
|
||||
(assuming the 60 FPS target frame rate).
|
||||
|
||||
Change detection profiler repeatedly performs change detection without invoking
|
||||
any user actions, such as clicking buttons or entering text in input fields. It
|
||||
then computes the average amount of time it took to perform a single cycle of
|
||||
change detection in milliseconds and prints it to the console. This number
|
||||
depends on the current state of the UI. You will likely see different numbers
|
||||
as you go from one screen in your application to another.
|
||||
|
||||
#### Running the profiler
|
||||
|
||||
Enable debug tools (see above), then in the dev console enter the following:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The results will be printed to the console.
|
||||
|
||||
#### Recording CPU profile
|
||||
|
||||
Pass `{record: true}` an argument:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then open the "Profiles" tab. You will see the recorded profile titled
|
||||
"Change Detection". In Chrome, if you record the profile repeatedly, all the
|
||||
profiles will be nested under "Change Detection".
|
||||
|
||||
#### Interpreting the numbers
|
||||
|
||||
In a properly-designed application repeated attempts to detect changes without
|
||||
any user actions should result in no changes to be applied on the UI. It is
|
||||
also desirable to have the cost of a user action be proportional to the amount
|
||||
of UI changes required. For example, popping up a menu with 5 items should be
|
||||
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
|
||||
change detection with no UI updates should be as fast as possible. Ideally the
|
||||
number printed by the profiler should be well below the length of a single
|
||||
animation frame (16ms). A good rule of thumb is to keep it under 3ms.
|
||||
|
||||
#### Investigating slow change detection
|
||||
|
||||
So you found a screen in your application on which the profiler reports a very
|
||||
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
|
||||
recording while profiling:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then look for hot spots using
|
||||
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
|
||||
|
||||
#### Reducing change detection cost
|
||||
|
||||
There are many reasons for slow change detection. To gain intuition about
|
||||
possible causes it would help to understand how change detection works. Such a
|
||||
discussion is outside the scope of this document (TODO link to docs), but here
|
||||
are some key concepts in brief.
|
||||
|
||||
By default Angular uses "dirty checking" mechanism for finding model changes.
|
||||
This mechanism involves evaluating every bound expression that's active on the
|
||||
UI. These usually include text interpolation via `{{expression}}` and property
|
||||
bindings via `[prop]="expression"`. If any of the evaluated expressions are
|
||||
costly to compute they could contribute to slow change detection. A good way to
|
||||
speed things up is to use plain class fields in your expressions and avoid any
|
||||
kinds of computation. Example:
|
||||
|
||||
```typescript
|
||||
@View({
|
||||
template: '<button [enabled]="isEnabled">{{title}}</button>'
|
||||
})
|
||||
class FancyButton {
|
||||
// GOOD: no computation, just return the value
|
||||
isEnabled: boolean;
|
||||
|
||||
// BAD: computes the final value upon request
|
||||
_title: String;
|
||||
get title(): String { return this._title.trim().toUpperCase(); }
|
||||
}
|
||||
```
|
||||
|
||||
Most cases like these could be solved by precomputing the value and storing the
|
||||
final value in a field.
|
||||
|
||||
Angular also supports a second type of change detection - the "push" model. In
|
||||
this model Angular does not poll your component for changes. Instead, the
|
||||
component "tells" Angular when it changes and only then does Angular perform
|
||||
the update. This model is suitable in situations when your data model uses
|
||||
observable or immutable objects (also a discussion for another time).
|
168
TRIAGE_AND_LABELS.md
Normal file
168
TRIAGE_AND_LABELS.md
Normal file
@ -0,0 +1,168 @@
|
||||
# Triage Process and Github Labels for Angular 2
|
||||
|
||||
This document describes how the Angular team uses labels and milestones to triage issues on github.
|
||||
|
||||
# Issues and PRs
|
||||
## Triaged vs Untriaged Issues
|
||||
|
||||
Every triaged issue must have four attributes assigned to it:
|
||||
|
||||
* `priority` -- P0 through P4. P0 issues are "drop everything and do this now". P4 are nice to have.
|
||||
* `component` -- Which area of Angular knowledge this relates to.
|
||||
* `effort` -- Rough assessment of how much work this issue is. E.g. `effort: easy` means
|
||||
"probably a few hours of work".
|
||||
* `type` -- Whether this issue is a bug, feature, or other kind of task.
|
||||
|
||||
Untriaged issues are any issues in the queue that don't yet have these four attributes.
|
||||
|
||||
You can view a report of untriaged issues here, in our
|
||||
[Angular Triage Dashboard](http://mhevery.github.io/github_issues/).
|
||||
|
||||
Issues should also have a clear action to complete that can be addressed or resolved within the
|
||||
scope of Angular 2. We'll close issues that don't meet these criteria.
|
||||
|
||||
### Assigning Issues to Milestones
|
||||
|
||||
Any issue that is being worked on must have:
|
||||
|
||||
* An `assignee`: The person doing the work.
|
||||
* A `Milestone`: When we expect to complete this work.
|
||||
|
||||
We aim to only have at most three milestones open at a time:
|
||||
|
||||
* Closing Milestone: A milestone with a very small number of issues, about to release.
|
||||
* Current Milestone: Work that we plan to complete within one week.
|
||||
* Next Milestone: Work that is > 1 week but current for the team.
|
||||
|
||||
The [backlog](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Amilestone)
|
||||
consists of all issues that have been triaged but do not have an assignee or milestone.
|
||||
|
||||
## Triaged vs Untriaged PRs
|
||||
|
||||
Because of the cumulative pain associated with rebasing PRs, we triage PRs daily, and
|
||||
closing or reviewing PRs is a top priority ahead of other ongoing work.
|
||||
|
||||
Every triaged PR must have a `pr_action` label assigned to it and an assignee:
|
||||
|
||||
* `pr_action: review` -- work is complete and comment is needed from the assignee.
|
||||
* `pr_action: cleanup` -- more work is needed from the current assignee.
|
||||
* `pr_action: discuss` -- discussion is needed, to be led by the current assignee.
|
||||
* `pr_action: merge` -- the PR should be merged. Add this to a PR when you would like to
|
||||
trigger automatic merging following a successful build. This is described in [COMMITTER.md](COMMITTER.md).
|
||||
|
||||
In addition, PRs can have the following states:
|
||||
|
||||
* `pr_state: LGTM` -- PR may have outstanding changes but does not require further review.
|
||||
* `pr_state: WIP` -- PR is experimental or rapidly changing. Not ready for review or triage.
|
||||
* `pr_state: blocked` -- PR is blocked on an issue or other PR. Not ready for review or triage.
|
||||
|
||||
Note that an LGTM state does not mean a PR is ready to merge: for example, a reviewer might set the
|
||||
LGTM state but request a minor tweak that doesn't need further review, e.g., a rebase or small
|
||||
uncontroversial change.
|
||||
|
||||
PRs do not need to be assigned to milestones, unless a milestone release should be held for that
|
||||
PR to land.
|
||||
|
||||
Victor (`vsavkin`) and Tobias (`tbosch`) are owners of the PR queue. Here is a list of [current
|
||||
untriaged PRs](https://github.com/angular/angular/pulls?utf8=%E2%9C%93&q=is%3Aopen+no%3Amilestone+is%3Apr+-label%3A%22pr_action%3A+cleanup%22+-label%3A%22pr_action%3A+merge%22+-label%3A%22pr_action%3A+review%22+-label%3A%22pr_action%3A+discuss%22+-label%3A%22pr_state%3A+blocked%22+-label%3A%22pr_state%3A+WIP%22+).
|
||||
|
||||
# Prioritization of Work
|
||||
|
||||
What should you be working on?
|
||||
|
||||
1. Any PRs that are assigned to you that don't have `pr_state: WIP` or `pr_state: blocked`
|
||||
1. Any issues that are assigned to you in the lowest-numbered Milestone
|
||||
1. Any issues that are assigned to you in any Milestone
|
||||
|
||||
If there are no issues assigned to you in any Milestone, pick an issue, self-assign it, and add
|
||||
it to the most appropriate Milestone based on effort.
|
||||
|
||||
Here are some suggestions for what to work on next:
|
||||
|
||||
* Filter for issues in a component that you are knowledgeable about, and pick something that has a
|
||||
high priority.
|
||||
* Filter for any small effort task that has the special `cust: GT` or `cust:Ionic` tags,
|
||||
and priority > P3.
|
||||
* Add a new task that's really important, add `component`, `priority`, `effort`, `type` and
|
||||
assign it to yourself and the most appropriate milestone.
|
||||
|
||||
# Labels Used in Triage
|
||||
|
||||
## Priority
|
||||
How urgent is this issue? We use priority to determine what should be worked on in each new
|
||||
milestone.
|
||||
|
||||
* `P0: critical` -- drop everything to work on this
|
||||
* `P1: urgent` -- resolve quickly in the current milestone. people are blocked
|
||||
* `P2: required` -- needed for development but not urgent yet. workaround exists, or e.g. new API
|
||||
* `P3: important` -- must complete before Angular 2 is ready for release
|
||||
* `P4: nice to have` -- a good idea, but maybe not until after release
|
||||
|
||||
|
||||
## Effort
|
||||
Rough, non-binding estimate of how much work this issue represents. Please change this assessment
|
||||
for anything you're working on to better reflect reality.
|
||||
|
||||
* `effort: easy` -- straightforward issue that can be resolved in a few hours, e.g. < 1 day of work.
|
||||
* `effort: medium` -- issue that will be a few days of work. Can be completed within a single
|
||||
milestone.
|
||||
* `effort: tough` -- issue that will likely take more than 1 milestone to complete.
|
||||
|
||||
<!-- We don't like these label names as
|
||||
they're not absolute (what is one developer-hour, really?) but decided it wasn't worth arguing
|
||||
over terms. -->
|
||||
|
||||
## Component
|
||||
Which area of Angular knowledge is this issue most closely related to? Helpful when deciding what
|
||||
to work on next.
|
||||
|
||||
* `comp: benchpress` -- benchmarks and performance testing → *tbosch*, *crossj*
|
||||
* `comp: build/dev-productivity` -- build process, e.g. CLI and related tasks → *iminar*, *caitp*
|
||||
* `comp: build/pipeline` -- build pipeline, e.g. ts2dart → *mprobst*, *alexeagle*
|
||||
* `comp: core` -- general core Angular issues, not related to a sub-category (see below) →
|
||||
*mhevery*
|
||||
* `comp: core/animations` -- animations framework → *matsko*
|
||||
* `comp: core/change_detection` -- change detection → *vsavkin*
|
||||
* `comp: core/di` -- dependency injection → *vicb*, *rkirov*
|
||||
* `comp: core/directives` -- directives
|
||||
* `comp: core/forms` -- forms → *vsavkin*
|
||||
* `comp: core/pipes` -- pipes
|
||||
* `comp: core/view` -- runtime processing of the `View`s
|
||||
* `comp: core/view/compiler` -- static analysis of the templates which generate `ProtoView`s.
|
||||
* `comp: core/testbed` -- e2e tests and support for them
|
||||
* `comp: core/webworker` -- core web worker infrastructure
|
||||
* `comp: dart-transformer` -- Dart transforms → *kegluneq*, *jakemac*
|
||||
* `comp: data-access` -- → *jeffbcross*
|
||||
* `comp: docs` -- API docs and doc generation → *naomiblack*, *petebacondarwin*
|
||||
* `comp: material-components` -- Angular Material components built in Angular 2 → *jelbourn*
|
||||
* `comp: router` -- Component Router → *btford*, *igorminar*, *matsko*
|
||||
* `comp: wrenchjs`
|
||||
|
||||
## Type
|
||||
What kind of problem is this?
|
||||
|
||||
* `type RFC / discussion / question`
|
||||
* `type bug`
|
||||
* `type chore`
|
||||
* `type feature`
|
||||
* `type performance`
|
||||
* `type refactor`
|
||||
|
||||
## Special Labels
|
||||
|
||||
### action:design
|
||||
More active discussion is needed before the issue can be worked on further. Typically used for
|
||||
`type: feature` or `type: RFC/discussion/question`
|
||||
|
||||
[See all issues that need discussion](https://github.com/angular/angular/labels/action:%20Design)
|
||||
|
||||
### cla
|
||||
Managed by googlebot. Indicates whether a PR has a CLA on file for its author(s). Only issues with
|
||||
`cla:yes` should be merged into master.
|
||||
|
||||
### cust
|
||||
This is an issue causing user pain for early adopter customers `cust: GT` or `cust: Ionic`.
|
||||
|
||||
### WORKS_AS_INTENDED
|
||||
|
||||
Only used on closed issues, to indicate to the reporter why we closed it.
|
@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "angular2",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"polymer": "dart-lang/polymer_js#0.8.0-preview"
|
||||
"polymer": "Polymer/polymer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
317
browser-providers.conf.js
Normal file
317
browser-providers.conf.js
Normal file
@ -0,0 +1,317 @@
|
||||
// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL) and BrowserStack (BS).
|
||||
// If the target is set to null, then the browser is not run anywhere during CI.
|
||||
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented out in Travis configuration.
|
||||
var CIconfiguration = {
|
||||
'Chrome': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'Firefox': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'ChromeBeta': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'FirefoxBeta': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'ChromeDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
|
||||
'FirefoxDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
|
||||
'IE9': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'IE10': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'IE11': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'Edge': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'Android4.1': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.2': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.3': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.4': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android5': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari7': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'iOS7': { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
|
||||
'iOS8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
// TODO(mlaval): iOS9 deactivated as not reliable, reactivate after https://github.com/angular/angular/issues/5408
|
||||
'iOS9': { unitTest: {target: null, required: false}, e2e: {target: null, required: true}},
|
||||
'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
|
||||
};
|
||||
|
||||
var customLaunchers = {
|
||||
'DartiumWithWebPlatform': {
|
||||
base: 'Dartium',
|
||||
flags: ['--enable-experimental-web-platform-features'] },
|
||||
'ChromeNoSandbox': {
|
||||
base: 'Chrome',
|
||||
flags: ['--no-sandbox'] },
|
||||
'SL_CHROME': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'chrome',
|
||||
version: '46'
|
||||
},
|
||||
'SL_CHROMEBETA': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'chrome',
|
||||
version: 'beta'
|
||||
},
|
||||
'SL_CHROMEDEV': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'chrome',
|
||||
version: 'dev'
|
||||
},
|
||||
'SL_FIREFOX': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'firefox',
|
||||
version: '42'
|
||||
},
|
||||
'SL_FIREFOXBETA': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'firefox',
|
||||
version: 'beta'
|
||||
},
|
||||
'SL_FIREFOXDEV': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'firefox',
|
||||
version: 'dev'
|
||||
},
|
||||
'SL_SAFARI7': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.9',
|
||||
version: '7'
|
||||
},
|
||||
'SL_SAFARI8': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.10',
|
||||
version: '8'
|
||||
},
|
||||
'SL_SAFARI9': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.11',
|
||||
version: '9.0'
|
||||
},
|
||||
'SL_IOS7': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'iphone',
|
||||
platform: 'OS X 10.10',
|
||||
version: '7.1'
|
||||
},
|
||||
'SL_IOS8': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'iphone',
|
||||
platform: 'OS X 10.10',
|
||||
version: '8.4'
|
||||
},
|
||||
'SL_IOS9': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'iphone',
|
||||
platform: 'OS X 10.10',
|
||||
version: '9.1'
|
||||
},
|
||||
'SL_IE9': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 2008',
|
||||
version: '9'
|
||||
},
|
||||
'SL_IE10': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 2012',
|
||||
version: '10'
|
||||
},
|
||||
'SL_IE11': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 8.1',
|
||||
version: '11'
|
||||
},
|
||||
'SL_EDGE': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'microsoftedge',
|
||||
platform: 'Windows 10',
|
||||
version: '20.10240'
|
||||
},
|
||||
'SL_ANDROID4.1': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'android',
|
||||
platform: 'Linux',
|
||||
version: '4.1'
|
||||
},
|
||||
'SL_ANDROID4.2': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'android',
|
||||
platform: 'Linux',
|
||||
version: '4.2'
|
||||
},
|
||||
'SL_ANDROID4.3': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'android',
|
||||
platform: 'Linux',
|
||||
version: '4.3'
|
||||
},
|
||||
'SL_ANDROID4.4': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'android',
|
||||
platform: 'Linux',
|
||||
version: '4.4'
|
||||
},
|
||||
'SL_ANDROID5': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'android',
|
||||
platform: 'Linux',
|
||||
version: '5.1'
|
||||
},
|
||||
|
||||
'BS_CHROME': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'chrome',
|
||||
os: 'OS X',
|
||||
os_version: 'Yosemite'
|
||||
},
|
||||
'BS_FIREFOX': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'firefox',
|
||||
os: 'Windows',
|
||||
os_version: '10'
|
||||
},
|
||||
'BS_SAFARI7': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'safari',
|
||||
os: 'OS X',
|
||||
os_version: 'Mavericks'
|
||||
},
|
||||
'BS_SAFARI8': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'safari',
|
||||
os: 'OS X',
|
||||
os_version: 'Yosemite'
|
||||
},
|
||||
'BS_SAFARI9': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'safari',
|
||||
os: 'OS X',
|
||||
os_version: 'El Capitan'
|
||||
},
|
||||
'BS_IOS7': {
|
||||
base: 'BrowserStack',
|
||||
device: 'iPhone 5S',
|
||||
os: 'ios',
|
||||
os_version: '7.0'
|
||||
},
|
||||
'BS_IOS8': {
|
||||
base: 'BrowserStack',
|
||||
device: 'iPhone 6',
|
||||
os: 'ios',
|
||||
os_version: '8.3'
|
||||
},
|
||||
'BS_IOS9': {
|
||||
base: 'BrowserStack',
|
||||
device: 'iPhone 6S',
|
||||
os: 'ios',
|
||||
os_version: '9.0'
|
||||
},
|
||||
'BS_IE9': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '9.0',
|
||||
os: 'Windows',
|
||||
os_version: '7'
|
||||
},
|
||||
'BS_IE10': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '10.0',
|
||||
os: 'Windows',
|
||||
os_version: '8'
|
||||
},
|
||||
'BS_IE11': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '11.0',
|
||||
os: 'Windows',
|
||||
os_version: '10'
|
||||
},
|
||||
'BS_EDGE': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'edge',
|
||||
os: 'Windows',
|
||||
os_version: '10'
|
||||
},
|
||||
'BS_WINDOWSPHONE' : {
|
||||
base: 'BrowserStack',
|
||||
device: 'Nokia Lumia 930',
|
||||
os: 'winphone',
|
||||
os_version: '8.1'
|
||||
},
|
||||
'BS_ANDROID5': {
|
||||
base: 'BrowserStack',
|
||||
device: 'Google Nexus 5',
|
||||
os: 'android',
|
||||
os_version: '5.0'
|
||||
},
|
||||
'BS_ANDROID4.4': {
|
||||
base: 'BrowserStack',
|
||||
device: 'HTC One M8',
|
||||
os: 'android',
|
||||
os_version: '4.4'
|
||||
},
|
||||
'BS_ANDROID4.3': {
|
||||
base: 'BrowserStack',
|
||||
device: 'Samsung Galaxy S4',
|
||||
os: 'android',
|
||||
os_version: '4.3'
|
||||
},
|
||||
'BS_ANDROID4.2': {
|
||||
base: 'BrowserStack',
|
||||
device: 'Google Nexus 4',
|
||||
os: 'android',
|
||||
os_version: '4.2'
|
||||
},
|
||||
'BS_ANDROID4.1': {
|
||||
base: 'BrowserStack',
|
||||
device: 'Google Nexus 7',
|
||||
os: 'android',
|
||||
os_version: '4.1'
|
||||
}
|
||||
};
|
||||
|
||||
var sauceAliases = {
|
||||
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
|
||||
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
|
||||
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
|
||||
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
|
||||
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
|
||||
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
|
||||
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
|
||||
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
|
||||
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
|
||||
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
|
||||
'CI_OPTIONAL': buildConfiguration('unitTest', 'SL', false)
|
||||
};
|
||||
|
||||
var browserstackAliases = {
|
||||
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
|
||||
'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
|
||||
'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'],
|
||||
'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
|
||||
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
|
||||
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
|
||||
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
|
||||
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
|
||||
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
customLaunchers: customLaunchers,
|
||||
sauceAliases: sauceAliases,
|
||||
browserstackAliases: browserstackAliases
|
||||
}
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');
|
||||
process.env.BROWSER_STACK_ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY.split('').reverse().join('');
|
||||
}
|
||||
|
||||
function buildConfiguration(type, target, required) {
|
||||
return Object.keys(CIconfiguration)
|
||||
.filter((item) => {
|
||||
var conf = CIconfiguration[item][type];
|
||||
return conf.required === required && conf.target === target;
|
||||
})
|
||||
.map((item) => {
|
||||
return target + '_' + item.toUpperCase();
|
||||
});
|
||||
}
|
21
circle.yml
Normal file
21
circle.yml
Normal file
@ -0,0 +1,21 @@
|
||||
machine:
|
||||
node:
|
||||
version: 5.4.1
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- npm install -g npm
|
||||
override:
|
||||
- npm install:
|
||||
environment:
|
||||
# Token for tsd to increase github rate limit
|
||||
# See https://github.com/DefinitelyTyped/tsd#tsdrc
|
||||
# This is not hidden using https://circleci.com/docs/fork-pr-builds#details
|
||||
# because those are not visible for pull requests, and those should also be reliable.
|
||||
# This SSO token belongs to github account angular-github-ratelimit-token which has no access
|
||||
# (password is in Valentine)
|
||||
TSD_GITHUB_TOKEN: ef474500309daea53d5991b3079159a29520a40b
|
||||
|
||||
test:
|
||||
override:
|
||||
- npm run build
|
@ -1,379 +0,0 @@
|
||||
|
||||
.hide { display: none !important; }
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3f51b5;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-bottom: 20px;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: $baseline-grid ($baseline-grid * 2);
|
||||
border-top: 1px solid #ddd;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 2px solid #ddd;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.md-sidenav-inner {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.layout-content,
|
||||
.doc-content {
|
||||
max-width: 864px;
|
||||
margin: auto;
|
||||
}
|
||||
.layout-label {
|
||||
width: 120px;
|
||||
}
|
||||
.layout-content code.highlight {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
background: none;
|
||||
border-width: 0;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
color: #333;
|
||||
font-size: inherit;
|
||||
line-height: 40px;
|
||||
max-height: 40px;
|
||||
opacity: 1;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
padding: 0px 28px;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
-webkit-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
-webkit-transition-property: max-height, background-color, opacity;
|
||||
-moz-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
-moz-transition-property: max-height, background-color, opacity;
|
||||
transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition-property: max-height, background-color, opacity;
|
||||
}
|
||||
.menu-item.ng-hide {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
.menu-item:hover {
|
||||
color: #999;
|
||||
}
|
||||
.menu-item:focus {
|
||||
font-weight: bold;
|
||||
}
|
||||
.menu-item.menu-title {
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
padding-left: 16px;
|
||||
text-align: left;
|
||||
text-transform: uppercase;
|
||||
transition: color 0.35s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
}
|
||||
.menu-item.menu-title:hover,
|
||||
.menu-item.menu-title.active {
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
.app-toolbar .md-toolbar-tools h3 {
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
}
|
||||
|
||||
.demo-container {
|
||||
border-radius: 4px;
|
||||
margin-top: 16px;
|
||||
-webkit-transition: 0.02s padding cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition: 0.02s padding cubic-bezier(0.35, 0, 0.25, 1);
|
||||
position: relative;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.demo-source-tabs {
|
||||
z-index: 1;
|
||||
-webkit-transition: all 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition: all 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
max-height: 448px;
|
||||
min-height: 448px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
md-tabs.demo-source-tabs md-tab,
|
||||
md-tabs.demo-source-tabs .md-header {
|
||||
background-color: #444444 !important;
|
||||
}
|
||||
|
||||
|
||||
md-tabs.demo-source-tabs md-tab-label {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
md-tabs.demo-source-tabs .active md-tab-label {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.demo-source-tabs.ng-hide {
|
||||
max-height: 0px;
|
||||
min-height: 0px;
|
||||
}
|
||||
.demo-source-tabs {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
.demo-content {
|
||||
position: relative;
|
||||
overflow:hidden;
|
||||
min-height: 448px;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -moz-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.small-demo .demo-source-tabs:not(.ng-hide) {
|
||||
min-height: 224px;
|
||||
max-height: 224px;
|
||||
}
|
||||
.small-demo .demo-content {
|
||||
min-height: 128px;
|
||||
}
|
||||
.demo-content > * {
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
-moz-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.demo-content > div[layout-fill] {
|
||||
min-height: 448px;
|
||||
}
|
||||
.small-demo .demo-content > div[layout-fill] {
|
||||
min-height: 224px;
|
||||
}
|
||||
.small-demo .demo-toolbar,
|
||||
.small-demo .md-toolbar-tools {
|
||||
min-height: 48px;
|
||||
max-height: 48px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.show-source md-toolbar.demo-toolbar {
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.36);
|
||||
}
|
||||
.demo-toolbar .md-button {
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
md-toolbar.demo-toolbar,
|
||||
.demo-source-tabs md-tab,
|
||||
.demo-source-tabs .tabs-header {
|
||||
background: #E0E0E0 !important;
|
||||
color: #616161;
|
||||
}
|
||||
md-toolbar.demo-toolbar md-tab-label {
|
||||
color: #99E4EE
|
||||
}
|
||||
md-toolbar.demo-toolbar .md-button:hover,
|
||||
md-toolbar.demo-toolbar .md-button:focus,
|
||||
md-toolbar.demo-toolbar .md-button.active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
md-toolbar.demo-toolbar .md-button {
|
||||
-webkit-transition: all 0.3s linear;
|
||||
-moz-transition: all 0.3s linear;
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
.demo-source-container {
|
||||
display: block;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #f6f6f6;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.demo-source-content {
|
||||
height: 400px;
|
||||
}
|
||||
.demo-source-content,
|
||||
.demo-source-content pre,
|
||||
.demo-source-content code {
|
||||
background: #f6f6f6;
|
||||
font-family: monospace;
|
||||
}
|
||||
.demo-source-content pre {
|
||||
max-width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.show-source div[demo-include] {
|
||||
border-top: #ddd solid 2px;
|
||||
}
|
||||
|
||||
|
||||
.menu-separator-icon {
|
||||
margin: 0;
|
||||
}
|
||||
.menu-module-name {
|
||||
opacity: 0.6;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/************
|
||||
* DOCS
|
||||
************/
|
||||
.api-options-bar .md-button {
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
.api-options-bar .md-button:hover,
|
||||
.api-options-bar .md-button:focus {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.api-options-bar.with-icon md-icon {
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
left: 2px;
|
||||
}
|
||||
.api-options-bar.with-icon .md-button span {
|
||||
margin-left: 22px;
|
||||
}
|
||||
|
||||
.api-params-item {
|
||||
min-height: 72px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.api-params-label {
|
||||
margin-right: 8px;
|
||||
text-align: center;
|
||||
margin-top: 14px;
|
||||
-webkit-align-self: flex-start;
|
||||
-moz-align-self: flex-start;
|
||||
-ms-flex-item-align: start;
|
||||
align-self: flex-start;
|
||||
}
|
||||
.api-params-title {
|
||||
color: #888;
|
||||
}
|
||||
code.api-type {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
}
|
||||
ul li {
|
||||
margin-top: 3px;
|
||||
list-style-position: inside;
|
||||
}
|
||||
ul li:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.layout-title {
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-params-content ul {
|
||||
padding-left: 4px;
|
||||
}
|
||||
ul.methods > li {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
ul.methods .method-function-syntax {
|
||||
font-weight: normal;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
}
|
||||
ul.methods li h3 {
|
||||
/* border-bottom: 1px solid #eee; */
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
ul.methods > li {
|
||||
padding-left: 0;
|
||||
border-left: none;
|
||||
list-style: default;
|
||||
}
|
||||
ul.methods .method-function-syntax {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.version {
|
||||
padding-left: 10px;
|
||||
text-decoration: underline;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.demo-source-container pre,
|
||||
.demo-source-container code {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
md-content.demo-source-container > hljs > pre > code.highlight {
|
||||
position : absolute;
|
||||
top : 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
|
||||
.extraPad {
|
||||
padding-left:32px !important;
|
||||
padding-right:32px !important;
|
||||
}
|
||||
|
||||
|
||||
.member .name {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
font-family: monospace;
|
||||
font-size: 1.17em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.left-nav {
|
||||
min-width: 300px;
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
/* GitHub Theme */
|
||||
.prettyprint {
|
||||
background: white;
|
||||
font-family: Menlo, 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Consolas, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.lang-text * {
|
||||
color: #333333!important;
|
||||
}
|
||||
|
||||
.pln {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
@media screen {
|
||||
.str {
|
||||
color: #dd1144;
|
||||
}
|
||||
|
||||
.kwd {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.com {
|
||||
color: #999988;
|
||||
}
|
||||
|
||||
.typ {
|
||||
color: #445588;
|
||||
}
|
||||
|
||||
.lit {
|
||||
color: #445588;
|
||||
}
|
||||
|
||||
.pun {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.opn {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.clo {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: navy;
|
||||
}
|
||||
|
||||
.atn {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
.atv {
|
||||
color: #dd1144;
|
||||
}
|
||||
|
||||
.dec {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.var {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
.fun {
|
||||
color: #990000;
|
||||
}
|
||||
}
|
||||
@media print, projection {
|
||||
.str {
|
||||
color: #006600;
|
||||
}
|
||||
|
||||
.kwd {
|
||||
color: #006;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.com {
|
||||
color: #600;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.typ {
|
||||
color: #404;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.lit {
|
||||
color: #004444;
|
||||
}
|
||||
|
||||
.pun, .opn, .clo {
|
||||
color: #444400;
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: #006;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.atn {
|
||||
color: #440044;
|
||||
}
|
||||
|
||||
.atv {
|
||||
color: #006600;
|
||||
}
|
||||
}
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* IE indents via margin-left */
|
||||
li.L0,
|
||||
li.L1,
|
||||
li.L2,
|
||||
li.L3,
|
||||
li.L4,
|
||||
li.L5,
|
||||
li.L6,
|
||||
li.L7,
|
||||
li.L8,
|
||||
li.L9 {
|
||||
/* */
|
||||
}
|
||||
|
||||
/* Alternate shading for lines */
|
||||
li.L1,
|
||||
li.L3,
|
||||
li.L5,
|
||||
li.L7,
|
||||
li.L9 {
|
||||
/* */
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Angular 2 Docs</title>
|
||||
<base href="/">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/lib/angular-material/angular-material.css">
|
||||
<link rel="stylesheet" type="text/css" href="/css/prettify-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="/css/app.css">
|
||||
|
||||
<script src="/lib/hammerjs/hammer.js"></script>
|
||||
<script src="/lib/google-code-prettify/src/prettify.js"></script>
|
||||
<script src="/lib/google-code-prettify/src/lang-css.js"></script>
|
||||
<script src="/lib/angular/angular.js"></script>
|
||||
<script src="/lib/angular-animate/angular-animate.js"></script>
|
||||
<script src="/lib/angular-aria/angular-aria.js"></script>
|
||||
<script src="/lib/angular-material/angular-material.js"></script>
|
||||
<script src="/js/navigation-modules.js"></script>
|
||||
<script src="/js/navigation-guides.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
<script src="/js/code.js"></script>
|
||||
</head>
|
||||
<body ng-app="app" ng-controller="NavController as nav" layout="column">
|
||||
|
||||
<md-toolbar md-scroll-shrink>
|
||||
<h1 class="md-toolbar-tools">Angular V2</h1>
|
||||
</md-toolbar>
|
||||
|
||||
<section layout="row">
|
||||
|
||||
<md-content class="left-nav">
|
||||
<h2>Navigation</h2>
|
||||
<section ng-repeat="area in nav.areas">
|
||||
<h3>{{ area.name }}</h3>
|
||||
<md-list>
|
||||
<md-item ng-repeat="section in area.sections">
|
||||
<h3><a href="{{section.path}}">{{section.name}}</a></h3>
|
||||
<ul>
|
||||
<li ng-repeat="page in section.pages">
|
||||
<a href="{{page.path}}">{{ page.name }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</md-item>
|
||||
</md-list>
|
||||
</section>
|
||||
</md-content>
|
||||
|
||||
|
||||
<md-content class="md-padding">
|
||||
<ng-include autoscroll src="nav.currentPage.partial"></ng-include>
|
||||
</md-content>
|
||||
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
@ -1,47 +0,0 @@
|
||||
angular.module('app', ['ngMaterial', 'navigation-modules', 'navigation-guides', 'code'])
|
||||
|
||||
.config(function($locationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
})
|
||||
|
||||
.controller('NavController', ['$scope', '$location', 'MODULES', 'GUIDES',
|
||||
function($scope, $location, MODULES, GUIDES) {
|
||||
var that = this;
|
||||
|
||||
this.areas = [
|
||||
{ name: 'Guides', sections: [ { pages: GUIDES.pages } ] },
|
||||
{ name: 'Modules', sections: MODULES.sections }
|
||||
];
|
||||
|
||||
this.updateCurrentPage = function(path) {
|
||||
path = path.replace(/^\//, '');
|
||||
console.log('path', path);
|
||||
this.currentPage = null;
|
||||
|
||||
this.areas.forEach(function(area) {
|
||||
area.sections.forEach(function(section) {
|
||||
|
||||
// Short-circuit out if the page has been found
|
||||
if ( that.currentPage ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (section.path === path) {
|
||||
console.log('found!');
|
||||
that.currentPage = section;
|
||||
} else {
|
||||
section.pages.forEach(function(page) {
|
||||
if (page.path === path) {
|
||||
that.currentPage = page;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$watch(
|
||||
function getLocationPath() { return $location.path(); },
|
||||
function handleLocationPathChange(path) { that.updateCurrentPage(path); }
|
||||
);
|
||||
}]);
|
@ -1,15 +0,0 @@
|
||||
angular.module('code', [])
|
||||
|
||||
.directive('code', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
terminal: true,
|
||||
compile: function(element) {
|
||||
var linenums = element.hasClass('linenum');
|
||||
var match = /lang-(\S+)/.exec(element[0].className);
|
||||
var lang = match && match[1];
|
||||
var html = element.html();
|
||||
element.html(window.prettyPrintOne(html, lang, linenums));
|
||||
}
|
||||
};
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "angular-docs",
|
||||
"main": "index.js",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/angular/angular",
|
||||
"authors": [],
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"angular-material": "~0.6.0",
|
||||
"google-code-prettify": "~1.0.3"
|
||||
}
|
||||
}
|
@ -1,160 +0,0 @@
|
||||
require('../../tools/transpiler/index.js').init();
|
||||
|
||||
var Package = require('dgeni').Package;
|
||||
var jsdocPackage = require('dgeni-packages/jsdoc');
|
||||
var nunjucksPackage = require('dgeni-packages/nunjucks');
|
||||
var path = require('canonical-path');
|
||||
|
||||
var PARTIAL_PATH = 'partials';
|
||||
var MODULES_DOCS_PATH = PARTIAL_PATH + '/modules';
|
||||
var GUIDES_PATH = PARTIAL_PATH + '/guides';
|
||||
|
||||
// Define the dgeni package for generating the docs
|
||||
module.exports = new Package('angular', [jsdocPackage, nunjucksPackage])
|
||||
|
||||
// Register the services and file readers
|
||||
.factory(require('./services/modules'))
|
||||
.factory(require('./services/atParser'))
|
||||
.factory(require('./services/getJSDocComment'))
|
||||
.factory(require('./services/SourceFile'))
|
||||
.factory(require('./services/TraceurParser'))
|
||||
.factory(require('./services/traceurOptions'))
|
||||
.factory(require('./services/ParseTreeVisitor'))
|
||||
.factory(require('./services/AttachCommentTreeVisitor'))
|
||||
.factory(require('./services/ExportTreeVisitor'))
|
||||
|
||||
.factory(require('./readers/atScript'))
|
||||
.factory(require('./readers/ngdoc'))
|
||||
|
||||
.factory('EXPORT_DOC_TYPES', function() {
|
||||
return [
|
||||
'class',
|
||||
'function',
|
||||
'var',
|
||||
'const'
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
// Register the processors
|
||||
.processor(require('./processors/captureModuleExports'))
|
||||
.processor(require('./processors/captureClassMembers'))
|
||||
.processor(require('./processors/captureModuleDocs'))
|
||||
.processor(require('./processors/attachModuleDocs'))
|
||||
.processor(require('./processors/cloneExportedFromDocs'))
|
||||
.processor(require('./processors/generateNavigationDoc'))
|
||||
.processor(require('./processors/extractTitleFromGuides'))
|
||||
.processor(require('./processors/createOverviewDump'))
|
||||
|
||||
|
||||
// Configure the log service
|
||||
.config(function(log) {
|
||||
log.level = 'warning';
|
||||
})
|
||||
|
||||
|
||||
// Configure file reading
|
||||
.config(function(readFilesProcessor, atScriptFileReader, ngdocFileReader) {
|
||||
readFilesProcessor.fileReaders = [atScriptFileReader, ngdocFileReader];
|
||||
readFilesProcessor.basePath = path.resolve(__dirname, '../..');
|
||||
readFilesProcessor.sourceFiles = [
|
||||
{ include: 'modules/*/*.js', basePath: 'modules' },
|
||||
{ include: 'modules/*/src/**/*.js', basePath: 'modules' },
|
||||
{ include: 'modules/*/*.es6', basePath: 'modules' },
|
||||
{ include: 'modules/*/src/**/*.es6', basePath: 'modules' },
|
||||
{ include: 'modules/*/docs/**/*.md', basePath: 'modules' },
|
||||
{ include: 'docs/content/**/*.md', basePath: 'docs/content' }
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
.config(function(parseTagsProcessor, getInjectables) {
|
||||
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/public'));
|
||||
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/private'));
|
||||
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/exportedAs'));
|
||||
})
|
||||
|
||||
|
||||
// Configure file writing
|
||||
.config(function(writeFilesProcessor) {
|
||||
writeFilesProcessor.outputFolder = 'dist/docs';
|
||||
})
|
||||
|
||||
|
||||
// Configure rendering
|
||||
.config(function(templateFinder, templateEngine) {
|
||||
|
||||
// Nunjucks and Angular conflict in their template bindings so change Nunjucks
|
||||
templateEngine.config.tags = {
|
||||
variableStart: '{$',
|
||||
variableEnd: '$}'
|
||||
};
|
||||
|
||||
templateFinder.templateFolders
|
||||
.unshift(path.resolve(__dirname, 'templates'));
|
||||
|
||||
templateFinder.templatePatterns = [
|
||||
'${ doc.template }',
|
||||
'${ doc.id }.${ doc.docType }.template.html',
|
||||
'${ doc.id }.template.html',
|
||||
'${ doc.docType }.template.html',
|
||||
'common.template.html'
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
// Configure ids and paths
|
||||
.config(function(computeIdsProcessor, computePathsProcessor, EXPORT_DOC_TYPES) {
|
||||
|
||||
computeIdsProcessor.idTemplates.push({
|
||||
docTypes: EXPORT_DOC_TYPES,
|
||||
idTemplate: '${moduleDoc.id}.${name}',
|
||||
getAliases: function(doc) { return [doc.id, doc.name]; }
|
||||
});
|
||||
|
||||
computeIdsProcessor.idTemplates.push({
|
||||
docTypes: ['member'],
|
||||
idTemplate: '${classDoc.id}.${name}',
|
||||
getAliases: function(doc) { return [doc.id]; }
|
||||
});
|
||||
|
||||
computeIdsProcessor.idTemplates.push({
|
||||
docTypes: ['guide'],
|
||||
getId: function(doc) {
|
||||
return doc.fileInfo.relativePath
|
||||
// path should be relative to `modules` folder
|
||||
.replace(/.*\/?modules\//, '')
|
||||
// path should not include `/docs/`
|
||||
.replace(/\/docs\//, '/')
|
||||
// path should not have a suffix
|
||||
.replace(/\.\w*$/, '');
|
||||
},
|
||||
getAliases: function(doc) { return [doc.id]; }
|
||||
});
|
||||
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['module'],
|
||||
pathTemplate: '${id}',
|
||||
outputPathTemplate: MODULES_DOCS_PATH + '/${id}/index.html'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: EXPORT_DOC_TYPES,
|
||||
pathTemplate: '${moduleDoc.path}/${name}',
|
||||
outputPathTemplate: MODULES_DOCS_PATH + '/${path}/index.html'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['member'],
|
||||
pathTemplate: '${classDoc.path}/${name}',
|
||||
getOutputPath: function() {} // These docs are not written to their own file, instead they are part of their class doc
|
||||
});
|
||||
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['guide'],
|
||||
pathTemplate: '${id}',
|
||||
outputPathTemplate: GUIDES_PATH + '/${id}.html'
|
||||
});
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
module.exports = function mockPackage() {
|
||||
|
||||
return new Package('mockPackage', [require('../')])
|
||||
|
||||
// provide a mock log service
|
||||
.factory('log', function() { return require('dgeni/lib/mocks/log')(false); });
|
||||
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function attachModuleDocs(log) {
|
||||
|
||||
return {
|
||||
$runAfter: ['tags-extracted'],
|
||||
$runBefore: ['computing-ids'],
|
||||
$process: function(docs) {
|
||||
return _.filter(docs, function(doc) {
|
||||
if (doc.docType !== 'moduleDoc') {
|
||||
return true;
|
||||
}
|
||||
if (doc.module || doc.module === '') {
|
||||
doc.moduleDoc.description = doc.description;
|
||||
doc.moduleDoc.public = doc.public;
|
||||
log.debug('attached', doc.moduleDoc.id, doc.moduleDoc.description);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
@ -1,70 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function captureClassMembers(log, getJSDocComment) {
|
||||
|
||||
return {
|
||||
$runAfter: ['captureModuleExports'],
|
||||
$runBefore: ['parsing-tags'],
|
||||
ignorePrivateMembers: false,
|
||||
$process: function(docs) {
|
||||
var memberDocs = [];
|
||||
var ignorePrivateMembers = this.ignorePrivateMembers;
|
||||
_.forEach(docs, function(classDoc) {
|
||||
if ( classDoc.docType === 'class' ) {
|
||||
|
||||
classDoc.members = [];
|
||||
|
||||
// Create a new doc for each member of the class
|
||||
_.forEach(classDoc.elements, function(memberDoc) {
|
||||
|
||||
var memberName = memberDoc.name.location.toString();
|
||||
|
||||
if (ignorePrivateMembers && memberName.charAt(0) === '_') return;
|
||||
|
||||
memberDocs.push(memberDoc);
|
||||
|
||||
memberDoc.docType = 'member';
|
||||
memberDoc.classDoc = classDoc;
|
||||
memberDoc.name = memberName;
|
||||
if (memberDoc.parameterList) {
|
||||
memberDoc.params = memberDoc.parameterList.parameters.map(function(param) {
|
||||
return param.location.toString();
|
||||
});
|
||||
}
|
||||
|
||||
if (memberDoc.commentBefore ) {
|
||||
// If this export has a comment, remove it from the list of
|
||||
// comments collected in the module
|
||||
var index = classDoc.moduleDoc.comments.indexOf(memberDoc.commentBefore);
|
||||
if ( index !== -1 ) {
|
||||
classDoc.moduleDoc.comments.splice(index, 1);
|
||||
}
|
||||
|
||||
_.assign(memberDoc, getJSDocComment(memberDoc.commentBefore));
|
||||
}
|
||||
|
||||
// Constuctor is a special case member
|
||||
if (memberName === 'constructor') {
|
||||
classDoc.constructorDoc = memberDoc;
|
||||
} else {
|
||||
insertSorted(classDoc.members, memberDoc, 'name');
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return docs.concat(memberDocs);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function insertSorted(collection, item, property) {
|
||||
var index = collection.length;
|
||||
while(index>0) {
|
||||
if(collection[index-1][property] < item[property]) break;
|
||||
index -= 1;
|
||||
}
|
||||
collection.splice(index, 0, item);
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function captureModuleDocs(log, getJSDocComment) {
|
||||
|
||||
return {
|
||||
$runAfter: ['captureClassMembers'],
|
||||
$runBefore: ['parsing-tags'],
|
||||
$process: function(docs) {
|
||||
// Generate docs for each module's file's comments not already captured
|
||||
_.forEach(docs, function(moduleDoc) {
|
||||
|
||||
if ( moduleDoc.docType !== 'module' ) return;
|
||||
|
||||
moduleDoc.extraComments = [];
|
||||
_.forEach(moduleDoc.comments, function(comment) {
|
||||
var jsDocComment = getJSDocComment(comment);
|
||||
if (jsDocComment) {
|
||||
jsDocComment.docType = 'moduleDoc';
|
||||
jsDocComment.moduleDoc = moduleDoc;
|
||||
moduleDoc.extraComments.push(jsDocComment);
|
||||
docs.push(jsDocComment);
|
||||
// console.log('found', jsDocComment.content);
|
||||
}
|
||||
});
|
||||
if ( moduleDoc.extraComments.length > 0 ) {
|
||||
// console.log(moduleDoc.extraComments.length);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function captureModuleExports(log, ExportTreeVisitor, getJSDocComment) {
|
||||
|
||||
return {
|
||||
$runAfter: ['files-read'],
|
||||
$runBefore: ['parsing-tags'],
|
||||
$process: function(docs) {
|
||||
var extraDocs = [];
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'module' ) {
|
||||
|
||||
log.debug('processing', doc.moduleTree.moduleName);
|
||||
|
||||
doc.exports = [];
|
||||
|
||||
if ( doc.moduleTree.visit ) {
|
||||
var visitor = new ExportTreeVisitor();
|
||||
visitor.visit(doc.moduleTree);
|
||||
|
||||
_.forEach(visitor.exports, function(exportDoc) {
|
||||
|
||||
doc.exports.push(exportDoc);
|
||||
extraDocs.push(exportDoc);
|
||||
exportDoc.moduleDoc = doc;
|
||||
|
||||
if (exportDoc.comment) {
|
||||
// If this export has a comment, remove it from the list of
|
||||
// comments collected in the module
|
||||
var index = doc.comments.indexOf(exportDoc.comment);
|
||||
if ( index !== -1 ) {
|
||||
doc.comments.splice(index, 1);
|
||||
}
|
||||
|
||||
_.assign(exportDoc, getJSDocComment(exportDoc.comment));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return docs.concat(extraDocs);
|
||||
}
|
||||
};
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function cloneExportedFromDocs(modules, EXPORT_DOC_TYPES) {
|
||||
return {
|
||||
$runAfter: ['tags-parsed', 'attachModuleDocs'],
|
||||
$runBefore: ['computing-ids'],
|
||||
$process: function(docs) {
|
||||
|
||||
var extraPublicDocs = [];
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
|
||||
if (EXPORT_DOC_TYPES.indexOf(doc.docType) === -1 || !doc.exportedAs) return;
|
||||
|
||||
_.forEach(doc.exportedAs, function(exportedAs) {
|
||||
var exportedAsModule = modules[exportedAs];
|
||||
|
||||
if (!exportedAsModule) {
|
||||
throw new Error('Missing module definition: "' + doc.exportedAs + '"\n' +
|
||||
'Referenced in "@exportedAs" tag on class: "' + doc.moduleDoc.id + '/' + doc.name + '"');
|
||||
} else {
|
||||
|
||||
if(exportedAsModule !== doc.moduleDoc) {
|
||||
// Add a clone of export to its "exportedAs" module
|
||||
var clonedDoc = _.clone(doc);
|
||||
clonedDoc.moduleDoc = exportedAsModule;
|
||||
exportedAsModule.exports.push(clonedDoc);
|
||||
extraPublicDocs.push(clonedDoc);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
docs = docs.concat(extraPublicDocs);
|
||||
|
||||
return docs;
|
||||
}
|
||||
};
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function createOverviewDump() {
|
||||
|
||||
return {
|
||||
$runAfter: ['captureModuleExports', 'captureClassMembers'],
|
||||
$runBefore: ['docs-processed'],
|
||||
$process: function(docs) {
|
||||
var overviewDoc = {
|
||||
id: 'overview-dump',
|
||||
aliases: ['overview-dump'],
|
||||
path: 'overview-dump',
|
||||
outputPath: 'overview-dump.html',
|
||||
modules: []
|
||||
};
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'module' ) {
|
||||
overviewDoc.modules.push(doc);
|
||||
}
|
||||
});
|
||||
docs.push(overviewDoc);
|
||||
}
|
||||
};
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function extractTitleFromGuides() {
|
||||
|
||||
return {
|
||||
$runAfter: ['processing-docs'],
|
||||
$runBefore: ['docs-processed'],
|
||||
$process: function(docs) {
|
||||
_(docs).forEach(function(doc) {
|
||||
if (doc.docType === 'guide') {
|
||||
doc.name = doc.name || getNameFromHeading(doc.description);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function getNameFromHeading(text) {
|
||||
var match = /^\s*#\s*(.*)/.exec(text);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function generateNavigationDoc() {
|
||||
|
||||
return {
|
||||
$runAfter: ['docs-processed'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
$process: function(docs) {
|
||||
var modulesDoc = {
|
||||
value: { sections: [] },
|
||||
moduleName: 'navigation-modules',
|
||||
serviceName: 'MODULES',
|
||||
template: 'data-module.template.js',
|
||||
outputPath: 'js/navigation-modules.js'
|
||||
};
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'module' ) {
|
||||
var moduleNavItem = {
|
||||
path: doc.path,
|
||||
partial: doc.outputPath,
|
||||
name: doc.id,
|
||||
type: 'module',
|
||||
pages: []
|
||||
};
|
||||
|
||||
modulesDoc.value.sections.push(moduleNavItem);
|
||||
|
||||
_.forEach(doc.exports, function(exportDoc) {
|
||||
if (!exportDoc.private) {
|
||||
var exportNavItem = {
|
||||
path: exportDoc.path,
|
||||
partial: exportDoc.outputPath,
|
||||
name: exportDoc.name,
|
||||
type: exportDoc.docType
|
||||
};
|
||||
moduleNavItem.pages.push(exportNavItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
docs.push(modulesDoc);
|
||||
|
||||
|
||||
var guidesDoc = {
|
||||
value: { pages: [] },
|
||||
moduleName: 'navigation-guides',
|
||||
serviceName: 'GUIDES',
|
||||
template: 'data-module.template.js',
|
||||
outputPath: 'js/navigation-guides.js'
|
||||
};
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'guide' ) {
|
||||
var guideDoc = {
|
||||
path: doc.path,
|
||||
partial: doc.outputPath,
|
||||
name: doc.name,
|
||||
type: 'guide'
|
||||
};
|
||||
guidesDoc.value.pages.push(guideDoc);
|
||||
}
|
||||
});
|
||||
docs.push(guidesDoc);
|
||||
}
|
||||
};
|
||||
};
|
@ -1,32 +0,0 @@
|
||||
var path = require('canonical-path');
|
||||
|
||||
|
||||
/**
|
||||
* @dgService atScriptFileReader
|
||||
* @description
|
||||
* This file reader will create a simple doc for each
|
||||
* file including a code AST of the AtScript in the file.
|
||||
*/
|
||||
module.exports = function atScriptFileReader(log, atParser, modules) {
|
||||
var reader = {
|
||||
name: 'atScriptFileReader',
|
||||
defaultPattern: /\.js|\.es6$/,
|
||||
getDocs: function(fileInfo) {
|
||||
|
||||
var moduleDoc = atParser.parseModule(fileInfo);
|
||||
moduleDoc.docType = 'module';
|
||||
moduleDoc.id = moduleDoc.moduleTree.moduleName;
|
||||
moduleDoc.aliases = [moduleDoc.id];
|
||||
|
||||
modules[moduleDoc.id] = moduleDoc;
|
||||
|
||||
// Readers return a collection of docs read from the file
|
||||
// but in this read there is only one document (module) to return
|
||||
return [moduleDoc];
|
||||
}
|
||||
};
|
||||
|
||||
return reader;
|
||||
|
||||
|
||||
};
|
@ -1,55 +0,0 @@
|
||||
var mockPackage = require('../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
|
||||
describe('atScript file reader', function() {
|
||||
|
||||
var dgeni, injector, reader;
|
||||
|
||||
var fileContent =
|
||||
'import {CONST} from "facade/lang";\n' +
|
||||
'\n' +
|
||||
'/**\n' +
|
||||
'* A parameter annotation that creates a synchronous eager dependency.\n' +
|
||||
'*\n' +
|
||||
'* class AComponent {\n' +
|
||||
'* constructor(@Inject("aServiceToken") aService) {}\n' +
|
||||
'* }\n' +
|
||||
'*\n' +
|
||||
'*/\n' +
|
||||
'export class Inject {\n' +
|
||||
'token;\n' +
|
||||
'@CONST()\n' +
|
||||
'constructor(token) {\n' +
|
||||
'this.token = token;\n' +
|
||||
'}\n' +
|
||||
'}';
|
||||
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
reader = injector.get('atScriptFileReader');
|
||||
});
|
||||
|
||||
|
||||
it('should provide a default pattern', function() {
|
||||
expect(reader.defaultPattern).toEqual(/\.js|\.es6$/);
|
||||
});
|
||||
|
||||
|
||||
it('should parse the file using the atParser and return a single doc', function() {
|
||||
|
||||
var atParser = injector.get('atParser');
|
||||
spyOn(atParser, 'parseModule').and.callThrough();
|
||||
|
||||
var docs = reader.getDocs({
|
||||
content: fileContent,
|
||||
relativePath: 'di/src/annotations.js'
|
||||
});
|
||||
|
||||
expect(atParser.parseModule).toHaveBeenCalled();
|
||||
expect(docs.length).toEqual(1);
|
||||
expect(docs[0].docType).toEqual('module');
|
||||
});
|
||||
|
||||
});
|
@ -1,32 +0,0 @@
|
||||
var path = require('canonical-path');
|
||||
|
||||
/**
|
||||
* @dgService ngdocFileReader
|
||||
* @description
|
||||
* This file reader will pull the contents from a text file (by default .ngdoc)
|
||||
*
|
||||
* The doc will initially have the form:
|
||||
* ```
|
||||
* {
|
||||
* content: 'the content of the file',
|
||||
* startingLine: 1
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
module.exports = function ngdocFileReader() {
|
||||
var reader = {
|
||||
name: 'ngdocFileReader',
|
||||
defaultPattern: /\.md$/,
|
||||
getDocs: function(fileInfo) {
|
||||
|
||||
// We return a single element array because ngdoc files only contain one document
|
||||
return [{
|
||||
docType: 'guide',
|
||||
content: fileInfo.content,
|
||||
startingLine: 1
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
return reader;
|
||||
};
|
@ -1,45 +0,0 @@
|
||||
var ngdocFileReaderFactory = require('./ngdoc');
|
||||
var path = require('canonical-path');
|
||||
|
||||
describe('ngdocFileReader', function() {
|
||||
|
||||
var fileReader;
|
||||
|
||||
var createFileInfo = function(file, content, basePath) {
|
||||
return {
|
||||
fileReader: fileReader.name,
|
||||
filePath: file,
|
||||
baseName: path.basename(file, path.extname(file)),
|
||||
extension: path.extname(file).replace(/^\./, ''),
|
||||
basePath: basePath,
|
||||
relativePath: path.relative(basePath, file),
|
||||
content: content
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
beforeEach(function() {
|
||||
fileReader = ngdocFileReaderFactory();
|
||||
});
|
||||
|
||||
|
||||
describe('defaultPattern', function() {
|
||||
it('should match .md files', function() {
|
||||
expect(fileReader.defaultPattern.test('abc.md')).toBeTruthy();
|
||||
expect(fileReader.defaultPattern.test('abc.js')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('getDocs', function() {
|
||||
it('should return an object containing info about the file and its contents', function() {
|
||||
var fileInfo = createFileInfo('project/path/modules/someModule/foo/docs/subfolder/bar.ngdoc', 'A load of content', 'project/path');
|
||||
expect(fileReader.getDocs(fileInfo)).toEqual([{
|
||||
docType: 'guide',
|
||||
content: 'A load of content',
|
||||
startingLine: 1
|
||||
}]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,54 +0,0 @@
|
||||
module.exports = function AttachCommentTreeVisitor(ParseTreeVisitor, log) {
|
||||
|
||||
function AttachCommentTreeVisitorImpl() {
|
||||
ParseTreeVisitor.call(this);
|
||||
}
|
||||
|
||||
AttachCommentTreeVisitorImpl.prototype = {
|
||||
|
||||
__proto__: ParseTreeVisitor.prototype,
|
||||
|
||||
|
||||
visit: function(tree, comments) {
|
||||
this.comments = comments;
|
||||
this.index = 0;
|
||||
this.currentComment = this.comments[this.index];
|
||||
|
||||
if (this.currentComment) log.silly('comment: ' +
|
||||
this.currentComment.range.start.line + ' - ' +
|
||||
this.currentComment.range.end.line + ' : ' +
|
||||
this.currentComment.range.toString());
|
||||
|
||||
ParseTreeVisitor.prototype.visit.call(this, tree);
|
||||
},
|
||||
|
||||
// Really we ought to subclass ParseTreeVisitor but this is fiddly in ES5 so
|
||||
// it is easier to simply override the prototype's method on the instance
|
||||
visitAny: function(tree) {
|
||||
if (tree && tree.location && tree.location.start && this.currentComment &&
|
||||
this.currentComment.range.end.offset < tree.location.start.offset) {
|
||||
log.silly('tree: ' + tree.constructor.name + ' - ' + tree.location.start.line);
|
||||
while (this.currentComment &&
|
||||
this.currentComment.range.end.offset < tree.location.start.offset) {
|
||||
var commentText = this.currentComment.range.toString();
|
||||
|
||||
// Only store the comment if it is JSDOC style (e.g. /** some comment */)
|
||||
if (/^\/\*\*([\w\W]*)\*\/$/.test(commentText)) {
|
||||
log.info('comment: ' + this.currentComment.range.start.line + ' - ' +
|
||||
this.currentComment.range.end.line + ' : ' +
|
||||
commentText);
|
||||
|
||||
tree.commentBefore = this.currentComment;
|
||||
this.currentComment.treeAfter = tree;
|
||||
}
|
||||
|
||||
this.index++;
|
||||
this.currentComment = this.comments[this.index];
|
||||
}
|
||||
}
|
||||
return ParseTreeVisitor.prototype.visitAny.call(this, tree);
|
||||
}
|
||||
};
|
||||
|
||||
return AttachCommentTreeVisitorImpl;
|
||||
};
|
@ -1,105 +0,0 @@
|
||||
module.exports = function ExportTreeVisitor(ParseTreeVisitor, log) {
|
||||
|
||||
function ExportTreeVisitorImpl() {
|
||||
ParseTreeVisitor.call(this);
|
||||
}
|
||||
ExportTreeVisitorImpl.prototype = {
|
||||
|
||||
__proto__: ParseTreeVisitor.prototype,
|
||||
|
||||
visitExportDeclaration: function(tree) {
|
||||
// We are entering an export declaration - create an object to track it
|
||||
this.currentExport = {
|
||||
comment: tree.commentBefore,
|
||||
location: tree.location
|
||||
};
|
||||
log.silly('enter', tree.type, tree.commentBefore ? 'has comment' : '');
|
||||
ParseTreeVisitor.prototype.visitExportDeclaration.call(this, tree);
|
||||
log.silly('exit', this.currentExport);
|
||||
|
||||
if(this.currentExport) {
|
||||
// We are exiting the export declaration - store the export object
|
||||
this.exports.push(this.currentExport);
|
||||
}
|
||||
this.currentExport = null;
|
||||
},
|
||||
|
||||
visitVariableDeclaration: function(tree) {
|
||||
if ( this.currentExport ) {
|
||||
this.updateExport(tree);
|
||||
this.currentExport.docType = 'var';
|
||||
this.currentExport.name = tree.lvalue.identifierToken.value;
|
||||
this.currentExport.variableDeclaration = tree;
|
||||
}
|
||||
},
|
||||
|
||||
visitFunctionDeclaration: function(tree) {
|
||||
if ( this.currentExport ) {
|
||||
this.updateExport(tree);
|
||||
this.currentExport.name = tree.name.identifierToken.value;
|
||||
this.currentExport.functionKind = tree.functionKind;
|
||||
this.currentExport.parameters = tree.parameterList.parameters.map(function(param) {
|
||||
return param.location.toString();
|
||||
});
|
||||
this.currentExport.typeAnnotation = tree.typeAnnotation;
|
||||
this.currentExport.annotations = tree.annotations;
|
||||
this.currentExport.docType = 'function';
|
||||
|
||||
log.silly(tree.type, tree.commentBefore ? 'has comment' : '');
|
||||
}
|
||||
},
|
||||
visitClassDeclaration: function(tree) {
|
||||
if ( this.currentExport ) {
|
||||
this.updateExport(tree);
|
||||
this.currentExport.name = tree.name.identifierToken.value;
|
||||
this.currentExport.superClass = tree.superClass;
|
||||
this.currentExport.annotations = tree.annotations;
|
||||
this.currentExport.elements = tree.elements;
|
||||
this.currentExport.docType = 'class';
|
||||
}
|
||||
},
|
||||
visitAsyncFunctionDeclaration: function(tree) {
|
||||
if ( this.currentExport ) {
|
||||
this.updateExport(tree);
|
||||
}
|
||||
},
|
||||
|
||||
visitExportDefault: function(tree) {
|
||||
if ( this.currentExport ) {
|
||||
this.updateExport(tree);
|
||||
this.currentExport.name = 'DEFAULT';
|
||||
this.currentExport.defaultExport = tree;
|
||||
// Default exports are either classes, functions or expressions
|
||||
// So we let the super class continue down...
|
||||
ParseTreeVisitor.prototype.visitExportDefault.call(this, tree);
|
||||
}
|
||||
},
|
||||
|
||||
visitNamedExport: function(tree) {
|
||||
this.currentExport = null;
|
||||
// if ( this.currentExport ) {
|
||||
// this.updateExport(tree);
|
||||
|
||||
// this.currentExport.namedExport = tree;
|
||||
// this.currentExport.name = 'NAMED_EXPORT';
|
||||
// // TODO: work out this bit!!
|
||||
// // We need to cope with any export specifiers in the named export
|
||||
// }
|
||||
},
|
||||
|
||||
// TODO - if the export is an expression, find the thing that is being
|
||||
// exported and use it and its comments for docs
|
||||
|
||||
updateExport: function(tree) {
|
||||
this.currentExport.comment = this.currentExport.comment || tree.commentBefore;
|
||||
this.currentExport.docType = tree.type;
|
||||
},
|
||||
|
||||
visit: function(tree) {
|
||||
this.exports = [];
|
||||
ParseTreeVisitor.prototype.visit.call(this, tree);
|
||||
}
|
||||
};
|
||||
|
||||
return ExportTreeVisitorImpl;
|
||||
};
|
@ -1,6 +0,0 @@
|
||||
var traceur = require('traceur/src/node/traceur.js');
|
||||
|
||||
module.exports = function ParseTreeVisitor() {
|
||||
console.log(System.map.traceur);
|
||||
return System.get(System.map.traceur + '/src/syntax/ParseTreeVisitor.js').ParseTreeVisitor;
|
||||
};
|
@ -1,5 +0,0 @@
|
||||
var traceur = require('traceur/src/node/traceur.js');
|
||||
|
||||
module.exports = function SourceFile() {
|
||||
return System.get(System.map.traceur + '/src/syntax/SourceFile.js').SourceFile;
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
module.exports = function TraceurParser() {
|
||||
return System.get('transpiler/src/parser').Parser;
|
||||
};
|
@ -1,79 +0,0 @@
|
||||
var file2modulename = require('../../../tools/build/file2modulename');
|
||||
/**
|
||||
* Wrapper around traceur that can parse the contents of a file
|
||||
*/
|
||||
module.exports = function atParser(AttachCommentTreeVisitor, SourceFile, TraceurParser, traceurOptions, log) {
|
||||
|
||||
var service = {
|
||||
/**
|
||||
* The options to pass to traceur
|
||||
*/
|
||||
traceurOptions: {
|
||||
annotations: true, // parse annotations
|
||||
types: true, // parse types
|
||||
memberVariables: true, // parse class fields
|
||||
commentCallback: true // handle comments
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse a module AST from the contents of a file.
|
||||
* @param {Object} fileInfo information about the file to parse
|
||||
* @return { { moduleTree: Object, comments: Array } } An object containing the parsed module
|
||||
* AST and an array of all the comments found in the file
|
||||
*/
|
||||
parseModule: parseModule
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
|
||||
// Parse the contents of the file using traceur
|
||||
function parseModule(fileInfo) {
|
||||
|
||||
var moduleName = file2modulename(fileInfo.relativePath);
|
||||
var sourceFile = new SourceFile(moduleName, fileInfo.content);
|
||||
var comments = [];
|
||||
var moduleTree;
|
||||
var errorReporter = {
|
||||
reportError: function(position, message) {
|
||||
}
|
||||
};
|
||||
|
||||
traceurOptions.setFromObject(service.traceurOptions);
|
||||
var parser = new TraceurParser(sourceFile, errorReporter, traceurOptions);
|
||||
|
||||
// Configure the parser
|
||||
parser.handleComment = function(range) {
|
||||
comments.push({ range: range });
|
||||
};
|
||||
|
||||
try {
|
||||
// Parse the file as a module, attaching the comments
|
||||
moduleTree = parser.parseModule();
|
||||
attachComments(moduleTree, comments);
|
||||
} catch(ex) {
|
||||
// HACK: sometime traceur crashes for various reasons including
|
||||
// Not Yet Implemented (NYI)!
|
||||
log.error(ex.stack);
|
||||
moduleTree = {};
|
||||
}
|
||||
log.debug(moduleName);
|
||||
moduleTree.moduleName = moduleName;
|
||||
|
||||
// We return the module AST but also a collection of all the comments
|
||||
// since it can be helpful to iterate through them without having to
|
||||
// traverse the AST again
|
||||
return {
|
||||
moduleTree: moduleTree,
|
||||
comments: comments
|
||||
};
|
||||
}
|
||||
|
||||
// attach the comments to their nearest code tree
|
||||
function attachComments(tree, comments) {
|
||||
|
||||
var visitor = new AttachCommentTreeVisitor();
|
||||
// Visit every node of the tree using our custom method
|
||||
visitor.visit(tree, comments);
|
||||
}
|
||||
};
|
@ -1,80 +0,0 @@
|
||||
var mockPackage = require('../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
|
||||
describe('atParser service', function() {
|
||||
|
||||
var dgeni, injector, parser;
|
||||
|
||||
var fileContent =
|
||||
'import {CONST} from "facade/lang";\n' +
|
||||
'\n' +
|
||||
'/**\n' +
|
||||
'* A parameter annotation that creates a synchronous eager dependency.\n' +
|
||||
'*\n' +
|
||||
'* class AComponent {\n' +
|
||||
'* constructor(@Inject("aServiceToken") aService) {}\n' +
|
||||
'* }\n' +
|
||||
'*\n' +
|
||||
'*/\n' +
|
||||
'export class Inject {\n' +
|
||||
'token;\n' +
|
||||
'@CONST()\n' +
|
||||
'constructor({a,b}:{a:string, b:string}) {\n' +
|
||||
'this.token = a;\n' +
|
||||
'}\n' +
|
||||
'}';
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
parser = injector.get('atParser');
|
||||
});
|
||||
|
||||
it('should extract the comments from the file', function() {
|
||||
var result = parser.parseModule({
|
||||
content: fileContent,
|
||||
relativePath: 'di/src/annotations.js'
|
||||
});
|
||||
|
||||
expect(result.comments[0].range.toString()).toEqual(
|
||||
'/**\n' +
|
||||
'* A parameter annotation that creates a synchronous eager dependency.\n' +
|
||||
'*\n' +
|
||||
'* class AComponent {\n' +
|
||||
'* constructor(@Inject("aServiceToken") aService) {}\n' +
|
||||
'* }\n' +
|
||||
'*\n' +
|
||||
'*/'
|
||||
);
|
||||
});
|
||||
|
||||
it('should extract a module AST from the file', function() {
|
||||
var result = parser.parseModule({
|
||||
content: fileContent,
|
||||
relativePath: 'di/src/annotations.js'
|
||||
});
|
||||
|
||||
expect(result.moduleTree.moduleName).toEqual('di/src/annotations');
|
||||
expect(result.moduleTree.scriptItemList[0].type).toEqual('IMPORT_DECLARATION');
|
||||
|
||||
expect(result.moduleTree.scriptItemList[1].type).toEqual('EXPORT_DECLARATION');
|
||||
});
|
||||
|
||||
it('should attach comments to their following AST', function() {
|
||||
var result = parser.parseModule({
|
||||
content: fileContent,
|
||||
relativePath: 'di/src/annotations.js'
|
||||
});
|
||||
|
||||
expect(result.moduleTree.scriptItemList[1].commentBefore.range.toString()).toEqual(
|
||||
'/**\n' +
|
||||
'* A parameter annotation that creates a synchronous eager dependency.\n' +
|
||||
'*\n' +
|
||||
'* class AComponent {\n' +
|
||||
'* constructor(@Inject("aServiceToken") aService) {}\n' +
|
||||
'* }\n' +
|
||||
'*\n' +
|
||||
'*/'
|
||||
);
|
||||
});
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
var LEADING_STAR = /^[^\S\r\n]*\*[^\S\n\r]?/gm;
|
||||
|
||||
/**
|
||||
* Extact comment info from a comment object
|
||||
* @param {Object} comment object to process
|
||||
* @return { {startingLine, endingLine, content, codeTree}= } a comment info object
|
||||
* or undefined if the comment is not a jsdoc style comment
|
||||
*/
|
||||
module.exports = function getJSDocComment() {
|
||||
return function(comment) {
|
||||
|
||||
var commentInfo;
|
||||
|
||||
// we need to check for `/**` at the start of the comment to find all the jsdoc style comments
|
||||
comment.range.toString().replace(/^\/\*\*([\w\W]*)\*\/$/g, function(match, commentBody) {
|
||||
commentBody = commentBody.replace(LEADING_STAR, '').trim();
|
||||
|
||||
commentInfo = {
|
||||
startingLine: comment.range.start.line,
|
||||
endingLine: comment.range.end.line,
|
||||
content: commentBody,
|
||||
codeTree: comment.treeAfter
|
||||
};
|
||||
});
|
||||
|
||||
return commentInfo;
|
||||
};
|
||||
};
|
@ -1,67 +0,0 @@
|
||||
var mockPackage = require('../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
|
||||
describe('getJSDocComment service', function() {
|
||||
|
||||
var dgeni, injector, getJSDocComment;
|
||||
|
||||
function createComment(commentString, start, end, codeTree) {
|
||||
return {
|
||||
range: {
|
||||
toString: function() { return commentString; },
|
||||
start: { line: start },
|
||||
end: { line: end },
|
||||
},
|
||||
treeAfter: codeTree
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
getJSDocComment = injector.get('getJSDocComment');
|
||||
});
|
||||
|
||||
it('should only return an object if the comment starts with /** and ends with */', function() {
|
||||
var result = getJSDocComment(createComment('/** this is a jsdoc comment */'));
|
||||
expect(result).toBeDefined();
|
||||
|
||||
result = getJSDocComment(createComment('/* this is a normal comment */'));
|
||||
expect(result).toBeUndefined();
|
||||
|
||||
result = getJSDocComment(createComment('this is not a valid comment */'));
|
||||
expect(result).toBeUndefined();
|
||||
|
||||
result = getJSDocComment(createComment('nor is this'));
|
||||
expect(result).toBeUndefined();
|
||||
|
||||
result = getJSDocComment(createComment('/* or even this'));
|
||||
expect(result).toBeUndefined();
|
||||
|
||||
result = getJSDocComment(createComment('/** and this'));
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
|
||||
it('should return a result that contains info about the comment', function() {
|
||||
var codeTree = {};
|
||||
var result = getJSDocComment(createComment('/** this is a comment */', 10, 20, codeTree));
|
||||
expect(result.startingLine).toEqual(10);
|
||||
expect(result.endingLine).toEqual(20);
|
||||
expect(result.codeTree).toBe(codeTree);
|
||||
});
|
||||
|
||||
it('should strip off leading stars from each line', function() {
|
||||
var result = getJSDocComment(createComment(
|
||||
'/** this is a jsdoc comment */\n' +
|
||||
' *\n' +
|
||||
' * some content\n' +
|
||||
' */'
|
||||
));
|
||||
expect(result.content).toEqual(
|
||||
'this is a jsdoc comment */\n' +
|
||||
'\n' +
|
||||
'some content'
|
||||
);
|
||||
});
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
module.exports = function modules() {
|
||||
return {};
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
module.exports = function traceurOptions() {
|
||||
var Options = System.get(System.map.traceur + "/src/Options.js").Options;
|
||||
return new Options();
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
name: 'exportedAs',
|
||||
multi: true
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
name: 'private',
|
||||
transforms: function(doc, tag) { return true; }
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
name: 'public',
|
||||
transforms: function(doc, tag) { return true; }
|
||||
};
|
@ -1,33 +0,0 @@
|
||||
{% include "lib/paramList.html" -%}
|
||||
{% extends 'layout/base.template.html' -%}
|
||||
|
||||
{% block body %}
|
||||
<h1 class="class export">{$ doc.name $} <span class="type">class</span></h1>
|
||||
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a><br/>
|
||||
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.location.start.source.name $}.js#L{$ doc.location.start.line $}">{$ doc.location.start.source.name $}.js (line {$ doc.location.start.line $})</a></p>
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{%- if doc.constructorDoc or doc.members.length -%}
|
||||
<h2>Members</h2>
|
||||
|
||||
{%- if doc.constructorDoc %}
|
||||
<section class="member constructor">
|
||||
<h1 id="constructor" class="name">{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.params) $}</h1>
|
||||
{% marked %}
|
||||
{$ doc.constructorDoc.description $}
|
||||
{% endmarked %}
|
||||
</section>
|
||||
{% endif -%}
|
||||
|
||||
{%- for member in doc.members %}{% if not member.private %}
|
||||
<section class="member">
|
||||
<h1 id="{$ member.name $}" class="name">{$ member.name $}{$ paramList(member.params) $}</h1>
|
||||
{% marked %}
|
||||
{$ member.description $}
|
||||
{% endmarked %}
|
||||
</section>
|
||||
|
||||
{% endif %}{% endfor %}
|
||||
{%- endif -%}
|
||||
|
||||
{% endblock %}
|
@ -1,9 +0,0 @@
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{$ doc.id $}</h1>
|
||||
<h2>({$ doc.docType $})</h2>
|
||||
<div>
|
||||
{$ doc.description | marked $}
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,3 +0,0 @@
|
||||
angular.module('{$ doc.moduleName $}', [])
|
||||
|
||||
.value('{$ doc.serviceName $}', {$ doc.value | json $});
|
@ -1,9 +0,0 @@
|
||||
{% include "lib/paramList.html" -%}
|
||||
{% extends 'layout/base.template.html' -%}
|
||||
|
||||
{% block body %}
|
||||
<h1 class="function export">{$ doc.name $}{$ paramList(doc.parameters) $}</h1>
|
||||
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a></p>
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{% endblock %}
|
@ -1,5 +0,0 @@
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
{$ doc.description | marked $}
|
||||
{% endblock %}
|
@ -1 +0,0 @@
|
||||
{% block body %}{% endblock %}
|
@ -1,7 +0,0 @@
|
||||
{% macro paramList(params) -%}
|
||||
{%- if params -%}<span class="params">(
|
||||
{%- for param in params -%}
|
||||
<span class="param">{$ param | escape $}{% if not loop.last %}, {% endif %}</span>
|
||||
{%- endfor %})</span>
|
||||
{%- endif %}
|
||||
{%- endmacro -%}
|
@ -1,18 +0,0 @@
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
<h1 class="id">{$ doc.id $} <span class="type">module</span></h1>
|
||||
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{% if doc.exports.length %}
|
||||
<h2>Exports</h2>
|
||||
<ul>
|
||||
{%- for exportDoc in doc.exports %}
|
||||
{% if not exportDoc.private -%}
|
||||
<li><a href="/{$ exportDoc.path $}"><strong>{$ exportDoc.name $}</strong> {$ exportDoc.docType $}</a></li>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -1,43 +0,0 @@
|
||||
{% include "lib/paramList.html" -%}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<style>
|
||||
h2 {
|
||||
padding-left: 20px;
|
||||
}
|
||||
h3 {
|
||||
padding-left: 50px;
|
||||
}
|
||||
h4 {
|
||||
padding-left: 60px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<h1>Modules</h1>
|
||||
|
||||
{% for module in doc.modules %}
|
||||
|
||||
<h2>{$ module.id $}
|
||||
{%- if module.public %} (public){% endif %}</h2>
|
||||
|
||||
{% for export in module.exports %}
|
||||
<h3>{$ export.name $}</h3>
|
||||
|
||||
{%- if export.constructorDoc %}
|
||||
<h4>{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.params) $}</h4>
|
||||
{% endif -%}
|
||||
{%- for member in export.members %}
|
||||
<h4>{$ member.name $}{$ paramList(member.params) $}</h4>
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,8 +0,0 @@
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{$ doc.name $} <span class="type">variable</span></h1>
|
||||
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a></p>
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{% endblock %}
|
@ -1,12 +0,0 @@
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
module.exports = new Package('links', [])
|
||||
|
||||
.factory(require('dgeni-packages/ngdoc/inline-tag-defs/link'))
|
||||
.factory(require('dgeni-packages/ngdoc/services/getAliases'))
|
||||
.factory(require('dgeni-packages/ngdoc/services/getDocFromAlias'))
|
||||
.factory(require('dgeni-packages/ngdoc/services/getLinkInfo'))
|
||||
|
||||
.config(function(inlineTagProcessor, linkInlineTagDef) {
|
||||
inlineTagProcessor.inlineTagDefinitions.push(linkInlineTagDef);
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
var Package = require('dgeni').Package;
|
||||
var basePackage = require('../dgeni-package');
|
||||
var linksPackage = require('../links-package');
|
||||
|
||||
module.exports = new Package('angular-public', [basePackage, linksPackage])
|
||||
|
||||
.processor(require('./processors/filterPublicDocs'))
|
||||
|
||||
.config(function(captureClassMembers) {
|
||||
captureClassMembers.ignorePrivateMembers = true;
|
||||
})
|
||||
|
||||
// Configure file writing
|
||||
.config(function(writeFilesProcessor) {
|
||||
writeFilesProcessor.outputFolder = 'dist/public_docs';
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function filterPublicDocs(modules, EXPORT_DOC_TYPES) {
|
||||
return {
|
||||
$runAfter: ['tags-parsed', 'cloneExportedFromDocs'],
|
||||
$runBefore: ['computing-ids'],
|
||||
$process: function(docs) {
|
||||
|
||||
// Filter out the documents that are not public
|
||||
return _.filter(docs, function(doc) {
|
||||
|
||||
if (doc.docType === 'module') {
|
||||
// doc is a module - is it public?
|
||||
return doc.public;
|
||||
}
|
||||
|
||||
if (EXPORT_DOC_TYPES.indexOf(doc.docType) === -1) {
|
||||
// doc is not a type we care about
|
||||
return true;
|
||||
}
|
||||
|
||||
// doc is in a public module
|
||||
return doc.moduleDoc && doc.moduleDoc.public;
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
1883
gulpfile.js
1883
gulpfile.js
File diff suppressed because it is too large
Load Diff
86
karma-dart-evalcache.js
Normal file
86
karma-dart-evalcache.js
Normal file
@ -0,0 +1,86 @@
|
||||
// This module provides a customFileHandler for karma
|
||||
// that serves files with urls like /packages_<timestamp>/...
|
||||
// with maximum cache.
|
||||
// We are using these urls when we spawn isolates
|
||||
// so that the isolates don't reload files every time.
|
||||
|
||||
var common = require('karma/lib/middleware/common');
|
||||
var fs = require('fs');
|
||||
|
||||
var DART_EVAL_PATH_RE = /.*\/packages_\d+\/(.*)$/;
|
||||
|
||||
module.exports = createFactory;
|
||||
|
||||
function createFactory(proxyPaths) {
|
||||
return {
|
||||
'framework:dart-evalcache': ['factory', dartEvalCacheFactory]
|
||||
};
|
||||
|
||||
function dartEvalCacheFactory(emitter, logger, customFileHandlers) {
|
||||
var filesPromise = new common.PromiseContainer();
|
||||
emitter.on('file_list_modified', function(files) {
|
||||
filesPromise.set(Promise.resolve(files));
|
||||
});
|
||||
|
||||
var serveFile = common.createServeFile(fs);
|
||||
var log = logger.create('dart-evalcache');
|
||||
|
||||
customFileHandlers.push({
|
||||
urlRegex: DART_EVAL_PATH_RE,
|
||||
handler: handler
|
||||
});
|
||||
|
||||
// See source_files handler
|
||||
function handler(request, response, fa, fb, basePath) {
|
||||
return filesPromise.then(function(files) {
|
||||
try {
|
||||
var requestedFilePath = mapUrlToFile(request.url, proxyPaths, basePath, log);
|
||||
// TODO(vojta): change served to be a map rather then an array
|
||||
var file = findByPath(files.served, requestedFilePath);
|
||||
if (file) {
|
||||
serveFile(file.contentPath || file.path, response, function() {
|
||||
common.setHeavyCacheHeaders(response);
|
||||
}, file.content);
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end('Not found');
|
||||
}
|
||||
} catch (e) {
|
||||
log.error(e.stack);
|
||||
response.writeHead(500);
|
||||
response.end('Error', e.stack);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function mapUrlToFile(url, proxyPaths, basePath, log) {
|
||||
var originalUrl = url;
|
||||
url = url.indexOf('?') > -1 ? url.substring(0, url.indexOf('?')) : url;
|
||||
var match = DART_EVAL_PATH_RE.exec(url);
|
||||
var packagePath = match[1];
|
||||
var result = null;
|
||||
var lastProxyFromLength = 0;
|
||||
Object.keys(proxyPaths).forEach(function(proxyFrom) {
|
||||
if (startsWith(packagePath, proxyFrom) && proxyFrom.length > lastProxyFromLength) {
|
||||
lastProxyFromLength = proxyFrom.length;
|
||||
result = proxyPaths[proxyFrom] + packagePath.substring(proxyFrom.length);
|
||||
}
|
||||
});
|
||||
return basePath + '/' + result;
|
||||
}
|
||||
|
||||
function startsWith(string, subString) {
|
||||
return string.length >= subString.length && string.slice(0, subString.length) === subString;
|
||||
}
|
||||
|
||||
function findByPath(files, path) {
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
if (files[i].path === path) {
|
||||
return files[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
@ -1,85 +1,82 @@
|
||||
var browserProvidersConf = require('./browser-providers.conf.js');
|
||||
|
||||
var packageSources = {
|
||||
// Dependencies installed with `pub install`.
|
||||
'unittest': 'packages/unittest',
|
||||
'guinness': 'packages/guinness',
|
||||
'matcher': 'packages/matcher',
|
||||
'stack_trace': 'packages/stack_trace',
|
||||
'collection': 'packages/collection',
|
||||
'path': 'packages/path',
|
||||
'observe': 'packages/observe',
|
||||
'quiver': 'packages/quiver',
|
||||
'intl': 'packages/intl',
|
||||
'smoke': 'packages/smoke',
|
||||
'logging': 'packages/logging',
|
||||
'utf': 'packages/utf',
|
||||
|
||||
// Local dependencies, transpiled from the source.
|
||||
'angular2': 'dist/dart/angular2/lib',
|
||||
'angular2/test/': 'dist/dart/angular2/test/',
|
||||
'http': 'dist/dart/http/lib',
|
||||
'angular2_material': 'dist/dart/angular2_material/lib',
|
||||
'benchpress': 'dist/dart/benchpress/lib',
|
||||
'examples': 'dist/dart/examples/lib'
|
||||
};
|
||||
|
||||
var proxyPaths = {};
|
||||
Object.keys(packageSources).map(function(packageName) {
|
||||
var filePath = packageSources[packageName];
|
||||
proxyPaths['/packages/'+packageName] = '/base/'+filePath;
|
||||
});
|
||||
|
||||
// Karma configuration
|
||||
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
|
||||
var file2moduleName = require('./tools/build/file2modulename');
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
|
||||
frameworks: ['dart-unittest'],
|
||||
frameworks: ['dart-unittest', 'dart-evalcache'],
|
||||
|
||||
files: [
|
||||
// Init and configure guiness.
|
||||
{pattern: 'test-init.dart', included: true},
|
||||
// Unit test files needs to be included.
|
||||
// Karma-dart generates `__adapter_unittest.dart` that imports these files.
|
||||
{pattern: 'modules/*/test/**/*_spec.js', included: true},
|
||||
{pattern: 'modules/*/test/**/*_spec.dart', included: true},
|
||||
{pattern: 'tools/transpiler/spec/**/*_spec.js', included: true},
|
||||
{pattern: 'dist/dart/**/*_spec.dart', included: true, watched: false},
|
||||
|
||||
// These files are not included, they are imported by the unit tests above.
|
||||
{pattern: 'modules/**', included: false},
|
||||
{pattern: 'tools/transpiler/spec/**/*', included: false},
|
||||
// Karma-dart via the dart-unittest framework generates
|
||||
// `__adapter_unittest.dart` that imports these files.
|
||||
{pattern: 'dist/dart/**', included: false, watched: false},
|
||||
|
||||
// Dependencies, installed with `pub install`.
|
||||
{pattern: 'packages/**/*.dart', included: false, watched: false},
|
||||
|
||||
// Init and configure guiness.
|
||||
{pattern: 'test-main.dart', included: true}
|
||||
{pattern: 'test-main.dart', included: true},
|
||||
{pattern: 'modules/**/test/**/static_assets/**', included: false, watched: false},
|
||||
],
|
||||
|
||||
exclude: [
|
||||
'dist/dart/**/packages/**',
|
||||
'modules/angular1_router/**'
|
||||
],
|
||||
|
||||
karmaDartImports: {
|
||||
guinness: 'package:guinness/guinness_html.dart'
|
||||
},
|
||||
|
||||
// TODO(vojta): Remove the localhost:9877 from urls, once the proxy fix is merged:
|
||||
// https://github.com/karma-runner/karma/pull/1207
|
||||
//
|
||||
// Map packages to the correct urls where Karma serves them.
|
||||
proxies: {
|
||||
// Dependencies installed with `pub install`.
|
||||
'/packages/unittest': 'http://localhost:9877/base/packages/unittest',
|
||||
'/packages/guinness': 'http://localhost:9877/base/packages/guinness',
|
||||
'/packages/matcher': 'http://localhost:9877/base/packages/matcher',
|
||||
'/packages/stack_trace': 'http://localhost:9877/base/packages/stack_trace',
|
||||
'/packages/collection': 'http://localhost:9877/base/packages/collection',
|
||||
'/packages/path': 'http://localhost:9877/base/packages/path',
|
||||
proxies: proxyPaths,
|
||||
|
||||
// Local dependencies, transpiled from the source.
|
||||
'/packages/angular': 'http://localhost:9877/base/modules/angular',
|
||||
'/packages/benchpress': 'http://localhost:9877/base/modules/benchpress',
|
||||
'/packages/core': 'http://localhost:9877/base/modules/core',
|
||||
'/packages/change_detection': 'http://localhost:9877/base/modules/change_detection',
|
||||
'/packages/reflection': 'http://localhost:9877/base/modules/reflection',
|
||||
'/packages/di': 'http://localhost:9877/base/modules/di',
|
||||
'/packages/directives': 'http://localhost:9877/base/modules/directives',
|
||||
'/packages/facade': 'http://localhost:9877/base/modules/facade',
|
||||
'/packages/forms': 'http://localhost:9877/base/modules/forms',
|
||||
'/packages/test_lib': 'http://localhost:9877/base/modules/test_lib',
|
||||
'/packages/mock': 'http://localhost:9877/base/modules/mock',
|
||||
},
|
||||
|
||||
preprocessors: {
|
||||
'modules/**/*.js': ['ts2dart'],
|
||||
'tools/**/*.js': ['ts2dart']
|
||||
},
|
||||
|
||||
ts2dartPreprocessor: {
|
||||
resolveModuleName: file2moduleName,
|
||||
transformPath: function(fileName) {
|
||||
return fileName.replace(/.js$/, '.dart');
|
||||
}
|
||||
},
|
||||
|
||||
customLaunchers: {
|
||||
DartiumWithWebPlatform: {
|
||||
base: 'Dartium',
|
||||
flags: ['--enable-experimental-web-platform-features'] }
|
||||
},
|
||||
customLaunchers: browserProvidersConf.customLaunchers,
|
||||
browsers: ['DartiumWithWebPlatform'],
|
||||
|
||||
port: 9877
|
||||
port: 9877,
|
||||
|
||||
plugins: [
|
||||
require('karma-dart'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-sauce-launcher'),
|
||||
require('./karma-dart-evalcache')(packageSources)
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
config.plugins.push(require('./tools/transpiler/karma-ts2dart-preprocessor'));
|
||||
};
|
||||
|
110
karma-js.conf.js
110
karma-js.conf.js
@ -1,7 +1,8 @@
|
||||
var browserProvidersConf = require('./browser-providers.conf.js');
|
||||
var internalAngularReporter = require('./tools/karma/reporter.js');
|
||||
|
||||
// Karma configuration
|
||||
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
|
||||
var file2moduleName = require('./tools/build/file2modulename');
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
|
||||
@ -9,65 +10,88 @@ module.exports = function(config) {
|
||||
|
||||
files: [
|
||||
// Sources and specs.
|
||||
// Loaded through the es6-module-loader, in `test-main.js`.
|
||||
{pattern: 'modules/**', included: false},
|
||||
{pattern: 'tools/transpiler/spec/**', included: false},
|
||||
// Loaded through the System loader, in `test-main.js`.
|
||||
{pattern: 'dist/js/dev/es5/**', included: false, watched: false},
|
||||
|
||||
'node_modules/es6-shim/es6-shim.js',
|
||||
// include Angular v1 for upgrade module testing
|
||||
'node_modules/angular/angular.min.js',
|
||||
|
||||
// zone-microtask must be included first as it contains a Promise monkey patch
|
||||
'node_modules/zone.js/dist/zone-microtask.js',
|
||||
'node_modules/zone.js/dist/long-stack-trace-zone.js',
|
||||
'node_modules/zone.js/dist/jasmine-patch.js',
|
||||
|
||||
'node_modules/traceur/bin/traceur-runtime.js',
|
||||
'node_modules/es6-module-loader/dist/es6-module-loader-sans-promises.src.js',
|
||||
// Including systemjs because it defines `__eval`, which produces correct stack traces.
|
||||
'modules/angular2/src/testing/shims_for_IE.js',
|
||||
'node_modules/systemjs/dist/system.src.js',
|
||||
'node_modules/systemjs/lib/extension-register.js',
|
||||
'node_modules/systemjs/lib/extension-cjs.js',
|
||||
'node_modules/rx/dist/rx.all.js',
|
||||
'node_modules/zone.js/zone.js',
|
||||
'node_modules/zone.js/long-stack-trace-zone.js',
|
||||
|
||||
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
|
||||
'node_modules/reflect-metadata/Reflect.js',
|
||||
'tools/build/file2modulename.js',
|
||||
'test-main.js'
|
||||
'test-main.js',
|
||||
{pattern: 'modules/**/test/**/static_assets/**', included: false, watched: false}
|
||||
],
|
||||
|
||||
exclude: [
|
||||
'modules/**/e2e_test/**'
|
||||
exclude: ['dist/js/dev/es5/**/e2e_test/**', 'dist/js/dev/es5/angular2/examples/**', 'dist/angular1_router.js'],
|
||||
|
||||
customLaunchers: browserProvidersConf.customLaunchers,
|
||||
|
||||
plugins: [
|
||||
'karma-jasmine',
|
||||
'karma-browserstack-launcher',
|
||||
'karma-sauce-launcher',
|
||||
'karma-chrome-launcher',
|
||||
'karma-sourcemap-loader',
|
||||
'karma-dart',
|
||||
internalAngularReporter
|
||||
],
|
||||
|
||||
preprocessors: {
|
||||
'modules/**/*.js': ['traceur'],
|
||||
'modules/**/*.es6': ['traceur'],
|
||||
'tools/transpiler/spec/**/*.js': ['traceur'],
|
||||
'tools/transpiler/spec/**/*.es6': ['traceur'],
|
||||
'**/*.js': ['sourcemap']
|
||||
},
|
||||
|
||||
traceurPreprocessor: {
|
||||
reporters: ['internal-angular'],
|
||||
sauceLabs: {
|
||||
testName: 'Angular2',
|
||||
startConnect: false,
|
||||
recordVideo: false,
|
||||
recordScreenshots: false,
|
||||
options: {
|
||||
outputLanguage: 'es5',
|
||||
sourceMaps: true,
|
||||
script: false,
|
||||
memberVariables: true,
|
||||
modules: 'instantiate',
|
||||
types: true,
|
||||
typeAssertions: true,
|
||||
typeAssertionModule: 'rtts_assert/rtts_assert',
|
||||
annotations: true
|
||||
},
|
||||
resolveModuleName: file2moduleName,
|
||||
transformPath: function(fileName) {
|
||||
return fileName.replace(/\.es6$/, '.js');
|
||||
'selenium-version': '2.48.2',
|
||||
'command-timeout': 600,
|
||||
'idle-timeout': 600,
|
||||
'max-duration': 5400
|
||||
}
|
||||
},
|
||||
|
||||
customLaunchers: {
|
||||
DartiumWithWebPlatform: {
|
||||
base: 'Dartium',
|
||||
flags: ['--enable-experimental-web-platform-features'] },
|
||||
ChromeNoSandbox: {
|
||||
base: 'Chrome',
|
||||
flags: ['--no-sandbox'] }
|
||||
browserStack: {
|
||||
project: 'Angular2',
|
||||
startTunnel: false,
|
||||
retryLimit: 1,
|
||||
timeout: 600,
|
||||
pollingTimeout: 10000
|
||||
},
|
||||
browsers: ['ChromeCanary'],
|
||||
|
||||
browsers: ['Chrome'],
|
||||
|
||||
port: 9876
|
||||
});
|
||||
|
||||
config.plugins.push(require('./tools/transpiler/karma-traceur-preprocessor'));
|
||||
if (process.env.TRAVIS) {
|
||||
var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
|
||||
if (process.env.MODE.startsWith('saucelabs')) {
|
||||
config.sauceLabs.build = buildId;
|
||||
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
|
||||
// TODO(mlaval): remove once SauceLabs supports websockets.
|
||||
// This speeds up the capturing a bit, as browsers don't even try to use websocket.
|
||||
console.log('>>>> setting socket.io transport to polling <<<<');
|
||||
config.transports = ['polling'];
|
||||
}
|
||||
|
||||
if (process.env.MODE.startsWith('browserstack')) {
|
||||
config.browserStack.build = buildId;
|
||||
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1 +0,0 @@
|
||||
karma-js.conf.js
|
97
modules/angular1_router/build.js
vendored
Normal file
97
modules/angular1_router/build.js
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var ts = require('typescript');
|
||||
|
||||
var files = [
|
||||
'lifecycle_annotations_impl.ts',
|
||||
'url_parser.ts',
|
||||
'route_recognizer.ts',
|
||||
'route_config_impl.ts',
|
||||
'async_route_handler.ts',
|
||||
'sync_route_handler.ts',
|
||||
'component_recognizer.ts',
|
||||
'instruction.ts',
|
||||
'path_recognizer.ts',
|
||||
'route_config_nomalizer.ts',
|
||||
'route_lifecycle_reflector.ts',
|
||||
'route_registry.ts',
|
||||
'router.ts'
|
||||
];
|
||||
|
||||
var PRELUDE = '(function(){\n';
|
||||
var POSTLUDE = '\n}());\n';
|
||||
|
||||
function main(modulesDirectory) {
|
||||
var angular1RouterModuleDirectory = modulesDirectory + '/angular1_router';
|
||||
|
||||
var facades = fs.readFileSync(
|
||||
angular1RouterModuleDirectory + '/lib/facades.es5', 'utf8');
|
||||
var directives = fs.readFileSync(
|
||||
angular1RouterModuleDirectory + '/src/ng_outlet.ts', 'utf8');
|
||||
var moduleTemplate = fs.readFileSync(
|
||||
angular1RouterModuleDirectory + '/src/module_template.js', 'utf8');
|
||||
|
||||
var dir = modulesDirectory + '/angular2/src/router/';
|
||||
var sharedCode = files.reduce(function (prev, file) {
|
||||
return prev + transform(fs.readFileSync(dir + file, 'utf8'));
|
||||
}, '');
|
||||
|
||||
var out = moduleTemplate.replace('//{{FACADES}}', facades)
|
||||
.replace('//{{SHARED_CODE}}', sharedCode);
|
||||
return PRELUDE + transform(directives) + out + POSTLUDE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a directory name and a file's TypeScript content, return an object with the ES5 code,
|
||||
* sourcemap, and exported variable identifier name for the content.
|
||||
*/
|
||||
var IMPORT_RE = new RegExp("import \\{?([\\w\\n_, ]+)\\}? from '(.+)';?", 'g');
|
||||
var INJECT_RE = new RegExp("@Inject\\(ROUTER_PRIMARY_COMPONENT\\)", 'g');
|
||||
var IMJECTABLE_RE = new RegExp("@Injectable\\(\\)", 'g');
|
||||
function transform(contents) {
|
||||
contents = contents.replace(INJECT_RE, '').replace(IMJECTABLE_RE, '');
|
||||
contents = contents.replace(IMPORT_RE, function (match, imports, includePath) {
|
||||
//TODO: remove special-case
|
||||
if (isFacadeModule(includePath) || includePath === './router_outlet') {
|
||||
return '';
|
||||
}
|
||||
return match;
|
||||
});
|
||||
return ts.transpile(contents, {
|
||||
target: ts.ScriptTarget.ES5,
|
||||
module: ts.ModuleKind.CommonJS
|
||||
});
|
||||
}
|
||||
|
||||
function isFacadeModule(modulePath) {
|
||||
return modulePath.indexOf('facade') > -1 ||
|
||||
modulePath === 'angular2/src/core/reflection/reflection';
|
||||
}
|
||||
|
||||
module.exports = function(modulesDirectory, outputDirectory) {
|
||||
if (!fs.existsSync(outputDirectory)) {
|
||||
fs.mkdirSync(outputDirectory);
|
||||
}
|
||||
fs.writeFileSync(
|
||||
outputDirectory + '/angular_1_router.js', main(modulesDirectory));
|
||||
};
|
||||
|
||||
// CLI entry point
|
||||
if (require.main === module) {
|
||||
try {
|
||||
var args = process.argv;
|
||||
args.shift(); // node
|
||||
args.shift(); // scriptfile.js
|
||||
if (args.length < 2) {
|
||||
console.log("usage: $0 outFile path/to/modules");
|
||||
process.exit(1);
|
||||
}
|
||||
var outfile = args.shift();
|
||||
var directory = args.shift();
|
||||
fs.writeFileSync(outfile, main(directory));
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
22
modules/angular1_router/index.html
Normal file
22
modules/angular1_router/index.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<div ng-app="myApp" ng-controller="MyCtrl">
|
||||
|
||||
</div>
|
||||
<script src="../../node_modules/angular/angular.js"></script>
|
||||
<script src="../../dist/angular_1_router.js"></script>
|
||||
<script>
|
||||
angular.module('myApp', ['ngComponentRouter'])
|
||||
.controller('MyCtrl', ['$router', function ($router) {
|
||||
console.log($router);
|
||||
$router.navigateByUrl('/')
|
||||
.then(console.log.bind(console, 'resolve'), console.log.bind(console, 'reject'));
|
||||
}]);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
30
modules/angular1_router/karma-router.conf.js
Normal file
30
modules/angular1_router/karma-router.conf.js
Normal file
@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
var browserProvidersConf = require('../../browser-providers.conf.js');
|
||||
|
||||
// This runs the tests for the router in Angular 1.x
|
||||
|
||||
module.exports = function (config) {
|
||||
var options = {
|
||||
frameworks: ['jasmine'],
|
||||
|
||||
files: [
|
||||
'../../node_modules/es6-shim/es6-shim.js',
|
||||
'../../node_modules/angular/angular.js',
|
||||
'../../node_modules/angular-animate/angular-animate.js',
|
||||
'../../node_modules/angular-mocks/angular-mocks.js',
|
||||
|
||||
'../../dist/angular_1_router.js',
|
||||
'src/ng_route_shim.js',
|
||||
|
||||
'test/*.es5.js',
|
||||
'test/**/*_spec.js'
|
||||
],
|
||||
|
||||
customLaunchers: browserProvidersConf.customLaunchers,
|
||||
|
||||
browsers: ['Chrome']
|
||||
};
|
||||
|
||||
config.set(options);
|
||||
};
|
318
modules/angular1_router/lib/facades.es5
Normal file
318
modules/angular1_router/lib/facades.es5
Normal file
@ -0,0 +1,318 @@
|
||||
function CONST() {
|
||||
return (function(target) {
|
||||
return target;
|
||||
});
|
||||
}
|
||||
|
||||
function CONST_EXPR(expr) {
|
||||
return expr;
|
||||
}
|
||||
|
||||
function isPresent (x) {
|
||||
return !!x;
|
||||
}
|
||||
|
||||
function isBlank (x) {
|
||||
return !x;
|
||||
}
|
||||
|
||||
function isString(obj) {
|
||||
return typeof obj === 'string';
|
||||
}
|
||||
|
||||
function isType (x) {
|
||||
return typeof x === 'function';
|
||||
}
|
||||
|
||||
function isStringMap(obj) {
|
||||
return typeof obj === 'object' && obj !== null;
|
||||
}
|
||||
|
||||
function isArray(obj) {
|
||||
return Array.isArray(obj);
|
||||
}
|
||||
|
||||
function getTypeNameForDebugging (fn) {
|
||||
return fn.name || 'Root';
|
||||
}
|
||||
|
||||
var PromiseWrapper = {
|
||||
resolve: function (reason) {
|
||||
return $q.when(reason);
|
||||
},
|
||||
|
||||
reject: function (reason) {
|
||||
return $q.reject(reason);
|
||||
},
|
||||
|
||||
catchError: function (promise, fn) {
|
||||
return promise.then(null, fn);
|
||||
},
|
||||
all: function (promises) {
|
||||
return $q.all(promises);
|
||||
}
|
||||
};
|
||||
|
||||
var RegExpWrapper = {
|
||||
create: function(regExpStr, flags) {
|
||||
flags = flags ? flags.replace(/g/g, '') : '';
|
||||
return new RegExp(regExpStr, flags + 'g');
|
||||
},
|
||||
firstMatch: function(regExp, input) {
|
||||
regExp.lastIndex = 0;
|
||||
return regExp.exec(input);
|
||||
},
|
||||
matcher: function (regExp, input) {
|
||||
regExp.lastIndex = 0;
|
||||
return { re: regExp, input: input };
|
||||
}
|
||||
};
|
||||
|
||||
var reflector = {
|
||||
annotations: function (fn) {
|
||||
//TODO: implement me
|
||||
return fn.annotations || [];
|
||||
}
|
||||
};
|
||||
|
||||
var MapWrapper = {
|
||||
create: function() {
|
||||
return new Map();
|
||||
},
|
||||
|
||||
get: function(m, k) {
|
||||
return m.get(k);
|
||||
},
|
||||
|
||||
set: function(m, k, v) {
|
||||
return m.set(k, v);
|
||||
},
|
||||
|
||||
contains: function (m, k) {
|
||||
return m.has(k);
|
||||
},
|
||||
|
||||
forEach: function (m, fn) {
|
||||
return m.forEach(fn);
|
||||
}
|
||||
};
|
||||
|
||||
var StringMapWrapper = {
|
||||
create: function () {
|
||||
return {};
|
||||
},
|
||||
|
||||
set: function (m, k, v) {
|
||||
return m[k] = v;
|
||||
},
|
||||
|
||||
get: function (m, k) {
|
||||
return m.hasOwnProperty(k) ? m[k] : undefined;
|
||||
},
|
||||
|
||||
contains: function (m, k) {
|
||||
return m.hasOwnProperty(k);
|
||||
},
|
||||
|
||||
keys: function(map) {
|
||||
return Object.keys(map);
|
||||
},
|
||||
|
||||
isEmpty: function(map) {
|
||||
for (var prop in map) {
|
||||
if (map.hasOwnProperty(prop)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
delete: function(map, key) {
|
||||
delete map[key];
|
||||
},
|
||||
|
||||
forEach: function (m, fn) {
|
||||
for (var prop in m) {
|
||||
if (m.hasOwnProperty(prop)) {
|
||||
fn(m[prop], prop);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
equals: function (m1, m2) {
|
||||
var k1 = Object.keys(m1);
|
||||
var k2 = Object.keys(m2);
|
||||
if (k1.length != k2.length) {
|
||||
return false;
|
||||
}
|
||||
var key;
|
||||
for (var i = 0; i < k1.length; i++) {
|
||||
key = k1[i];
|
||||
if (m1[key] !== m2[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
merge: function(m1, m2) {
|
||||
var m = {};
|
||||
for (var attr in m1) {
|
||||
if (m1.hasOwnProperty(attr)) {
|
||||
m[attr] = m1[attr];
|
||||
}
|
||||
}
|
||||
for (var attr in m2) {
|
||||
if (m2.hasOwnProperty(attr)) {
|
||||
m[attr] = m2[attr];
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
};
|
||||
|
||||
var List = Array;
|
||||
var ListWrapper = {
|
||||
toJSON: function(l) {
|
||||
return JSON.stringify(l);
|
||||
},
|
||||
|
||||
clear: function (l) {
|
||||
l.length = 0;
|
||||
},
|
||||
|
||||
create: function () {
|
||||
return [];
|
||||
},
|
||||
|
||||
push: function (l, v) {
|
||||
return l.push(v);
|
||||
},
|
||||
|
||||
forEach: function (l, fn) {
|
||||
return l.forEach(fn);
|
||||
},
|
||||
|
||||
first: function(array) {
|
||||
if (!array)
|
||||
return null;
|
||||
return array[0];
|
||||
},
|
||||
|
||||
last: function(array) {
|
||||
return (array && array.length) > 0 ? array[array.length - 1] : null;
|
||||
},
|
||||
|
||||
map: function (l, fn) {
|
||||
return l.map(fn);
|
||||
},
|
||||
|
||||
join: function (l, str) {
|
||||
return l.join(str);
|
||||
},
|
||||
|
||||
reduce: function(list, fn, init) {
|
||||
return list.reduce(fn, init);
|
||||
},
|
||||
|
||||
filter: function(array, pred) {
|
||||
return array.filter(pred);
|
||||
},
|
||||
|
||||
concat: function(a, b) {
|
||||
return a.concat(b);
|
||||
},
|
||||
|
||||
slice: function(l) {
|
||||
var from = arguments[1] !== (void 0) ? arguments[1] : 0;
|
||||
var to = arguments[2] !== (void 0) ? arguments[2] : null;
|
||||
return l.slice(from, to === null ? undefined : to);
|
||||
},
|
||||
|
||||
maximum: function(list, predicate) {
|
||||
if (list.length == 0) {
|
||||
return null;
|
||||
}
|
||||
var solution = null;
|
||||
var maxValue = -Infinity;
|
||||
for (var index = 0; index < list.length; index++) {
|
||||
var candidate = list[index];
|
||||
if (isBlank(candidate)) {
|
||||
continue;
|
||||
}
|
||||
var candidateValue = predicate(candidate);
|
||||
if (candidateValue > maxValue) {
|
||||
solution = candidate;
|
||||
maxValue = candidateValue;
|
||||
}
|
||||
}
|
||||
return solution;
|
||||
}
|
||||
};
|
||||
|
||||
var StringWrapper = {
|
||||
charCodeAt: function(s, i) {
|
||||
return s.charCodeAt(i);
|
||||
},
|
||||
|
||||
equals: function (s1, s2) {
|
||||
return s1 === s2;
|
||||
},
|
||||
|
||||
split: function(s, re) {
|
||||
return s.split(re);
|
||||
},
|
||||
|
||||
replaceAll: function(s, from, replace) {
|
||||
return s.replace(from, replace);
|
||||
},
|
||||
|
||||
replaceAllMapped: function(s, from, cb) {
|
||||
return s.replace(from, function(matches) {
|
||||
// Remove offset & string from the result array
|
||||
matches.splice(-2, 2);
|
||||
// The callback receives match, p1, ..., pn
|
||||
return cb.apply(null, matches);
|
||||
});
|
||||
},
|
||||
|
||||
contains: function(s, substr) {
|
||||
return s.indexOf(substr) != -1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//TODO: implement?
|
||||
// I think it's too heavy to ask 1.x users to bring in Rx for the router...
|
||||
function EventEmitter() {}
|
||||
|
||||
var BaseException = Error;
|
||||
|
||||
var ObservableWrapper = {
|
||||
callNext: function(ob, val) {
|
||||
ob.fn(val);
|
||||
},
|
||||
callEmit: function(ob, val) {
|
||||
ob.fn(val);
|
||||
},
|
||||
|
||||
subscribe: function(ob, fn) {
|
||||
ob.fn = fn;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: https://github.com/angular/angular.js/blob/master/src/ng/browser.js#L227-L265
|
||||
var $__router_47_location__ = {
|
||||
Location: Location
|
||||
};
|
||||
|
||||
function Location(){}
|
||||
Location.prototype.subscribe = function () {
|
||||
//TODO: implement
|
||||
};
|
||||
Location.prototype.path = function () {
|
||||
return $location.url();
|
||||
};
|
||||
Location.prototype.go = function (path, query) {
|
||||
return $location.url(path + query);
|
||||
};
|
71
modules/angular1_router/src/module_template.js
vendored
Normal file
71
modules/angular1_router/src/module_template.js
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
angular.module('ngComponentRouter').
|
||||
value('$route', null). // can be overloaded with ngRouteShim
|
||||
// Because Angular 1 has no notion of a root component, we use an object with unique identity
|
||||
// to represent this. Can be overloaded with a component name
|
||||
value('$routerRootComponent', new Object()).
|
||||
factory('$router', ['$q', '$location', '$$directiveIntrospector', '$browser', '$rootScope', '$injector', '$routerRootComponent', routerFactory]);
|
||||
|
||||
function routerFactory($q, $location, $$directiveIntrospector, $browser, $rootScope, $injector, $routerRootComponent) {
|
||||
|
||||
// When this file is processed, the line below is replaced with
|
||||
// the contents of `../lib/facades.es5`.
|
||||
//{{FACADES}}
|
||||
|
||||
var exports = {
|
||||
Injectable: function () {},
|
||||
OpaqueToken: function () {},
|
||||
Inject: function () {}
|
||||
};
|
||||
var require = function () {return exports;};
|
||||
|
||||
// When this file is processed, the line below is replaced with
|
||||
// the contents of the compiled TypeScript classes.
|
||||
//{{SHARED_CODE}}
|
||||
|
||||
//TODO: this is a hack to replace the exiting implementation at run-time
|
||||
exports.getCanActivateHook = function (directiveName) {
|
||||
var factory = $$directiveIntrospector.getTypeByName(directiveName);
|
||||
return factory && factory.$canActivate && function (next, prev) {
|
||||
return $injector.invoke(factory.$canActivate, null, {
|
||||
$nextInstruction: next,
|
||||
$prevInstruction: prev
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// This hack removes assertions about the type of the "component"
|
||||
// property in a route config
|
||||
exports.assertComponentExists = function () {};
|
||||
|
||||
angular.stringifyInstruction = function (instruction) {
|
||||
return instruction.toRootUrl();
|
||||
};
|
||||
|
||||
var RouteRegistry = exports.RouteRegistry;
|
||||
var RootRouter = exports.RootRouter;
|
||||
|
||||
var registry = new RouteRegistry($routerRootComponent);
|
||||
var location = new Location();
|
||||
|
||||
$$directiveIntrospector(function (name, factory) {
|
||||
if (angular.isArray(factory.$routeConfig)) {
|
||||
factory.$routeConfig.forEach(function (config) {
|
||||
registry.config(name, config);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var router = new RootRouter(registry, location, $routerRootComponent);
|
||||
$rootScope.$watch(function () { return $location.url(); }, function (path) {
|
||||
if (router.lastNavigationAttempt !== path) {
|
||||
router.navigateByUrl(path);
|
||||
}
|
||||
});
|
||||
|
||||
router.subscribe(function () {
|
||||
$rootScope.$broadcast('$routeChangeSuccess', {});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
299
modules/angular1_router/src/ng_outlet.ts
Normal file
299
modules/angular1_router/src/ng_outlet.ts
Normal file
@ -0,0 +1,299 @@
|
||||
///<reference path="../typings/angularjs/angular.d.ts"/>
|
||||
|
||||
/*
|
||||
* decorates $compileProvider so that we have access to routing metadata
|
||||
*/
|
||||
function compilerProviderDecorator($compileProvider,
|
||||
$$directiveIntrospectorProvider: DirectiveIntrospectorProvider) {
|
||||
let directive = $compileProvider.directive;
|
||||
$compileProvider.directive = function(name: string, factory: Function) {
|
||||
$$directiveIntrospectorProvider.register(name, factory);
|
||||
return directive.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* private service that holds route mappings for each controller
|
||||
*/
|
||||
class DirectiveIntrospectorProvider {
|
||||
private directiveBuffer: any[] = [];
|
||||
private directiveFactoriesByName: {[name: string]: Function} = {};
|
||||
private onDirectiveRegistered: (name: string, factory: Function) => any = null;
|
||||
|
||||
register(name: string, factory: Function) {
|
||||
if (angular.isArray(factory)) {
|
||||
factory = factory[factory.length - 1];
|
||||
}
|
||||
this.directiveFactoriesByName[name] = factory;
|
||||
if (this.onDirectiveRegistered) {
|
||||
this.onDirectiveRegistered(name, factory);
|
||||
} else {
|
||||
this.directiveBuffer.push({name: name, factory: factory});
|
||||
}
|
||||
}
|
||||
|
||||
$get() {
|
||||
let fn: any = newOnControllerRegistered => {
|
||||
this.onDirectiveRegistered = newOnControllerRegistered;
|
||||
while (this.directiveBuffer.length > 0) {
|
||||
let directive = this.directiveBuffer.pop();
|
||||
this.onDirectiveRegistered(directive.name, directive.factory);
|
||||
}
|
||||
};
|
||||
|
||||
fn.getTypeByName = name => this.directiveFactoriesByName[name];
|
||||
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name ngOutlet
|
||||
*
|
||||
* @description
|
||||
* An ngOutlet is where resolved content goes.
|
||||
*
|
||||
* ## Use
|
||||
*
|
||||
* ```html
|
||||
* <div ng-outlet="name"></div>
|
||||
* ```
|
||||
*
|
||||
* The value for the `ngOutlet` attribute is optional.
|
||||
*/
|
||||
function ngOutletDirective($animate, $q: ng.IQService, $router) {
|
||||
let rootRouter = $router;
|
||||
|
||||
return {
|
||||
restrict: 'AE',
|
||||
transclude: 'element',
|
||||
terminal: true,
|
||||
priority: 400,
|
||||
require: ['?^^ngOutlet', 'ngOutlet'],
|
||||
link: outletLink,
|
||||
controller: class {},
|
||||
controllerAs: '$$ngOutlet'
|
||||
};
|
||||
|
||||
function outletLink(scope, element, attrs, ctrls, $transclude) {
|
||||
class Outlet {
|
||||
constructor(private controller, private router) {}
|
||||
|
||||
private currentController;
|
||||
private currentInstruction;
|
||||
private currentScope;
|
||||
private currentElement;
|
||||
private previousLeaveAnimation;
|
||||
|
||||
private cleanupLastView() {
|
||||
if (this.previousLeaveAnimation) {
|
||||
$animate.cancel(this.previousLeaveAnimation);
|
||||
this.previousLeaveAnimation = null;
|
||||
}
|
||||
|
||||
if (this.currentScope) {
|
||||
this.currentScope.$destroy();
|
||||
this.currentScope = null;
|
||||
}
|
||||
if (this.currentElement) {
|
||||
this.previousLeaveAnimation = $animate.leave(this.currentElement);
|
||||
this.previousLeaveAnimation.then(() => this.previousLeaveAnimation = null);
|
||||
this.currentElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
reuse(instruction) {
|
||||
let next = $q.when(true);
|
||||
let previousInstruction = this.currentInstruction;
|
||||
this.currentInstruction = instruction;
|
||||
if (this.currentController && this.currentController.$routerOnReuse) {
|
||||
next = $q.when(
|
||||
this.currentController.$routerOnReuse(this.currentInstruction, previousInstruction));
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
routerCanReuse(nextInstruction) {
|
||||
let result;
|
||||
if (!this.currentInstruction ||
|
||||
this.currentInstruction.componentType !== nextInstruction.componentType) {
|
||||
result = false;
|
||||
} else if (this.currentController && this.currentController.$routerCanReuse) {
|
||||
result = this.currentController.$routerCanReuse(nextInstruction, this.currentInstruction);
|
||||
} else {
|
||||
result = nextInstruction === this.currentInstruction ||
|
||||
angular.equals(nextInstruction.params, this.currentInstruction.params);
|
||||
}
|
||||
return $q.when(result);
|
||||
}
|
||||
|
||||
routerCanDeactivate(instruction) {
|
||||
if (this.currentController && this.currentController.$routerCanDeactivate) {
|
||||
return $q.when(
|
||||
this.currentController.$routerCanDeactivate(instruction, this.currentInstruction));
|
||||
}
|
||||
return $q.when(true);
|
||||
}
|
||||
|
||||
deactivate(instruction) {
|
||||
if (this.currentController && this.currentController.$routerOnDeactivate) {
|
||||
return $q.when(
|
||||
this.currentController.$routerOnDeactivate(instruction, this.currentInstruction));
|
||||
}
|
||||
return $q.when();
|
||||
}
|
||||
|
||||
activate(instruction) {
|
||||
let previousInstruction = this.currentInstruction;
|
||||
this.currentInstruction = instruction;
|
||||
|
||||
let componentName = this.controller.$$componentName = instruction.componentType;
|
||||
|
||||
if (typeof componentName !== 'string') {
|
||||
throw new Error('Component is not a string for ' + instruction.urlPath);
|
||||
}
|
||||
|
||||
this.controller.$$routeParams = instruction.params;
|
||||
this.controller.$$template =
|
||||
'<' + dashCase(componentName) + ' router="$$router"></' + dashCase(componentName) + '>';
|
||||
this.controller.$$router = this.router.childRouter(instruction.componentType);
|
||||
|
||||
let newScope = scope.$new();
|
||||
newScope.$$router = this.controller.$$router;
|
||||
|
||||
let clone = $transclude(newScope, clone => {
|
||||
$animate.enter(clone, null, this.currentElement || element);
|
||||
this.cleanupLastView();
|
||||
});
|
||||
|
||||
this.currentElement = clone;
|
||||
this.currentScope = newScope;
|
||||
|
||||
// TODO: prefer the other directive retrieving the controller
|
||||
// by debug mode
|
||||
this.currentController = this.currentElement.children().eq(0).controller(componentName);
|
||||
|
||||
if (this.currentController && this.currentController.$routerOnActivate) {
|
||||
return this.currentController.$routerOnActivate(instruction, previousInstruction);
|
||||
}
|
||||
return $q.when();
|
||||
}
|
||||
}
|
||||
|
||||
let parentCtrl = ctrls[0], myCtrl = ctrls[1],
|
||||
router = (parentCtrl && parentCtrl.$$router) || rootRouter;
|
||||
|
||||
myCtrl.$$currentComponent = null;
|
||||
|
||||
router.registerPrimaryOutlet(new Outlet(myCtrl, router));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This directive is responsible for compiling the contents of ng-outlet
|
||||
*/
|
||||
function ngOutletFillContentDirective($compile) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
priority: -400,
|
||||
require: 'ngOutlet',
|
||||
link: (scope, element, attrs, ctrl) => {
|
||||
let template = ctrl.$$template;
|
||||
element.html(template);
|
||||
let link = $compile(element.contents());
|
||||
link(scope);
|
||||
|
||||
// TODO: move to primary directive
|
||||
let componentInstance = scope[ctrl.$$componentName];
|
||||
if (componentInstance) {
|
||||
ctrl.$$currentComponent = componentInstance;
|
||||
|
||||
componentInstance.$router = ctrl.$$router;
|
||||
componentInstance.$routeParams = ctrl.$$routeParams;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @name ngLink
|
||||
* @description
|
||||
* Lets you link to different parts of the app, and automatically generates hrefs.
|
||||
*
|
||||
* ## Use
|
||||
* The directive uses a simple syntax: `ng-link="componentName({ param: paramValue })"`
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```js
|
||||
* angular.module('myApp', ['ngComponentRouter'])
|
||||
* .controller('AppController', ['$router', function($router) {
|
||||
* $router.config({ path: '/user/:id', component: 'user' });
|
||||
* this.user = { name: 'Brian', id: 123 };
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* ```html
|
||||
* <div ng-controller="AppController as app">
|
||||
* <a ng-link="user({id: app.user.id})">{{app.user.name}}</a>
|
||||
* </div>
|
||||
* ```
|
||||
*/
|
||||
function ngLinkDirective($router, $parse) {
|
||||
let rootRouter = $router;
|
||||
|
||||
return {require: '?^^ngOutlet', restrict: 'A', link: ngLinkDirectiveLinkFn};
|
||||
|
||||
function ngLinkDirectiveLinkFn(scope, element, attrs, ctrl) {
|
||||
let router = (ctrl && ctrl.$$router) || rootRouter;
|
||||
if (!router) {
|
||||
return;
|
||||
}
|
||||
|
||||
let instruction = null;
|
||||
let link = attrs.ngLink || '';
|
||||
|
||||
function getLink(params) {
|
||||
instruction = router.generate(params);
|
||||
return './' + angular.stringifyInstruction(instruction);
|
||||
}
|
||||
|
||||
let routeParamsGetter = $parse(link);
|
||||
// we can avoid adding a watcher if it's a literal
|
||||
if (routeParamsGetter.constant) {
|
||||
let params = routeParamsGetter();
|
||||
element.attr('href', getLink(params));
|
||||
} else {
|
||||
scope.$watch(() => routeParamsGetter(scope), params => element.attr('href', getLink(params)),
|
||||
true);
|
||||
}
|
||||
|
||||
element.on('click', event => {
|
||||
if (event.which !== 1 || !instruction) {
|
||||
return;
|
||||
}
|
||||
|
||||
$router.navigateByInstruction(instruction);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function dashCase(str: string): string {
|
||||
return str.replace(/[A-Z]/g, match => '-' + match.toLowerCase());
|
||||
}
|
||||
|
||||
/*
|
||||
* A module for adding new a routing system Angular 1.
|
||||
*/
|
||||
angular.module('ngComponentRouter', [])
|
||||
.directive('ngOutlet', ngOutletDirective)
|
||||
.directive('ngOutlet', ngOutletFillContentDirective)
|
||||
.directive('ngLink', ngLinkDirective);
|
||||
|
||||
/*
|
||||
* A module for inspecting controller constructors
|
||||
*/
|
||||
angular.module('ng')
|
||||
.provider('$$directiveIntrospector', DirectiveIntrospectorProvider)
|
||||
.config(compilerProviderDecorator);
|
349
modules/angular1_router/src/ng_route_shim.js
vendored
Normal file
349
modules/angular1_router/src/ng_route_shim.js
vendored
Normal file
@ -0,0 +1,349 @@
|
||||
/** @license Copyright 2014-2016 Google, Inc. http://github.com/angular/angular/LICENSE */
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
// keep a reference to compileProvider so we can register new component-directives
|
||||
// on-the-fly based on $routeProvider configuration
|
||||
// TODO: remove this– right now you can only bootstrap one Angular app with this hack
|
||||
var $compileProvider, $q, $injector;
|
||||
|
||||
/**
|
||||
* This module loads services that mimic ngRoute's configuration, and includes
|
||||
* an anchor link directive that intercepts clicks to routing.
|
||||
*
|
||||
* This module is intended to be used as a stop-gap solution for projects upgrading from ngRoute.
|
||||
* It intentionally does not implement all features of ngRoute.
|
||||
*/
|
||||
angular.module('ngRouteShim', [])
|
||||
.provider('$route', $RouteProvider)
|
||||
.config(['$compileProvider', function (compileProvider) {
|
||||
$compileProvider = compileProvider;
|
||||
}])
|
||||
.factory('$routeParams', $routeParamsFactory)
|
||||
.directive('a', anchorLinkDirective)
|
||||
|
||||
// Connects the legacy $routeProvider config shim to Component Router's config.
|
||||
.run(['$route', '$router', function ($route, $router) {
|
||||
$route.$$subscribe(function (routeDefinition) {
|
||||
if (!angular.isArray(routeDefinition)) {
|
||||
routeDefinition = [routeDefinition];
|
||||
}
|
||||
$router.config(routeDefinition);
|
||||
});
|
||||
}]);
|
||||
|
||||
|
||||
/**
|
||||
* A shimmed out provider that provides the same API as ngRoute's $routeProvider, but uses these calls
|
||||
* to configure Component Router.
|
||||
*/
|
||||
function $RouteProvider() {
|
||||
|
||||
var routes = [];
|
||||
var subscriptionFn = null;
|
||||
|
||||
var routeMap = {};
|
||||
|
||||
// Stats for which routes are skipped
|
||||
var skipCount = 0;
|
||||
var successCount = 0;
|
||||
var allCount = 0;
|
||||
|
||||
function consoleMetrics() {
|
||||
return '(' + skipCount + ' skipped / ' + successCount + ' success / ' + allCount + ' total)';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $routeProvider#when
|
||||
*
|
||||
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
||||
* contains redundant trailing slash or is missing one, the route will still match and the
|
||||
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
||||
* route definition.
|
||||
*
|
||||
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
||||
* match.
|
||||
*/
|
||||
this.when = function(path, route) {
|
||||
//copy original route object to preserve params inherited from proto chain
|
||||
var routeCopy = angular.copy(route);
|
||||
|
||||
allCount++;
|
||||
|
||||
if (angular.isDefined(routeCopy.reloadOnSearch)) {
|
||||
console.warn('Route for "' + path + '" uses "reloadOnSearch" which is not implemented.');
|
||||
}
|
||||
if (angular.isDefined(routeCopy.caseInsensitiveMatch)) {
|
||||
console.warn('Route for "' + path + '" uses "caseInsensitiveMatch" which is not implemented.');
|
||||
}
|
||||
|
||||
// use new wildcard format
|
||||
path = reformatWildcardParams(path);
|
||||
|
||||
if (path[path.length - 1] == '*') {
|
||||
skipCount++;
|
||||
console.warn('Route for "' + path + '" ignored because it ends with *. Skipping.', consoleMetrics());
|
||||
return this;
|
||||
}
|
||||
|
||||
if (path.indexOf('?') > -1) {
|
||||
skipCount++;
|
||||
console.warn('Route for "' + path + '" ignored because it has optional parameters. Skipping.', consoleMetrics());
|
||||
return this;
|
||||
}
|
||||
|
||||
if (typeof route.redirectTo == 'function') {
|
||||
skipCount++;
|
||||
console.warn('Route for "' + path + '" ignored because lazy redirecting to a function is not yet implemented. Skipping.', consoleMetrics());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
var routeDefinition = {
|
||||
path: path,
|
||||
data: routeCopy
|
||||
};
|
||||
|
||||
routeMap[path] = routeCopy;
|
||||
|
||||
if (route.redirectTo) {
|
||||
routeDefinition.redirectTo = [routeMap[route.redirectTo].name];
|
||||
} else {
|
||||
if (routeCopy.controller && !routeCopy.controllerAs) {
|
||||
console.warn('Route for "' + path + '" should use "controllerAs".');
|
||||
}
|
||||
|
||||
var directiveName = routeObjToRouteName(routeCopy, path);
|
||||
|
||||
if (!directiveName) {
|
||||
throw new Error('Could not determine a name for route "' + path + '".');
|
||||
}
|
||||
|
||||
routeDefinition.component = directiveName;
|
||||
routeDefinition.name = route.name || upperCase(directiveName);
|
||||
|
||||
var directiveController = routeCopy.controller;
|
||||
|
||||
var directiveDefinition = {
|
||||
scope: false,
|
||||
controller: directiveController,
|
||||
controllerAs: routeCopy.controllerAs,
|
||||
templateUrl: routeCopy.templateUrl,
|
||||
template: routeCopy.template
|
||||
};
|
||||
|
||||
var directiveFactory = function () {
|
||||
return directiveDefinition;
|
||||
};
|
||||
|
||||
// if we have route resolve options, prepare a wrapper controller
|
||||
if (directiveController && routeCopy.resolve) {
|
||||
var originalController = directiveController;
|
||||
var resolvedLocals = {};
|
||||
|
||||
directiveDefinition.controller = ['$injector', '$scope', function ($injector, $scope) {
|
||||
var locals = angular.extend({
|
||||
$scope: $scope
|
||||
}, resolvedLocals);
|
||||
|
||||
var ctrl = $injector.instantiate(originalController, locals);
|
||||
|
||||
if (routeCopy.controllerAs) {
|
||||
locals.$scope[routeCopy.controllerAs] = ctrl;
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
}];
|
||||
|
||||
// we take care of controllerAs in the directive controller wrapper
|
||||
delete directiveDefinition.controllerAs;
|
||||
|
||||
// we resolve the locals in a canActivate block
|
||||
directiveFactory.$canActivate = function() {
|
||||
var locals = angular.extend({}, routeCopy.resolve);
|
||||
|
||||
angular.forEach(locals, function(value, key) {
|
||||
locals[key] = angular.isString(value) ?
|
||||
$injector.get(value) : $injector.invoke(value, null, null, key);
|
||||
});
|
||||
|
||||
return $q.all(locals).then(function (locals) {
|
||||
resolvedLocals = locals;
|
||||
}).then(function () {
|
||||
return true;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// register the dynamically created directive
|
||||
$compileProvider.directive(directiveName, directiveFactory);
|
||||
}
|
||||
if (subscriptionFn) {
|
||||
subscriptionFn(routeDefinition);
|
||||
} else {
|
||||
routes.push(routeDefinition);
|
||||
}
|
||||
successCount++;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.otherwise = function(params) {
|
||||
if (typeof params === 'string') {
|
||||
params = {redirectTo: params};
|
||||
}
|
||||
this.when('/*rest', params);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$q', '$injector', function (q, injector) {
|
||||
$q = q;
|
||||
$injector = injector;
|
||||
|
||||
var $route = {
|
||||
routes: routeMap,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $route#reload
|
||||
*
|
||||
* @description
|
||||
* Causes `$route` service to reload the current route even if
|
||||
* {@link ng.$location $location} hasn't changed.
|
||||
*/
|
||||
reload: function() {
|
||||
throw new Error('Not implemented: $route.reload');
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $route#updateParams
|
||||
*/
|
||||
updateParams: function(newParams) {
|
||||
throw new Error('Not implemented: $route.updateParams');
|
||||
},
|
||||
|
||||
/**
|
||||
* Runs the given `fn` whenever new configs are added.
|
||||
* Only one subscription is allowed.
|
||||
* Passed `fn` is called synchronously.
|
||||
*/
|
||||
$$subscribe: function(fn) {
|
||||
if (subscriptionFn) {
|
||||
throw new Error('only one subscription allowed');
|
||||
}
|
||||
subscriptionFn = fn;
|
||||
subscriptionFn(routes);
|
||||
routes = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Runs a string with stats about many route configs were adapted, and how many were
|
||||
* dropped because they are incompatible.
|
||||
*/
|
||||
$$getStats: consoleMetrics
|
||||
};
|
||||
|
||||
return $route;
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
function $routeParamsFactory($router, $rootScope) {
|
||||
// the identity of this object cannot change
|
||||
var paramsObj = {};
|
||||
|
||||
$rootScope.$on('$routeChangeSuccess', function () {
|
||||
var newParams = $router._currentInstruction && $router._currentInstruction.component.params;
|
||||
|
||||
angular.forEach(paramsObj, function (val, name) {
|
||||
delete paramsObj[name];
|
||||
});
|
||||
angular.forEach(newParams, function (val, name) {
|
||||
paramsObj[name] = val;
|
||||
});
|
||||
});
|
||||
|
||||
return paramsObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows normal anchor links to kick off routing.
|
||||
*/
|
||||
function anchorLinkDirective($router) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function (scope, element) {
|
||||
// If the linked element is not an anchor tag anymore, do nothing
|
||||
if (element[0].nodeName.toLowerCase() !== 'a') {
|
||||
return;
|
||||
}
|
||||
|
||||
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
||||
var hrefAttrName = Object.prototype.toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
||||
'xlink:href' : 'href';
|
||||
|
||||
element.on('click', function (event) {
|
||||
if (event.which !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var href = element.attr(hrefAttrName);
|
||||
if (href && $router.recognize(href)) {
|
||||
$router.navigateByUrl(href);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a route object, attempts to find a unique directive name.
|
||||
*
|
||||
* @param route – route config object passed to $routeProvider.when
|
||||
* @param path – route configuration path
|
||||
* @returns {string|name} – a normalized (camelCase) directive name
|
||||
*/
|
||||
function routeObjToRouteName(route, path) {
|
||||
var name = route.controllerAs;
|
||||
|
||||
var controller = route.controller;
|
||||
if (!name && controller) {
|
||||
if (angular.isArray(controller)) {
|
||||
controller = controller[controller.length - 1];
|
||||
}
|
||||
name = controller.name;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
var segments = path.split('/');
|
||||
name = segments[segments.length - 1];
|
||||
}
|
||||
|
||||
if (name) {
|
||||
name = name + 'AutoCmp';
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
function upperCase(str) {
|
||||
return str.charAt(0).toUpperCase() + str.substr(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Changes "/:foo*" to "/*foo"
|
||||
*/
|
||||
var WILDCARD_PARAM_RE = new RegExp('\\/:([a-z0-9]+)\\*', 'gi');
|
||||
function reformatWildcardParams(path) {
|
||||
return path.replace(WILDCARD_PARAM_RE, function (m, m1) {
|
||||
return '/*' + m1;
|
||||
});
|
||||
}
|
||||
|
||||
}());
|
38
modules/angular1_router/test/directive_introspector_spec.js
vendored
Normal file
38
modules/angular1_router/test/directive_introspector_spec.js
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
describe('$$directiveIntrospector', function () {
|
||||
|
||||
var $compileProvider;
|
||||
|
||||
beforeEach(function() {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function(_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the introspector function whenever a directive factory is registered', inject(function ($$directiveIntrospector) {
|
||||
var spy = jasmine.createSpy();
|
||||
$$directiveIntrospector(spy);
|
||||
function myDir(){}
|
||||
$compileProvider.directive('myDir', myDir);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('myDir', myDir);
|
||||
}));
|
||||
|
||||
it('should call the introspector function whenever a directive factory is registered with array annotations', inject(function ($$directiveIntrospector) {
|
||||
var spy = jasmine.createSpy();
|
||||
$$directiveIntrospector(spy);
|
||||
function myDir(){}
|
||||
$compileProvider.directive('myDir', ['foo', myDir]);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('myDir', myDir);
|
||||
}));
|
||||
|
||||
it('should retrieve a factory based on directive name', inject(function ($$directiveIntrospector) {
|
||||
function myDir(){}
|
||||
$compileProvider.directive('myDir', ['foo', myDir]);
|
||||
expect($$directiveIntrospector.getTypeByName('myDir')).toBe(myDir);
|
||||
}));
|
||||
});
|
102
modules/angular1_router/test/integration/animation_spec.js
vendored
Normal file
102
modules/angular1_router/test/integration/animation_spec.js
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
'use strict';
|
||||
|
||||
describe('ngOutlet animations', function () {
|
||||
var elt,
|
||||
$animate,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$compileProvider;
|
||||
|
||||
beforeEach(function () {
|
||||
module('ng');
|
||||
module('ngAnimate');
|
||||
module('ngAnimateMock');
|
||||
module('ngComponentRouter');
|
||||
module(function (_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
});
|
||||
|
||||
inject(function (_$animate_, _$compile_, _$rootScope_, _$router_) {
|
||||
$animate = _$animate_;
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
});
|
||||
|
||||
registerComponent('userCmp', {
|
||||
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
expect($animate.queue).toEqual([]);
|
||||
});
|
||||
|
||||
it('should work in a simple case', function () {
|
||||
var item;
|
||||
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: 'userCmp' }
|
||||
]);
|
||||
|
||||
$router.navigateByUrl('/user/brian');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('hello brian');
|
||||
|
||||
// "user" component enters
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('enter');
|
||||
|
||||
// navigate to pete
|
||||
$router.navigateByUrl('/user/pete');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('hello pete');
|
||||
|
||||
// "user pete" component enters
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('enter');
|
||||
expect(item.element.text()).toBe('hello pete');
|
||||
|
||||
// "user brian" component leaves
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('leave');
|
||||
expect(item.element.text()).toBe('hello brian');
|
||||
});
|
||||
|
||||
|
||||
function registerComponent(name, options) {
|
||||
var controller = options.controller || function () {};
|
||||
|
||||
['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
|
||||
if (options[hookName]) {
|
||||
controller.prototype[hookName] = options[hookName];
|
||||
}
|
||||
});
|
||||
|
||||
function factory() {
|
||||
return {
|
||||
template: options.template || '',
|
||||
controllerAs: name,
|
||||
controller: controller
|
||||
};
|
||||
}
|
||||
|
||||
if (options.$canActivate) {
|
||||
factory.$canActivate = options.$canActivate;
|
||||
}
|
||||
if (options.$routeConfig) {
|
||||
factory.$routeConfig = options.$routeConfig;
|
||||
}
|
||||
|
||||
$compileProvider.directive(name, factory);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
});
|
487
modules/angular1_router/test/integration/lifecycle_hook_spec.js
vendored
Normal file
487
modules/angular1_router/test/integration/lifecycle_hook_spec.js
vendored
Normal file
@ -0,0 +1,487 @@
|
||||
'use strict';
|
||||
|
||||
describe('Navigation lifecycle', function () {
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$compileProvider;
|
||||
|
||||
beforeEach(function () {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function (_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
});
|
||||
|
||||
inject(function (_$compile_, _$rootScope_, _$router_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
});
|
||||
|
||||
registerComponent('oneCmp', {
|
||||
template: '<div>{{oneCmp.number}}</div>',
|
||||
controller: function () {this.number = 'one'}
|
||||
});
|
||||
registerComponent('twoCmp', {
|
||||
template: '<div><a ng-link="[\'/Two\']">{{twoCmp.number}}</a></div>',
|
||||
controller: function () {this.number = 'two'}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should run the activate hook of controllers', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
registerComponent('activateCmp', {
|
||||
template: '<p>hello</p>',
|
||||
$routerOnActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'activateCmp' }
|
||||
]);
|
||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('should pass instruction into the activate hook of a controller', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
registerComponent('userCmp', {
|
||||
$routerOnActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: 'userCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user/brian');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).toHaveBeenCalledWith(instructionFor('userCmp'), undefined);
|
||||
});
|
||||
|
||||
|
||||
it('should pass previous instruction into the activate hook of a controller', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
var activate = registerComponent('activateCmp', {
|
||||
template: 'hi',
|
||||
$routerOnActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: 'oneCmp' },
|
||||
{ path: '/post/:id', component: 'activateCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user/brian');
|
||||
$rootScope.$digest();
|
||||
$router.navigateByUrl('/post/123');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalledWith(instructionFor('activateCmp'),
|
||||
instructionFor('oneCmp'));
|
||||
});
|
||||
|
||||
it('should inject $scope into the controller constructor', function () {
|
||||
var injectedScope;
|
||||
registerComponent('userCmp', {
|
||||
template: '',
|
||||
controller: function ($scope) {
|
||||
injectedScope = $scope;
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user', component: 'userCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(injectedScope).toBeDefined();
|
||||
});
|
||||
|
||||
|
||||
it('should run the deactivate hook of controllers', function () {
|
||||
var spy = jasmine.createSpy('deactivate');
|
||||
registerComponent('deactivateCmp', {
|
||||
$routerOnDeactivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'deactivateCmp' },
|
||||
{ path: '/b', component: 'oneCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
$router.navigateByUrl('/b');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('should pass instructions into the deactivate hook of controllers', function () {
|
||||
var spy = jasmine.createSpy('deactivate');
|
||||
registerComponent('deactivateCmp', {
|
||||
$routerOnDeactivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: 'deactivateCmp' },
|
||||
{ path: '/post/:id', component: 'oneCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user/brian');
|
||||
$rootScope.$digest();
|
||||
$router.navigateByUrl('/post/123');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalledWith(instructionFor('oneCmp'),
|
||||
instructionFor('deactivateCmp'));
|
||||
});
|
||||
|
||||
|
||||
it('should run the deactivate hook before the activate hook', function () {
|
||||
var log = [];
|
||||
|
||||
registerComponent('activateCmp', {
|
||||
$routerOnActivate: function () {
|
||||
log.push('activate');
|
||||
}
|
||||
});
|
||||
|
||||
registerComponent('deactivateCmp', {
|
||||
$routerOnDeactivate: function () {
|
||||
log.push('deactivate');
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'deactivateCmp' },
|
||||
{ path: '/b', component: 'activateCmp' }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
$router.navigateByUrl('/b');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(log).toEqual(['deactivate', 'activate']);
|
||||
});
|
||||
|
||||
it('should reuse a component when the routerCanReuse hook returns true', function () {
|
||||
var log = [];
|
||||
var cmpInstanceCount = 0;
|
||||
|
||||
function ReuseCmp() {
|
||||
cmpInstanceCount++;
|
||||
}
|
||||
|
||||
registerComponent('reuseCmp', {
|
||||
template: 'reuse {<ng-outlet></ng-outlet>}',
|
||||
$routeConfig: [
|
||||
{path: '/a', component: 'oneCmp'},
|
||||
{path: '/b', component: 'twoCmp'}
|
||||
],
|
||||
controller: ReuseCmp,
|
||||
$routerCanReuse: function () {
|
||||
return true;
|
||||
},
|
||||
$routerOnReuse: function (next, prev) {
|
||||
log.push('reuse: ' + prev.urlPath + ' -> ' + next.urlPath);
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/on-reuse/:number/...', component: 'reuseCmp' },
|
||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigateByUrl('/on-reuse/1/a');
|
||||
$rootScope.$digest();
|
||||
expect(log).toEqual([]);
|
||||
expect(cmpInstanceCount).toBe(1);
|
||||
expect(elt.text()).toBe('outer { reuse {one} }');
|
||||
|
||||
$router.navigateByUrl('/on-reuse/2/b');
|
||||
$rootScope.$digest();
|
||||
expect(log).toEqual(['reuse: on-reuse/1 -> on-reuse/2']);
|
||||
expect(cmpInstanceCount).toBe(1);
|
||||
expect(elt.text()).toBe('outer { reuse {two} }');
|
||||
});
|
||||
|
||||
|
||||
it('should not reuse a component when the routerCanReuse hook returns false', function () {
|
||||
var log = [];
|
||||
var cmpInstanceCount = 0;
|
||||
|
||||
function NeverReuseCmp() {
|
||||
cmpInstanceCount++;
|
||||
}
|
||||
registerComponent('reuseCmp', {
|
||||
template: 'reuse {<ng-outlet></ng-outlet>}',
|
||||
$routeConfig: [
|
||||
{path: '/a', component: 'oneCmp'},
|
||||
{path: '/b', component: 'twoCmp'}
|
||||
],
|
||||
controller: NeverReuseCmp,
|
||||
$routerCanReuse: function () {
|
||||
return false;
|
||||
},
|
||||
$routerOnReuse: function (next, prev) {
|
||||
log.push('reuse: ' + prev.urlPath + ' -> ' + next.urlPath);
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/never-reuse/:number/...', component: 'reuseCmp' },
|
||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigateByUrl('/never-reuse/1/a');
|
||||
$rootScope.$digest();
|
||||
expect(log).toEqual([]);
|
||||
expect(cmpInstanceCount).toBe(1);
|
||||
expect(elt.text()).toBe('outer { reuse {one} }');
|
||||
|
||||
$router.navigateByUrl('/never-reuse/2/b');
|
||||
$rootScope.$digest();
|
||||
expect(log).toEqual([]);
|
||||
expect(cmpInstanceCount).toBe(2);
|
||||
expect(elt.text()).toBe('outer { reuse {two} }');
|
||||
});
|
||||
|
||||
|
||||
// TODO: need to solve getting ahold of canActivate hook
|
||||
it('should not activate a component when canActivate returns false', function () {
|
||||
var canActivateSpy = jasmine.createSpy('canActivate').and.returnValue(false);
|
||||
var spy = jasmine.createSpy('activate');
|
||||
registerComponent('activateCmp', {
|
||||
$canActivate: canActivateSpy,
|
||||
$routerOnActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'activateCmp' }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
expect(elt.text()).toBe('outer { }');
|
||||
});
|
||||
|
||||
|
||||
it('should activate a component when canActivate returns true', function () {
|
||||
var activateSpy = jasmine.createSpy('activate');
|
||||
var canActivateSpy = jasmine.createSpy('canActivate').and.returnValue(true);
|
||||
registerComponent('activateCmp', {
|
||||
template: 'hi',
|
||||
$canActivate: canActivateSpy,
|
||||
$routerOnActivate: activateSpy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'activateCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(canActivateSpy).toHaveBeenCalled();
|
||||
expect(activateSpy).toHaveBeenCalled();
|
||||
expect(elt.text()).toBe('hi');
|
||||
});
|
||||
|
||||
|
||||
it('should activate a component when canActivate returns a resolved promise', inject(function ($q) {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
registerComponent('activateCmp', {
|
||||
template: 'hi',
|
||||
$canActivate: function () {
|
||||
return $q.when(true);
|
||||
},
|
||||
$routerOnActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'activateCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(elt.text()).toBe('hi');
|
||||
}));
|
||||
|
||||
|
||||
it('should inject into the canActivate hook of controllers', inject(function ($http) {
|
||||
var spy = jasmine.createSpy('canActivate').and.returnValue(true);
|
||||
registerComponent('activateCmp', {
|
||||
$canActivate: spy
|
||||
});
|
||||
|
||||
spy.$inject = ['$nextInstruction', '$http'];
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: 'activateCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user/brian');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
var args = spy.calls.mostRecent().args;
|
||||
expect(args[0].params).toEqual({name: 'brian'});
|
||||
expect(args[1]).toBe($http);
|
||||
}));
|
||||
|
||||
|
||||
it('should not navigate when routerCanDeactivate returns false', function () {
|
||||
registerComponent('activateCmp', {
|
||||
template: 'hi',
|
||||
$routerCanDeactivate: function () {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'activateCmp' },
|
||||
{ path: '/b', component: 'oneCmp' }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('outer { hi }');
|
||||
|
||||
$router.navigateByUrl('/b');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('outer { hi }');
|
||||
});
|
||||
|
||||
|
||||
it('should navigate when routerCanDeactivate returns true', function () {
|
||||
registerComponent('activateCmp', {
|
||||
template: 'hi',
|
||||
$routerCanDeactivate: function () {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'activateCmp' },
|
||||
{ path: '/b', component: 'oneCmp' }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('outer { hi }');
|
||||
|
||||
$router.navigateByUrl('/b');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('outer { one }');
|
||||
});
|
||||
|
||||
|
||||
it('should activate a component when canActivate returns true', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
registerComponent('activateCmp', {
|
||||
template: 'hi',
|
||||
$canActivate: function () {
|
||||
return true;
|
||||
},
|
||||
$routerOnActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'activateCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(elt.text()).toBe('hi');
|
||||
});
|
||||
|
||||
|
||||
it('should pass instructions into the routerCanDeactivate hook of controllers', function () {
|
||||
var spy = jasmine.createSpy('routerCanDeactivate').and.returnValue(true);
|
||||
registerComponent('deactivateCmp', {
|
||||
$routerCanDeactivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: 'deactivateCmp' },
|
||||
{ path: '/post/:id', component: 'oneCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user/brian');
|
||||
$rootScope.$digest();
|
||||
$router.navigateByUrl('/post/123');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalledWith(instructionFor('oneCmp'),
|
||||
instructionFor('deactivateCmp'));
|
||||
});
|
||||
|
||||
|
||||
function registerComponent(name, options) {
|
||||
var controller = options.controller || function () {};
|
||||
|
||||
['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
|
||||
if (options[hookName]) {
|
||||
controller.prototype[hookName] = options[hookName];
|
||||
}
|
||||
});
|
||||
|
||||
function factory() {
|
||||
return {
|
||||
template: options.template || '',
|
||||
controllerAs: name,
|
||||
controller: controller
|
||||
};
|
||||
}
|
||||
|
||||
if (options.$canActivate) {
|
||||
factory.$canActivate = options.$canActivate;
|
||||
}
|
||||
if (options.$routeConfig) {
|
||||
factory.$routeConfig = options.$routeConfig;
|
||||
}
|
||||
|
||||
$compileProvider.directive(name, factory);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
|
||||
function instructionFor(componentType) {
|
||||
return jasmine.objectContaining({componentType: componentType});
|
||||
}
|
||||
});
|
355
modules/angular1_router/test/integration/navigation_spec.js
vendored
Normal file
355
modules/angular1_router/test/integration/navigation_spec.js
vendored
Normal file
@ -0,0 +1,355 @@
|
||||
'use strict';
|
||||
|
||||
describe('navigation', function () {
|
||||
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$compileProvider;
|
||||
|
||||
beforeEach(function () {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function (_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
});
|
||||
|
||||
inject(function (_$compile_, _$rootScope_, _$router_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
});
|
||||
|
||||
registerDirective('userCmp', {
|
||||
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
|
||||
});
|
||||
registerDirective('oneCmp', {
|
||||
template: '<div>{{oneCmp.number}}</div>',
|
||||
controller: function () {this.number = 'one'}
|
||||
});
|
||||
registerDirective('twoCmp', {
|
||||
template: '<div>{{twoCmp.number}}</div>',
|
||||
controller: function () {this.number = 'two'}
|
||||
});
|
||||
registerComponent('threeCmp', {
|
||||
template: '<div>{{$ctrl.number}}</div>',
|
||||
controller: function () {this.number = 'three'}
|
||||
});
|
||||
registerComponent('getParams', {
|
||||
template: '<div>{{$ctrl.params.x}}</div>',
|
||||
controller: function () {
|
||||
this.$routerOnActivate = function(next) {
|
||||
this.params = next.params;
|
||||
};
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
it('should work in a simple case', function () {
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/', component: 'oneCmp' }
|
||||
]);
|
||||
|
||||
$router.navigateByUrl('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('one');
|
||||
});
|
||||
|
||||
|
||||
it('should work with components created by the `mod.component()` helper', function () {
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/', component: 'threeCmp' }
|
||||
]);
|
||||
|
||||
$router.navigateByUrl('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('three');
|
||||
});
|
||||
|
||||
|
||||
it('should navigate between components with different parameters', function () {
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: 'userCmp' }
|
||||
]);
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.navigateByUrl('/user/brian');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('hello brian');
|
||||
|
||||
$router.navigateByUrl('/user/igor');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('hello igor');
|
||||
});
|
||||
|
||||
|
||||
it('should reuse a parent when navigating between child components with different parameters', function () {
|
||||
var instanceCount = 0;
|
||||
function ParentController() {
|
||||
instanceCount += 1;
|
||||
}
|
||||
registerDirective('parentCmp', {
|
||||
template: 'parent { <ng-outlet></ng-outlet> }',
|
||||
$routeConfig: [
|
||||
{ path: '/user/:name', component: 'userCmp' }
|
||||
],
|
||||
controller: ParentController
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/parent/...', component: 'parentCmp' }
|
||||
]);
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.navigateByUrl('/parent/user/brian');
|
||||
$rootScope.$digest();
|
||||
expect(instanceCount).toBe(1);
|
||||
expect(elt.text()).toBe('parent { hello brian }');
|
||||
|
||||
$router.navigateByUrl('/parent/user/igor');
|
||||
$rootScope.$digest();
|
||||
expect(instanceCount).toBe(1);
|
||||
expect(elt.text()).toBe('parent { hello igor }');
|
||||
});
|
||||
|
||||
|
||||
it('should work with nested outlets', function () {
|
||||
registerDirective('childCmp', {
|
||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
||||
$routeConfig: [
|
||||
{ path: '/b', component: 'oneCmp' }
|
||||
]
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a/...', component: 'childCmp' }
|
||||
]);
|
||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
||||
|
||||
$router.navigateByUrl('/a/b');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('outer { inner { one } }');
|
||||
});
|
||||
|
||||
it('should work when parent route has empty path', inject(function ($location) {
|
||||
registerComponent('childCmp', {
|
||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
||||
$routeConfig: [
|
||||
{ path: '/b', component: 'oneCmp' }
|
||||
]
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/...', component: 'childCmp' }
|
||||
]);
|
||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
||||
|
||||
$router.navigateByUrl('/b');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('outer { inner { one } }');
|
||||
expect($location.path()).toBe('/b');
|
||||
}));
|
||||
|
||||
|
||||
it('should work with recursive nested outlets', function () {
|
||||
registerDirective('recurCmp', {
|
||||
template: '<div>recur { <div ng-outlet></div> }</div>',
|
||||
$routeConfig: [
|
||||
{ path: '/recur', component: 'recurCmp' },
|
||||
{ path: '/end', component: 'oneCmp' }
|
||||
]});
|
||||
|
||||
$router.config([
|
||||
{ path: '/recur', component: 'recurCmp' },
|
||||
{ path: '/', component: 'oneCmp' }
|
||||
]);
|
||||
|
||||
compile('<div>root { <div ng-outlet></div> }</div>');
|
||||
$router.navigateByUrl('/recur/recur/end');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('root { one }');
|
||||
});
|
||||
|
||||
|
||||
it('should change location path', inject(function ($location) {
|
||||
$router.config([
|
||||
{ path: '/user', component: 'userCmp' }
|
||||
]);
|
||||
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/user');
|
||||
}));
|
||||
|
||||
|
||||
it('should pass through query terms to the location', inject(function ($location) {
|
||||
$router.config([
|
||||
{ path: '/user', component: 'userCmp' }
|
||||
]);
|
||||
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user?x=y');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/user');
|
||||
expect($location.search()).toEqual({ x: 'y'});
|
||||
}));
|
||||
|
||||
|
||||
it('should change location to the canonical route', inject(function ($location) {
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/', redirectTo: ['/User'] },
|
||||
{ path: '/user', component: 'userCmp', name: 'User' }
|
||||
]);
|
||||
|
||||
$router.navigateByUrl('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/user');
|
||||
}));
|
||||
|
||||
|
||||
it('should change location to the canonical route with nested components', inject(function ($location) {
|
||||
registerDirective('childRouter', {
|
||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
||||
$routeConfig: [
|
||||
{ path: '/new-child', component: 'oneCmp', name: 'NewChild'},
|
||||
{ path: '/new-child-two', component: 'twoCmp', name: 'NewChildTwo'}
|
||||
]
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/old-parent/old-child', redirectTo: ['/NewParent', 'NewChild'] },
|
||||
{ path: '/old-parent/old-child-two', redirectTo: ['/NewParent', 'NewChildTwo'] },
|
||||
{ path: '/new-parent/...', component: 'childRouter', name: 'NewParent' }
|
||||
]);
|
||||
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/old-parent/old-child');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/new-parent/new-child');
|
||||
expect(elt.text()).toBe('inner { one }');
|
||||
|
||||
$router.navigateByUrl('/old-parent/old-child-two');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/new-parent/new-child-two');
|
||||
expect(elt.text()).toBe('inner { two }');
|
||||
}));
|
||||
|
||||
|
||||
it('should navigate when the location path changes', inject(function ($location) {
|
||||
$router.config([
|
||||
{ path: '/one', component: 'oneCmp' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$location.path('/one');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('one');
|
||||
}));
|
||||
|
||||
|
||||
it('should navigate when the location query changes', inject(function ($location) {
|
||||
$router.config([
|
||||
{ path: '/get/params', component: 'getParams' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$location.url('/get/params?x=y');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('y');
|
||||
}));
|
||||
|
||||
|
||||
it('should expose a "navigating" property on $router', inject(function ($q) {
|
||||
var defer;
|
||||
registerDirective('pendingActivate', {
|
||||
$canActivate: function () {
|
||||
defer = $q.defer();
|
||||
return defer.promise;
|
||||
}
|
||||
});
|
||||
$router.config([
|
||||
{ path: '/pending-activate', component: 'pendingActivate' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/pending-activate');
|
||||
$rootScope.$digest();
|
||||
expect($router.navigating).toBe(true);
|
||||
defer.resolve();
|
||||
$rootScope.$digest();
|
||||
expect($router.navigating).toBe(false);
|
||||
}));
|
||||
|
||||
function registerDirective(name, options) {
|
||||
function factory() {
|
||||
return {
|
||||
template: options.template || '',
|
||||
controllerAs: name,
|
||||
controller: getController(options)
|
||||
};
|
||||
}
|
||||
applyStaticProperties(factory, options);
|
||||
$compileProvider.directive(name, factory);
|
||||
}
|
||||
|
||||
function registerComponent(name, options) {
|
||||
|
||||
var definition = {
|
||||
template: options.template || '',
|
||||
controller: getController(options),
|
||||
}
|
||||
applyStaticProperties(definition, options);
|
||||
$compileProvider.component(name, definition);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
|
||||
function getController(options) {
|
||||
var controller = options.controller || function () {};
|
||||
[
|
||||
'$routerOnActivate', '$routerOnDeactivate',
|
||||
'$routerOnReuse', '$routerCanReuse',
|
||||
'$routerCanDeactivate'
|
||||
].forEach(function (hookName) {
|
||||
if (options[hookName]) {
|
||||
controller.prototype[hookName] = options[hookName];
|
||||
}
|
||||
});
|
||||
return controller;
|
||||
}
|
||||
|
||||
function applyStaticProperties(target, options) {
|
||||
['$canActivate', '$routeConfig'].forEach(function(property) {
|
||||
if (options[property]) {
|
||||
target[property] = options[property];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
148
modules/angular1_router/test/integration/router_spec.js
vendored
Normal file
148
modules/angular1_router/test/integration/router_spec.js
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
'use strict';
|
||||
|
||||
describe('router', function () {
|
||||
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$compileProvider;
|
||||
|
||||
beforeEach(function () {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function($provide) {
|
||||
$provide.value('$routerRootComponent', 'app');
|
||||
});
|
||||
module(function (_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
});
|
||||
|
||||
inject(function (_$compile_, _$rootScope_, _$router_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with a provided root component', inject(function($location) {
|
||||
registerComponent('homeCmp', {
|
||||
template: 'Home'
|
||||
});
|
||||
|
||||
registerComponent('app', {
|
||||
template: '<div ng-outlet></div>',
|
||||
$routeConfig: [
|
||||
{ path: '/', component: 'homeCmp' }
|
||||
]
|
||||
});
|
||||
|
||||
compile('<app></app>');
|
||||
|
||||
$location.path('/');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('Home');
|
||||
}));
|
||||
|
||||
it('should bind the component to the current router', inject(function($location) {
|
||||
var router;
|
||||
registerComponent('homeCmp', {
|
||||
bindings: { router: '=' },
|
||||
controller: function($scope, $element) {
|
||||
this.$routerOnActivate = function() {
|
||||
router = this.router;
|
||||
};
|
||||
},
|
||||
template: 'Home'
|
||||
});
|
||||
|
||||
registerComponent('app', {
|
||||
template: '<div ng-outlet></div>',
|
||||
$routeConfig: [
|
||||
{ path: '/', component: 'homeCmp' }
|
||||
]
|
||||
});
|
||||
|
||||
compile('<app></app>');
|
||||
|
||||
$location.path('/');
|
||||
$rootScope.$digest();
|
||||
var homeElement = elt.find('home-cmp');
|
||||
expect(homeElement.text()).toBe('Home');
|
||||
expect(homeElement.isolateScope().$ctrl.router).toBeDefined();
|
||||
expect(router).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should work when an async route is provided route data', inject(function($location, $q) {
|
||||
registerDirective('homeCmp', {
|
||||
template: 'Home ({{homeCmp.isAdmin}})',
|
||||
$routerOnActivate: function(next, prev) {
|
||||
this.isAdmin = next.routeData.data.isAdmin;
|
||||
}
|
||||
});
|
||||
|
||||
registerDirective('app', {
|
||||
template: '<div ng-outlet></div>',
|
||||
$routeConfig: [
|
||||
{ path: '/', loader: function() { return $q.when('homeCmp'); }, data: { isAdmin: true } }
|
||||
]
|
||||
});
|
||||
|
||||
compile('<app></app>');
|
||||
|
||||
$location.path('/');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('Home (true)');
|
||||
}));
|
||||
|
||||
function registerDirective(name, options) {
|
||||
function factory() {
|
||||
return {
|
||||
template: options.template || '',
|
||||
controllerAs: name,
|
||||
controller: getController(options)
|
||||
};
|
||||
}
|
||||
applyStaticProperties(factory, options);
|
||||
$compileProvider.directive(name, factory);
|
||||
}
|
||||
|
||||
function registerComponent(name, options) {
|
||||
|
||||
var definition = {
|
||||
bindings: options.bindings,
|
||||
template: options.template || '',
|
||||
controller: getController(options),
|
||||
}
|
||||
applyStaticProperties(definition, options);
|
||||
$compileProvider.component(name, definition);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
|
||||
function getController(options) {
|
||||
var controller = options.controller || function () {};
|
||||
[
|
||||
'$routerOnActivate', '$routerOnDeactivate',
|
||||
'$routerOnReuse', '$routerCanReuse',
|
||||
'$routerCanDeactivate'
|
||||
].forEach(function (hookName) {
|
||||
if (options[hookName]) {
|
||||
controller.prototype[hookName] = options[hookName];
|
||||
}
|
||||
});
|
||||
return controller;
|
||||
}
|
||||
|
||||
function applyStaticProperties(target, options) {
|
||||
['$canActivate', '$routeConfig'].forEach(function(property) {
|
||||
if (options[property]) {
|
||||
target[property] = options[property];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
183
modules/angular1_router/test/integration/shim_spec.js
vendored
Normal file
183
modules/angular1_router/test/integration/shim_spec.js
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
'use strict';
|
||||
|
||||
describe('ngRoute shim', function () {
|
||||
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$compileProvider,
|
||||
$routeProvider;
|
||||
|
||||
beforeEach(function () {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module('ngRouteShim');
|
||||
module(function (_$compileProvider_, _$routeProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
$routeProvider = _$routeProvider_;
|
||||
});
|
||||
|
||||
inject(function (_$compile_, _$rootScope_, _$router_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
});
|
||||
});
|
||||
|
||||
it('should work in a simple case', function () {
|
||||
$routeProvider.when('/', {
|
||||
controller: function OneController() {
|
||||
this.number = 'one';
|
||||
},
|
||||
controllerAs: 'oneCmp',
|
||||
template: '{{oneCmp.number}}'
|
||||
});
|
||||
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.navigateByUrl('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('one');
|
||||
});
|
||||
|
||||
it('should adapt routes with templateUrl', inject(function ($templateCache) {
|
||||
$routeProvider.when('/', {
|
||||
controller: function OneController() {
|
||||
this.number = 'one';
|
||||
},
|
||||
controllerAs: 'oneCmp',
|
||||
templateUrl: '/foo'
|
||||
});
|
||||
|
||||
$templateCache.put('/foo', [200, '{{oneCmp.number}}', {}]);
|
||||
|
||||
compile('root {<ng-outlet></ng-outlet>}');
|
||||
|
||||
$router.navigateByUrl('/');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('root {one}');
|
||||
}));
|
||||
|
||||
it('should adapt routes using the "resolve" option', inject(function ($q) {
|
||||
$routeProvider.when('/', {
|
||||
controller: function TestController(resolvedService) {
|
||||
this.resolvedValue = resolvedService;
|
||||
},
|
||||
controllerAs: 'testCmp',
|
||||
resolve: {
|
||||
resolvedService: function () {
|
||||
return $q.when(42);
|
||||
}
|
||||
},
|
||||
template: 'value: {{testCmp.resolvedValue}}'
|
||||
});
|
||||
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.navigateByUrl('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('value: 42');
|
||||
}));
|
||||
|
||||
it('should adapt routes with params', function () {
|
||||
$routeProvider.when('/user/:name', {
|
||||
controller: function UserController($routeParams) {
|
||||
this.$routeParams = $routeParams;
|
||||
},
|
||||
controllerAs: 'userCmp',
|
||||
template: 'hello {{userCmp.$routeParams.name}}'
|
||||
});
|
||||
$rootScope.$digest();
|
||||
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.navigateByUrl('/user/brian');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('hello brian');
|
||||
|
||||
$router.navigateByUrl('/user/igor');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('hello igor');
|
||||
});
|
||||
|
||||
it('should adapt routes with wildcard params', function () {
|
||||
$routeProvider.when('/home/:params*', {
|
||||
controller: function UserController($routeParams) {
|
||||
this.$routeParams = $routeParams;
|
||||
},
|
||||
controllerAs: 'homeCmp',
|
||||
template: 'rest: {{homeCmp.$routeParams.params}}'
|
||||
});
|
||||
$rootScope.$digest();
|
||||
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.navigateByUrl('/home/foo/bar/123');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('rest: foo/bar/123');
|
||||
});
|
||||
|
||||
it('should warn about and ignore routes with optional params', function () {
|
||||
spyOn(console, 'warn');
|
||||
$routeProvider.when('/home/:params?', {
|
||||
template: 'home'
|
||||
});
|
||||
$rootScope.$digest();
|
||||
|
||||
compile('root {<ng-outlet></ng-outlet>}');
|
||||
|
||||
$router.navigateByUrl('/home/test');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('root {}');
|
||||
expect(console.warn)
|
||||
.toHaveBeenCalledWith('Route for "/home/:params?" ignored because it has optional parameters. Skipping.',
|
||||
'(1 skipped / 0 success / 1 total)');
|
||||
});
|
||||
|
||||
it('should adapt routes with redirects', inject(function ($location) {
|
||||
$routeProvider
|
||||
.when('/home', {
|
||||
template: 'welcome home!',
|
||||
name: 'Home'
|
||||
})
|
||||
.when('/', {
|
||||
redirectTo: '/home'
|
||||
});
|
||||
$rootScope.$digest();
|
||||
|
||||
compile('root {<ng-outlet></ng-outlet>}');
|
||||
|
||||
$router.navigateByUrl('/');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('root {welcome home!}');
|
||||
expect($location.path()).toBe('/home');
|
||||
}));
|
||||
|
||||
//TODO: this is broken in recognition. un-xit this when https://github.com/angular/angular/issues/4133 is fixed
|
||||
xit('should adapt "otherwise" routes', inject(function ($location) {
|
||||
$routeProvider
|
||||
.when('/home', {
|
||||
template: 'welcome home!'
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: '/home'
|
||||
});
|
||||
$rootScope.$digest();
|
||||
|
||||
compile('root {<ng-outlet></ng-outlet>}');
|
||||
|
||||
$router.navigateByUrl('/somewhere');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('root {welcome home!}');
|
||||
expect($location.path()).toBe('/home');
|
||||
}));
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
});
|
170
modules/angular1_router/test/ng_link_spec.js
vendored
Normal file
170
modules/angular1_router/test/ng_link_spec.js
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
'use strict';
|
||||
|
||||
describe('ngLink', function () {
|
||||
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$compileProvider;
|
||||
|
||||
beforeEach(function () {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function (_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
});
|
||||
|
||||
inject(function (_$compile_, _$rootScope_, _$router_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
});
|
||||
|
||||
registerComponent('userCmp', '<div>hello {{userCmp.$routeParams.name}}</div>', function () {});
|
||||
registerComponent('oneCmp', '<div>{{oneCmp.number}}</div>', function () {this.number = 'one'});
|
||||
registerComponent('twoCmp', '<div><a ng-link="[\'/Two\']">{{twoCmp.number}}</a></div>', function () {this.number = 'two'});
|
||||
});
|
||||
|
||||
|
||||
it('should allow linking from the parent to the child', function () {
|
||||
$router.config([
|
||||
{ path: '/a', component: 'oneCmp' },
|
||||
{ path: '/b', component: 'twoCmp', name: 'Two' }
|
||||
]);
|
||||
compile('<a ng-link="[\'/Two\']">link</a> | outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./b');
|
||||
});
|
||||
|
||||
it('should allow linking from the child and the parent', function () {
|
||||
$router.config([
|
||||
{ path: '/a', component: 'oneCmp' },
|
||||
{ path: '/b', component: 'twoCmp', name: 'Two' }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigateByUrl('/b');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./b');
|
||||
});
|
||||
|
||||
|
||||
it('should allow params in routerLink directive', function () {
|
||||
registerComponent('twoLinkCmp', '<div><a ng-link="[\'/Two\', {param: \'lol\'}]">{{twoLinkCmp.number}}</a></div>', function () {this.number = 'two'});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: 'twoLinkCmp' },
|
||||
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./b/lol');
|
||||
});
|
||||
|
||||
|
||||
it('should update the href of links with bound params', function () {
|
||||
registerComponent('twoLinkCmp', '<div><a ng-link="[\'/Two\', {param: twoLinkCmp.number}]">{{twoLinkCmp.number}}</a></div>', function () {this.number = 'param'});
|
||||
$router.config([
|
||||
{ path: '/a', component: 'twoLinkCmp' },
|
||||
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./b/param');
|
||||
});
|
||||
|
||||
|
||||
it('should navigate on left-mouse click when a link url matches a route', function () {
|
||||
$router.config([
|
||||
{ path: '/', component: 'oneCmp' },
|
||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
||||
]);
|
||||
|
||||
compile('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link | one');
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./two');
|
||||
|
||||
elt.find('a')[0].click();
|
||||
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link | two');
|
||||
});
|
||||
|
||||
|
||||
it('should not navigate on non-left mouse click when a link url matches a route', inject(function ($router) {
|
||||
$router.config([
|
||||
{ path: '/', component: 'oneCmp' },
|
||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
||||
]);
|
||||
|
||||
compile('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link | one');
|
||||
elt.find('a').triggerHandler({ type: 'click', which: 3 });
|
||||
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link | one');
|
||||
}));
|
||||
|
||||
|
||||
// See https://github.com/angular/router/issues/206
|
||||
it('should not navigate a link without an href', function () {
|
||||
$router.config([
|
||||
{ path: '/', component: 'oneCmp' },
|
||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
||||
]);
|
||||
expect(function () {
|
||||
compile('<a>link</a>');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link');
|
||||
elt.find('a')[0].click();
|
||||
$rootScope.$digest();
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
|
||||
function registerComponent(name, template, config) {
|
||||
var controller = function () {};
|
||||
|
||||
function factory() {
|
||||
return {
|
||||
template: template,
|
||||
controllerAs: name,
|
||||
controller: controller
|
||||
};
|
||||
}
|
||||
|
||||
if (!template) {
|
||||
template = '';
|
||||
}
|
||||
if (angular.isArray(config)) {
|
||||
factory.annotations = [new angular.annotations.RouteConfig(config)];
|
||||
} else if (typeof config === 'function') {
|
||||
controller = config;
|
||||
} else if (typeof config === 'object') {
|
||||
if (config.canActivate) {
|
||||
controller.$canActivate = config.canActivate;
|
||||
}
|
||||
}
|
||||
$compileProvider.directive(name, factory);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
});
|
80
modules/angular1_router/test/util.es5.js
Normal file
80
modules/angular1_router/test/util.es5.js
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Helpers to keep tests DRY
|
||||
*/
|
||||
|
||||
function componentTemplatePath(name) {
|
||||
return './components/' + dashCase(name) + '/' + dashCase(name) + '.html';
|
||||
}
|
||||
|
||||
function componentControllerName(name) {
|
||||
return name[0].toUpperCase() + name.substr(1) + 'Controller';
|
||||
}
|
||||
|
||||
function dashCase(str) {
|
||||
return str.replace(/([A-Z])/g, function ($1) {
|
||||
return '-' + $1.toLowerCase();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function provideHelpers(fn, preInject) {
|
||||
return function () {
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$templateCache,
|
||||
$controllerProvider;
|
||||
|
||||
module('ng');
|
||||
module('ngNewRouter');
|
||||
module(function(_$controllerProvider_) {
|
||||
$controllerProvider = _$controllerProvider_;
|
||||
});
|
||||
|
||||
inject(function(_$compile_, _$rootScope_, _$router_, _$templateCache_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
$templateCache = _$templateCache_;
|
||||
});
|
||||
|
||||
function registerComponent(name, template, config) {
|
||||
if (!template) {
|
||||
template = '';
|
||||
}
|
||||
var ctrl;
|
||||
if (!config) {
|
||||
ctrl = function () {};
|
||||
} else if (angular.isArray(config)) {
|
||||
ctrl = function () {};
|
||||
ctrl.$routeConfig = config;
|
||||
} else if (typeof config === 'function') {
|
||||
ctrl = config;
|
||||
} else {
|
||||
ctrl = function () {};
|
||||
ctrl.prototype = config;
|
||||
}
|
||||
$controllerProvider.register(componentControllerName(name), ctrl);
|
||||
put(name, template);
|
||||
}
|
||||
|
||||
|
||||
function put (name, template) {
|
||||
$templateCache.put(componentTemplatePath(name), [200, template, {}]);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
var elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
|
||||
fn({
|
||||
registerComponent: registerComponent,
|
||||
$router: $router,
|
||||
put: put,
|
||||
compile: compile
|
||||
})
|
||||
}
|
||||
}
|
12
modules/angular1_router/tsd.json
Normal file
12
modules/angular1_router/tsd.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": "v4",
|
||||
"repo": "DefinitelyTyped/DefinitelyTyped",
|
||||
"ref": "master",
|
||||
"path": "typings",
|
||||
"bundle": "typings/tsd.d.ts",
|
||||
"installed": {
|
||||
"angularjs/angular.d.ts": {
|
||||
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
|
||||
}
|
||||
}
|
||||
}
|
@ -5,14 +5,11 @@ The sources for this package are in the main [Angular2](https://github.com/angul
|
||||
|
||||
This package contains different sources for different users:
|
||||
|
||||
1. The files located in the root folder can be consumed using CommonJS
|
||||
1. The files located in the root folder can be consumed using CommonJS.
|
||||
2. The files under `/es6` are es6 compatible files that can be transpiled to
|
||||
es5 using any transpiler. This contains:
|
||||
* `dev/`: a development version that includes runtime type assertions
|
||||
* `prod/`: a production version that does not include runtime type assertions
|
||||
3. The files under `/atscript` are the AtScript source files
|
||||
|
||||
As a convenience, we provide you with `/es6/{dev|prod}/es5build.js`, a script to transpile the es6 sources into es5
|
||||
using [Google Traceur](https://github.com/google/traceur-compiler/).
|
||||
3. The files under `/ts` are the TypeScript source files.
|
||||
|
||||
License: Apache MIT 2.0
|
||||
|
17
modules/angular2/angular2.dart
Normal file
17
modules/angular2/angular2.dart
Normal file
@ -0,0 +1,17 @@
|
||||
library angular2;
|
||||
|
||||
/**
|
||||
* An all-in-one place to import Angular 2 stuff.
|
||||
*
|
||||
* This library does not include `bootstrap`. Import `bootstrap.dart` instead.
|
||||
*/
|
||||
export 'package:angular2/core.dart';
|
||||
export 'package:angular2/common.dart';
|
||||
export 'package:angular2/instrumentation.dart';
|
||||
export 'package:angular2/src/core/angular_entrypoint.dart' show AngularEntrypoint;
|
||||
export 'package:angular2/src/core/application_tokens.dart'
|
||||
hide APP_COMPONENT_REF_PROMISE, APP_ID_RANDOM_PROVIDER;
|
||||
export 'package:angular2/src/platform/dom/dom_tokens.dart';
|
||||
export 'package:angular2/src/platform/dom/dom_adapter.dart';
|
||||
export 'package:angular2/src/platform/dom/events/event_manager.dart';
|
||||
export 'package:angular2/src/compiler/url_resolver.dart';
|
8
modules/angular2/angular2.js
vendored
8
modules/angular2/angular2.js
vendored
@ -1,8 +0,0 @@
|
||||
export * from './change_detection';
|
||||
export * from './core';
|
||||
export * from './annotations';
|
||||
export * from './directives';
|
||||
export * from './forms';
|
||||
export {Observable, EventEmitter} from 'angular2/src/facade/async';
|
||||
export * from 'angular2/src/render/api';
|
||||
export {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
@ -1,14 +0,0 @@
|
||||
import * as angular from './angular2';
|
||||
|
||||
var _prevAngular = window.angular;
|
||||
|
||||
/**
|
||||
* Calling noConflict will restore window.angular to its pre-angular loading state
|
||||
* and return the angular module object.
|
||||
*/
|
||||
angular.noConflict = function() {
|
||||
window.angular = _prevAngular;
|
||||
return angular;
|
||||
};
|
||||
|
||||
window.angular = angular;
|
5
modules/angular2/animate.ts
Normal file
5
modules/angular2/animate.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export {Animation} from './src/animate/animation';
|
||||
export {AnimationBuilder} from './src/animate/animation_builder';
|
||||
export {BrowserDetails} from './src/animate/browser_details';
|
||||
export {CssAnimationBuilder} from './src/animate/css_animation_builder';
|
||||
export {CssAnimationOptions} from './src/animate/css_animation_options';
|
1
modules/angular2/animate/testing.ts
Normal file
1
modules/angular2/animate/testing.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from 'angular2/src/mock/animation_builder_mock';
|
11
modules/angular2/annotations.js
vendored
11
modules/angular2/annotations.js
vendored
@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @module
|
||||
* @public
|
||||
* @description
|
||||
*
|
||||
* Annotations provide the additional information that Angular requires in order to run your application. This module
|
||||
* contains {@link Component}, {@link Decorator}, and {@link View} annotations, as well as {@link Parent} and {@link Ancestor} annotations that are
|
||||
* used by Angular to resolve dependencies.
|
||||
*
|
||||
*/
|
||||
export * from './src/core/annotations/annotations';
|
6
modules/angular2/bootstrap.ts
Normal file
6
modules/angular2/bootstrap.ts
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* See {@link bootstrap} for more information.
|
||||
* @deprecated
|
||||
*/
|
||||
export {bootstrap} from 'angular2/platform/browser';
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
6
modules/angular2/bootstrap_static.ts
Normal file
6
modules/angular2/bootstrap_static.ts
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* See {@link bootstrap} for more information.
|
||||
* @deprecated
|
||||
*/
|
||||
export {bootstrapStatic} from 'angular2/platform/browser_static';
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
29
modules/angular2/change_detection.js
vendored
29
modules/angular2/change_detection.js
vendored
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* @module
|
||||
* @public
|
||||
* @description
|
||||
* Change detection enables data binding in Angular.
|
||||
*/
|
||||
|
||||
export {
|
||||
ASTWithSource, AST, AstTransformer, AccessMember, LiteralArray, ImplicitReceiver
|
||||
} from './src/change_detection/parser/ast';
|
||||
|
||||
export {Lexer} from './src/change_detection/parser/lexer';
|
||||
export {Parser} from './src/change_detection/parser/parser';
|
||||
export {Locals} from './src/change_detection/parser/locals';
|
||||
|
||||
export {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './src/change_detection/exceptions';
|
||||
export {ProtoChangeDetector, ChangeDispatcher, ChangeDetector, ChangeDetection} from './src/change_detection/interfaces';
|
||||
export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './src/change_detection/constants';
|
||||
export {DynamicProtoChangeDetector, JitProtoChangeDetector} from './src/change_detection/proto_change_detector';
|
||||
export {BindingRecord} from './src/change_detection/binding_record';
|
||||
export {DirectiveRecord} from './src/change_detection/directive_record';
|
||||
export {DynamicChangeDetector} from './src/change_detection/dynamic_change_detector';
|
||||
export {ChangeDetectorRef} from './src/change_detection/change_detector_ref';
|
||||
export {PipeRegistry} from './src/change_detection/pipes/pipe_registry';
|
||||
export {uninitialized} from './src/change_detection/change_detection_util';
|
||||
export {NO_CHANGE, Pipe} from './src/change_detection/pipes/pipe';
|
||||
export {
|
||||
defaultPipes, DynamicChangeDetection, JitChangeDetection, defaultPipeRegistry
|
||||
} from './src/change_detection/change_detection';
|
4
modules/angular2/common.ts
Normal file
4
modules/angular2/common.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './src/common/pipes';
|
||||
export * from './src/common/directives';
|
||||
export * from './src/common/forms';
|
||||
export * from './src/common/common_directives';
|
8
modules/angular2/compiler.ts
Normal file
8
modules/angular2/compiler.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Starting point to import all compiler APIs.
|
||||
*/
|
||||
export * from './src/compiler/url_resolver';
|
||||
export * from './src/compiler/xhr';
|
||||
export * from './src/compiler/compiler';
|
26
modules/angular2/core.dart
Normal file
26
modules/angular2/core.dart
Normal file
@ -0,0 +1,26 @@
|
||||
library angular2.core;
|
||||
|
||||
export './src/core/angular_entrypoint.dart' show AngularEntrypoint;
|
||||
export './src/core/metadata.dart';
|
||||
export './src/core/util.dart';
|
||||
export 'package:angular2/src/facade/lang.dart' show enableProdMode;
|
||||
export './src/core/di.dart' hide ForwardRefFn, resolveForwardRef, forwardRef;
|
||||
export './src/facade/facade.dart';
|
||||
export './src/core/application_ref.dart' show platform, createNgZone, PlatformRef, ApplicationRef;
|
||||
export './src/core/application_tokens.dart' show APP_ID,
|
||||
APP_COMPONENT,
|
||||
APP_INITIALIZER,
|
||||
PACKAGE_ROOT_URL,
|
||||
PLATFORM_INITIALIZER;
|
||||
export './src/core/zone.dart';
|
||||
export './src/core/render.dart';
|
||||
export './src/core/linker.dart';
|
||||
export './src/core/debug/debug_node.dart' show DebugElement,
|
||||
DebugNode,
|
||||
asNativeElements;
|
||||
export './src/core/testability/testability.dart';
|
||||
export './src/core/change_detection.dart';
|
||||
export './src/core/platform_directives_and_pipes.dart';
|
||||
export './src/core/platform_common_providers.dart';
|
||||
export './src/core/application_common_providers.dart';
|
||||
export './src/core/reflection/reflection.dart';
|
24
modules/angular2/core.js
vendored
24
modules/angular2/core.js
vendored
@ -1,24 +0,0 @@
|
||||
/**
|
||||
* @module
|
||||
* @public
|
||||
* @description
|
||||
* Define angular core API here.
|
||||
*/
|
||||
export * from './src/core/annotations/visibility';
|
||||
export * from './src/core/compiler/interfaces';
|
||||
export * from './src/core/annotations/view';
|
||||
export * from './src/core/application';
|
||||
export * from './src/core/application_tokens';
|
||||
export * from './src/core/annotations/di';
|
||||
|
||||
export * from './src/core/compiler/compiler';
|
||||
|
||||
// TODO(tbosch): remove this once render migration is complete
|
||||
export * from 'angular2/src/render/dom/compiler/template_loader';
|
||||
export * from './src/core/compiler/dynamic_component_loader';
|
||||
export {ElementRef, ComponentRef} from './src/core/compiler/element_injector';
|
||||
export * from './src/core/compiler/view';
|
||||
export * from './src/core/compiler/view_container';
|
||||
|
||||
export * from './src/core/compiler/ng_element';
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user