Compare commits
680 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93b0c2d892 | |||
| d262378b7c | |||
| 7729c84ec7 | |||
| dffeef29d7 | |||
| 2e22588ccf | |||
| 0b0acb0342 | |||
| 18fc43e828 | |||
| ed47d811e2 | |||
| a84f9f6178 | |||
| 4fbbe1152e | |||
| df3d941c57 | |||
| 2bd3214a55 | |||
| fc2abef327 | |||
| 76a0eb89fb | |||
| ee57b4c26b | |||
| 29eaabc000 | |||
| 2a6081057f | |||
| 79538afd7b | |||
| bcfa64e77c | |||
| b7a2deed30 | |||
| 98ff901bda | |||
| 428b81cba9 | |||
| 5dae9c230e | |||
| c3fad1157e | |||
| 9242c580a1 | |||
| c2860944c6 | |||
| e9a00fbdc3 | |||
| d018ac2a9a | |||
| b770c353bc | |||
| 812277c257 | |||
| 61871da9de | |||
| 9ee075518f | |||
| afe93eaff8 | |||
| d8f94d1a3f | |||
| f53b53df22 | |||
| eab5731afc | |||
| 986c446aaf | |||
| 60366c8d0b | |||
| 494c8aa0b3 | |||
| cd9459e129 | |||
| 2862883bd8 | |||
| bbb673a48a | |||
| cd9afd9961 | |||
| e25ed0d48d | |||
| cd6d21e78a | |||
| 9cf5b35e5c | |||
| 5d11e02008 | |||
| 209e600070 | |||
| ceaca57786 | |||
| cbdf0c2afb | |||
| 1111076552 | |||
| 948c86c602 | |||
| cd63ff497d | |||
| 9d6240561b | |||
| 05b5245790 | |||
| e6ebfc87c9 | |||
| 7f2bcc3933 | |||
| 492b0cdf28 | |||
| 51863f80d7 | |||
| 9d4000d689 | |||
| bc036c68ac | |||
| 580135a9cb | |||
| da0c5efa72 | |||
| c280d5ab02 | |||
| 28c8199cd6 | |||
| 0252a9889b | |||
| 1c15cdc2d0 | |||
| 0bd329d4fd | |||
| 8db84a16db | |||
| cffcfc73a0 | |||
| 25eb9b794f | |||
| 6941779543 | |||
| 65f40d2123 | |||
| e159f9626c | |||
| 685a9d040d | |||
| 8eede099cd | |||
| a17d42d706 | |||
| 60af504c18 | |||
| 243d9ac72c | |||
| cc8eb91665 | |||
| 8697c3bf4c | |||
| 3c46c94342 | |||
| 71eb1901f6 | |||
| 4e57e28589 | |||
| 13289c0903 | |||
| afdb4f1b76 | |||
| e7999e7447 | |||
| d175bb0131 | |||
| fe1188daf3 | |||
| e1a3a6251f | |||
| 25d3d3730d | |||
| af5aacce05 | |||
| 3abd0fb93c | |||
| 36d2658b94 | |||
| 6ce5a04d42 | |||
| 929064d9e4 | |||
| d0b873a4b7 | |||
| 2e10659472 | |||
| 2a8493f40c | |||
| 2f960f1530 | |||
| 3f5f20fe77 | |||
| 01387c0a8f | |||
| c0afbfaca5 | |||
| bf13d2683d | |||
| fe01a85a8e | |||
| 6b9a332959 | |||
| f1b28847c8 | |||
| 1b779028fd | |||
| 49b2a1c8cf | |||
| 3e82492fc6 | |||
| 856be44628 | |||
| dbb21b1531 | |||
| 3ce56b739c | |||
| ecbb374826 | |||
| 0e5d31908e | |||
| f1b0d21f97 | |||
| 58e94dcde9 | |||
| eba192b863 | |||
| 75099e6137 | |||
| 172a40931b | |||
| 23e5109b64 | |||
| cc84ce3bf5 | |||
| bee2d1fbb9 | |||
| 7101a02c93 | |||
| 888be00712 | |||
| 05597c24c7 | |||
| bf55f23325 | |||
| ab051e78ea | |||
| 87d46a84c3 | |||
| ae764f1844 | |||
| ad8092ed80 | |||
| 55e1b3e1c8 | |||
| 6f465a2b26 | |||
| 3ecac62251 | |||
| c64610269d | |||
| 5c2302949b | |||
| 7c84e2632f | |||
| 18d18f07db | |||
| 9f5be534fc | |||
| 1cd7912614 | |||
| 514da451fc | |||
| 2788cc4e12 | |||
| 7f6322df6a | |||
| 5bd8613168 | |||
| 32b507890e | |||
| bfedafdede | |||
| cdefbe3425 | |||
| f75f4bce82 | |||
| 4349de3d41 | |||
| df545d7eed | |||
| 3b5f346314 | |||
| 3aab87b381 | |||
| 0973175058 | |||
| 112da45c07 | |||
| e3dc85841d | |||
| ef1c352bc9 | |||
| a5b6444324 | |||
| dd18c00b1d | |||
| a0fad24dc2 | |||
| da0e3c99f5 | |||
| a41c58e285 | |||
| bce5b49133 | |||
| 816b84230c | |||
| 873acf8fab | |||
| 9063a0c2e7 | |||
| 03cbc0d6b1 | |||
| 931789ec14 | |||
| 9bc807783f | |||
| 2d6ee651b1 | |||
| 7ca24a8264 | |||
| 1d8e42070a | |||
| fe6b2fbfc4 | |||
| 5a222244fb | |||
| 4026074aba | |||
| d9a596addd | |||
| 8c0898b21c | |||
| d9b693bb7a | |||
| da94ab2e63 | |||
| 2fd8dc7061 | |||
| 01012a4d7a | |||
| ce84429adf | |||
| a26acb64fe | |||
| 7088ed1ed3 | |||
| 7027844d42 | |||
| 16c584ed7f | |||
| b586bfdfab | |||
| 1d69015e3d | |||
| f13c33bf10 | |||
| ba62e975f1 | |||
| b89d941cdf | |||
| 07fa87a8a8 | |||
| 0af70eb99e | |||
| cb713e6045 | |||
| 89ca859734 | |||
| bc6fb7cc94 | |||
| 0c80df21b6 | |||
| 3141dbf179 | |||
| aad502bad8 | |||
| dca8972367 | |||
| 284de57435 | |||
| f780ccfa1c | |||
| 55f99e0710 | |||
| 1a99ca9c08 | |||
| 37500fca83 | |||
| 4fe4fc5abf | |||
| 74e1cc683b | |||
| a4faa5cde7 | |||
| 32cb40b86d | |||
| d1cd677433 | |||
| 43c735a816 | |||
| ab2e83c8c8 | |||
| e5f454c8af | |||
| 67c11b9a39 | |||
| 5a306b7ba3 | |||
| 8ce61bf178 | |||
| 9d452bc845 | |||
| 192fecc790 | |||
| 32be6369e4 | |||
| 2a45cea0ba | |||
| ea653e4cdd | |||
| 03777445e8 | |||
| 8b25ea129a | |||
| d71f16e745 | |||
| ed59370d80 | |||
| d8e5acfe27 | |||
| af59f4e69a | |||
| 24aee81634 | |||
| f81d56e66c | |||
| f0904cf12e | |||
| 81b7e5ab0e | |||
| 1b1890274e | |||
| 6d418ef5e3 | |||
| 3fa1606c43 | |||
| 8661a9e3d4 | |||
| cf63292742 | |||
| fd420c4061 | |||
| 1382d4e88e | |||
| b9ddef2a49 | |||
| eafba9e2e5 | |||
| 6f1d9f8ca6 | |||
| bb9310974b | |||
| 30279d7b9b | |||
| 8df5f3259a | |||
| 14e797c1a1 | |||
| 82cd6b87f0 | |||
| 6d7cc572b5 | |||
| 2ebbe00eb5 | |||
| 8b86d363aa | |||
| 9b51067516 | |||
| a3208bf66e | |||
| 4e1fb82628 | |||
| ad466412c6 | |||
| 299a32740c | |||
| eb799bcb71 | |||
| 7314c1b69e | |||
| fcfe2b3793 | |||
| 5e140a99c7 | |||
| 4da169d15d | |||
| f37c6f9f73 | |||
| eae658fd96 | |||
| 286f269753 | |||
| 73640a6b7c | |||
| 2dc55ff5c2 | |||
| 98a2563ec4 | |||
| 8c02122837 | |||
| 1e069532fc | |||
| 6f6f7e82a4 | |||
| d852122442 | |||
| 66cb161221 | |||
| 6c14fb1eb6 | |||
| e906aafb0a | |||
| 6acc73f3e0 | |||
| a4367ab00d | |||
| 2e0464fba4 | |||
| 6ffd53ee3c | |||
| 2395bf604d | |||
| 2e5fe846e3 | |||
| b6388b3f1d | |||
| 669e3aeaa8 | |||
| 55b2f0e862 | |||
| ca566d8d81 | |||
| b306babe29 | |||
| d9317cde4f | |||
| 23c8af232f | |||
| 2fcbd39d0b | |||
| 3ffbf202ce | |||
| 09367d88c2 | |||
| 369f69d67a | |||
| 9f43d02af8 | |||
| 08e6b88fb2 | |||
| 9227a5db94 | |||
| fc6ce59cd2 | |||
| 96a314766c | |||
| 6aa31e17ee | |||
| d18d5f57c2 | |||
| 2d9e96772f | |||
| bc2a5aaf05 | |||
| 4547c11dad | |||
| c0b360b993 | |||
| a659049893 | |||
| a3b9b1d205 | |||
| 3305f38db2 | |||
| 9be4e035d1 | |||
| 85ce5d0db9 | |||
| 5c99720934 | |||
| 8d26238664 | |||
| b7cb454546 | |||
| 199825ec26 | |||
| bcdd925c9d | |||
| 0bcace309e | |||
| 46c9c942df | |||
| 2ad439dfc5 | |||
| 3fbfe3f966 | |||
| 8ff671753c | |||
| 24092127d1 | |||
| f1c7240f04 | |||
| fcee3bea1a | |||
| ad08638c0a | |||
| 093e76fa15 | |||
| 28c0497524 | |||
| 88505d8029 | |||
| c241a57761 | |||
| b0e985fb67 | |||
| a0dbd95bb9 | |||
| 9fd5450ee8 | |||
| b5391fae8f | |||
| b635903ec4 | |||
| c9ee20b64b | |||
| 25ae98ca77 | |||
| adb5ee2e0a | |||
| 78954ffcde | |||
| 3b30a4b64a | |||
| 866057233c | |||
| ec1f4a8c9b | |||
| c94190139d | |||
| 4896a0b4d4 | |||
| 32bd990eda | |||
| 23723298f9 | |||
| edab80cddb | |||
| f4bb006e45 | |||
| cf3f709889 | |||
| e9ecd56dca | |||
| f107ef8bd8 | |||
| e7eab501db | |||
| 97fc47f39e | |||
| 6d1c67727a | |||
| 8ba78f08b9 | |||
| 02a3c31c23 | |||
| d4c3d5caaf | |||
| 279f98c4e3 | |||
| 5e548edf67 | |||
| acaf9be685 | |||
| bdd75c97ad | |||
| a3f1cba8ec | |||
| 4195b04072 | |||
| ccc8ec869b | |||
| 6d8abaedd8 | |||
| fd49d6634c | |||
| cecd5214df | |||
| c5e39c688b | |||
| 240608447a | |||
| bcb53deda8 | |||
| 9d4fa33e35 | |||
| de1461da78 | |||
| 2866daf7d6 | |||
| b3de37e418 | |||
| a4cc9e1944 | |||
| f8a1c56cad | |||
| 113850602d | |||
| e76105a320 | |||
| 14e9be202a | |||
| dd5215eceb | |||
| 497ba08775 | |||
| eaaf4967f9 | |||
| f440ac7492 | |||
| d566c4bc61 | |||
| 766b962eac | |||
| 0388eed7e5 | |||
| 82448b86b5 | |||
| fafcd6285a | |||
| 5319621afd | |||
| 32aa491588 | |||
| 31bdb60f0a | |||
| a8aae48bc0 | |||
| 517917f9fa | |||
| 1748abe8ef | |||
| 5f5bf07bb8 | |||
| 3d0b49c07f | |||
| b6aec5642e | |||
| e44e5f447b | |||
| ca273fd9da | |||
| 5ff453d422 | |||
| d9c75bee93 | |||
| e030e64196 | |||
| 7ba19cc355 | |||
| 21428e5cea | |||
| 9321a5f14c | |||
| 72421b2acf | |||
| c3fe170b8b | |||
| ed18b8c9da | |||
| 0cb276f7ac | |||
| cfccb8f64a | |||
| 0069f87007 | |||
| 9599234bae | |||
| d423117158 | |||
| 3c8a940686 | |||
| 9f8e30f550 | |||
| dcd94a23e1 | |||
| 9b79a00294 | |||
| 02058bfbe2 | |||
| 76647d3855 | |||
| 1f1cad8517 | |||
| e1f1d65d0c | |||
| a5df2d4e36 | |||
| b6514d9e1a | |||
| 1b1f94d8fe | |||
| 1362a9b456 | |||
| 6a26b2c38c | |||
| 9ab9bf6b41 | |||
| e7e56fe9bf | |||
| 85ea376da2 | |||
| 050aae3ceb | |||
| 79d9fd9d57 | |||
| 2dc2265e4f | |||
| 9cd33df50c | |||
| 1db20ce90f | |||
| 76cb5ce7c5 | |||
| 2a778d0038 | |||
| b04d3a8ec6 | |||
| 7839330b40 | |||
| 2d7cb14a16 | |||
| f20b06d26d | |||
| 109e5d1d39 | |||
| 227822dac3 | |||
| 92f6b45e02 | |||
| 24f7999bc1 | |||
| e0203660d3 | |||
| b6eb5fdb05 | |||
| 5bf6e50b40 | |||
| a7ccb7531c | |||
| 6bea059109 | |||
| fcdac65aed | |||
| 373078a94c | |||
| db07ad2d4c | |||
| 19d7a127c7 | |||
| f5a04f59cf | |||
| ab92da43b0 | |||
| 6782c45ddc | |||
| c55477fb2b | |||
| 2e2d62ca12 | |||
| e3141fe5f4 | |||
| 1ebed26678 | |||
| e987efd4c0 | |||
| ea72e5f881 | |||
| c550c12738 | |||
| 651caffe45 | |||
| 45855b8ba2 | |||
| feb54d68d2 | |||
| 2d0f6037f7 | |||
| ebd9a2a960 | |||
| fcfa6ebb6b | |||
| cf8ed01c6e | |||
| c352b92c40 | |||
| 369145467c | |||
| c3ec6ea226 | |||
| 291684c29c | |||
| d7615351df | |||
| a97a172ee9 | |||
| d53a787f0d | |||
| 9682bd0c4e | |||
| 34d0740350 | |||
| 4d9efa2f76 | |||
| f9a7b064a0 | |||
| 26ca443c10 | |||
| 0f37e49039 | |||
| 3fdcde73ae | |||
| d2dc77169b | |||
| d99b506885 | |||
| fef0cfc837 | |||
| 5de845506b | |||
| 38ea542662 | |||
| 2db66f5b69 | |||
| 55fe6d6331 | |||
| f4c08fee85 | |||
| 71bc451f95 | |||
| 7e4e696ec3 | |||
| 6da44a4410 | |||
| a81195c6ca | |||
| 102a3201c1 | |||
| 59244a7776 | |||
| 293cb1fc5d | |||
| 81395ac298 | |||
| ba66c4f3cc | |||
| 4ea57e7e96 | |||
| 6e420ff28d | |||
| 5393814756 | |||
| fab59e7515 | |||
| 553c252d5c | |||
| e145a8df72 | |||
| b49d0cc6e7 | |||
| 97b171ecb2 | |||
| 245de33c00 | |||
| 8d4d437e8c | |||
| 7287dbf71d | |||
| da88449f25 | |||
| eaf1f8546d | |||
| 20d926cc45 | |||
| 9ae9c1c0da | |||
| 8a5972461c | |||
| 35d635cbcb | |||
| db2a4c04d6 | |||
| 0d62257c5f | |||
| f911b84aef | |||
| 32c09c1d19 | |||
| 26064375ca | |||
| 7a294369ab | |||
| fbab287ea2 | |||
| 254dcee93d | |||
| 69e5c369d7 | |||
| c0ccbb7b6a | |||
| b87713687e | |||
| 950ffb5a84 | |||
| 259003056d | |||
| fedc4194d9 | |||
| 16862705e1 | |||
| c694c96e4c | |||
| 5ac8a6e74a | |||
| 0e5106ec2c | |||
| 9091b77fe6 | |||
| 849f998be3 | |||
| 8bc77b68b3 | |||
| 95bd046881 | |||
| bfce9126e1 | |||
| bf2264e2aa | |||
| 5ced7b20ff | |||
| 114cf9e418 | |||
| 1b61b73f28 | |||
| d657d63a21 | |||
| c5bb3a9098 | |||
| 77edce5ded | |||
| f37cd4e4ef | |||
| 2acc91098b | |||
| 5b1c89931e | |||
| 99a2ad381b | |||
| 300263abec | |||
| b0bcf18892 | |||
| ea3b6310c9 | |||
| 764a3beecc | |||
| a603330e7a | |||
| 1f842b1c63 | |||
| 3b09f1bf4e | |||
| 561ddc9ff1 | |||
| 512ecf8f1b | |||
| 6636f1d03f | |||
| 7cccb8b777 | |||
| a275d539f9 | |||
| 17fa2468bc | |||
| fb2ae5660e | |||
| 2c4b3573cc | |||
| b2363e3102 | |||
| edfca4c769 | |||
| a9b5a1087d | |||
| 87b18b9fbe | |||
| ad128e09ff | |||
| 187b4adbd2 | |||
| 375c47d0c0 | |||
| 8fd47a1cd5 | |||
| e48c28fe92 | |||
| 10d3e1e447 | |||
| 93d1c95c61 | |||
| 01a34f513b | |||
| 916e53ce14 | |||
| b91b3119a4 | |||
| 0d60f8d367 | |||
| ca69dc6f17 | |||
| 5b7f1bcc00 | |||
| 9ab594a66c | |||
| 6c82a497c6 | |||
| df804406fb | |||
| dadce485a7 | |||
| 344cdce136 | |||
| f0347d5efa | |||
| 1c27e5fc37 | |||
| 5fb298b90f | |||
| 483325a7b5 | |||
| a86cb7d794 | |||
| c7e60153a5 | |||
| c0416866f5 | |||
| 8ba452544e | |||
| 8f7f0d26ed | |||
| 98d825e10d | |||
| 57b0d91fd8 | |||
| 9226b36572 | |||
| 39635fd0d7 | |||
| cad307fa1f | |||
| 78bc84c497 | |||
| 1f2750136e | |||
| 5b93e5fcfc | |||
| 770fd5a917 | |||
| 4b29186696 | |||
| 7b5be9ee29 | |||
| eeb261bcd5 | |||
| ef88a8a020 | |||
| 86ab885fd9 | |||
| de07ddeac6 | |||
| dc149de936 | |||
| 320f6d1214 | |||
| 1517d6d2f2 | |||
| 6bb17af2e3 | |||
| 505ead7e58 | |||
| 1da4e89385 | |||
| 83f37d78ba | |||
| d4ac25496a | |||
| e84da2283c | |||
| 3dd9572754 | |||
| 922cb7e42f | |||
| 103cb513d9 | |||
| c24e4e4ed5 | |||
| 1b46a7dcdf | |||
| 8d28d65b36 | |||
| fbb125a3af | |||
| ca7336391a | |||
| 771bccc35c | |||
| c794b96bdc | |||
| f108a2a994 | |||
| 7cbf61cabb | |||
| dfdb72559f | |||
| d69793d93c | |||
| b068c8b605 | |||
| ec16352579 | |||
| aa4ba23350 | |||
| 25e639b474 | |||
| ee8e4a946e | |||
| a41a2a1d2c | |||
| eadd8d08d3 | |||
| 602a1142e8 | |||
| 0b7fef3d94 | |||
| 809d47ec77 | |||
| f3444d495d | |||
| 612c882b83 | |||
| f2a6be3129 | |||
| 465663ed77 | |||
| 1102ffaaf8 | |||
| 98f6a82390 | |||
| a43c6e1828 | |||
| 0db301f863 | |||
| 8e6d3875c6 | |||
| b9d77d46ff | |||
| 96f94d4347 | |||
| 63831f118f | |||
| ebe280eede | |||
| 95d6cdc7c7 | |||
| 9223215add | |||
| 309cfd109f | |||
| cfc6175aab | |||
| dc39f368c3 | |||
| c0f3400573 | |||
| 822d7e5ae9 | |||
| 5874db84ab | |||
| e9e8d49216 | |||
| 550fc21ce5 | |||
| a8aba8957b | |||
| ca0ac64997 | |||
| 7678501bc9 | |||
| dec5eb6e83 | |||
| 2eff326781 | |||
| 50ce5746a7 | |||
| 1537f80267 | |||
| 021d3aa21a | |||
| e8c8c5459e | |||
| 1c20aed318 | |||
| 4c4d24a338 | |||
| 8c7b9b8de4 | |||
| f39ac571c4 | |||
| 84f36701bc | |||
| 6d4ce240de | |||
| 229a155aef | |||
| 73250089cd | |||
| a72bc4e69f | |||
| 0812061274 |
@@ -14,7 +14,6 @@ angular.js.tmproj
|
||||
angular.xcodeproj
|
||||
.idea
|
||||
.agignore
|
||||
.lvimrc
|
||||
libpeerconnection.log
|
||||
npm-debug.log
|
||||
/tmp/
|
||||
|
||||
+15
-732
@@ -921,77 +921,6 @@ jQuery. We don't expect that app code actually depends on this accidental featur
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-beta.11"></a>
|
||||
# 1.3.0-beta.11 transclusion-deforestation (2014-06-06)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** remove the need to add `display:block !important` for `ngShow`/`ngHide`
|
||||
([7c011e79](https://github.com/angular/angular.js/commit/7c011e79d8b3d805755181ace472883800234bf4),
|
||||
[#3813](https://github.com/angular/angular.js/issues/3813))
|
||||
- **$compile:**
|
||||
- bound transclusion to correct scope
|
||||
([56c60218](https://github.com/angular/angular.js/commit/56c60218d1e70e3a47e37193a4a48714eeda7d44))
|
||||
- set the iteration state before linking
|
||||
([0c8a2cd2](https://github.com/angular/angular.js/commit/0c8a2cd2da3a4a9f5d2ee9c25ea8ed56d74a93ab))
|
||||
- don't pass transcludes to non-transclude templateUrl directives
|
||||
([2ee29c5d](https://github.com/angular/angular.js/commit/2ee29c5da81ffacdc1cabb438f5d125d5e116cb9))
|
||||
- don't pass transclude to template of non-transclude directive
|
||||
([19af0397](https://github.com/angular/angular.js/commit/19af0397456eb8fc06dea47145fdee0e38e62f81))
|
||||
- fix nested isolated transclude directives
|
||||
([d414b787](https://github.com/angular/angular.js/commit/d414b787173643362c0c513a1929d8e715ca340e),
|
||||
[#1809](https://github.com/angular/angular.js/issues/1809), [#7499](https://github.com/angular/angular.js/issues/7499))
|
||||
- pass transcludeFn down to nested transclude directives
|
||||
([1fef5fe8](https://github.com/angular/angular.js/commit/1fef5fe8230e8dc53f2c9f3f510a35cf18eeab43),
|
||||
[#7240](https://github.com/angular/angular.js/issues/7240), [#7387](https://github.com/angular/angular.js/issues/7387))
|
||||
- **$parse:** fix parsing error with leading space and one time bind
|
||||
([24c844df](https://github.com/angular/angular.js/commit/24c844df3b6d80103b01e4847b2d55b082757feb),
|
||||
[#7640](https://github.com/angular/angular.js/issues/7640))
|
||||
- **angular.copy:** support circular references in the value being copied
|
||||
([083f496d](https://github.com/angular/angular.js/commit/083f496d46415c01fec6dfa012da63235d0996e4),
|
||||
[#7618](https://github.com/angular/angular.js/issues/7618))
|
||||
- **angular.toJson:** only strip properties beginning with `$$`, not `$`
|
||||
([c054288c](https://github.com/angular/angular.js/commit/c054288c9722875e3595e6e6162193e0fb67a251))
|
||||
- **ngAnimate:**
|
||||
- `$animate` methods should accept native DOM elements
|
||||
([222d4737](https://github.com/angular/angular.js/commit/222d47370e585d9de9fa842310734ba1dd895fab))
|
||||
- fix property name that is used to calculate cache key
|
||||
([9f5c4370](https://github.com/angular/angular.js/commit/9f5c4370489043ed953c102340ce203a822c8b42),
|
||||
[#7566](https://github.com/angular/angular.js/issues/7566))
|
||||
- **ngClass:** support multiple classes in key
|
||||
([7eaaca8e](https://github.com/angular/angular.js/commit/7eaaca8ef2b3db76b7c87e98d264d4b16d90a392))
|
||||
- **ngIf:** ensure that the correct (transcluded) scope is used
|
||||
([d71df9f8](https://github.com/angular/angular.js/commit/d71df9f83cd3882295ca01b1bb8ad7fb024165b6))
|
||||
- **ngLocale:** fix i18n code-generation to support `get_vf_`, `decimals_`, and `get_wt_`
|
||||
([cbab51ca](https://github.com/angular/angular.js/commit/cbab51cac5d6460938e4dfe0035d624df2208d6c))
|
||||
- **ngRepeat:** ensure that the correct (transcluded) scope is used
|
||||
([b87e5fc0](https://github.com/angular/angular.js/commit/b87e5fc0920915991122ba5dac87b619847b3568))
|
||||
- **ngShow:** ensure that the display property is never set to `block`
|
||||
([1d90744f](https://github.com/angular/angular.js/commit/1d90744f4095ee202616a30f5d6f060fc8e74b20),
|
||||
[#7707](https://github.com/angular/angular.js/issues/7707))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$resource:** allow props beginning with `$` to be used on resources
|
||||
([d3c50c84](https://github.com/angular/angular.js/commit/d3c50c845671f0f8bcc3f7842df9e2fb1d1b1c40))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$resource:** due to [d3c50c84](https://github.com/angular/angular.js/commit/d3c50c845671f0f8bcc3f7842df9e2fb1d1b1c40),
|
||||
|
||||
If you expected `$resource` to strip these types of properties before,
|
||||
you will have to manually do this yourself now.
|
||||
|
||||
- **angular.toJson:** due to [c054288c](https://github.com/angular/angular.js/commit/c054288c9722875e3595e6e6162193e0fb67a251),
|
||||
|
||||
If you expected `toJson` to strip these types of properties before,
|
||||
you will have to manually do this yourself now.
|
||||
|
||||
|
||||
|
||||
<a name="1.2.17"></a>
|
||||
# 1.2.17 - quantum disentanglement (2014-06-06)
|
||||
|
||||
@@ -1089,427 +1018,6 @@ jQuery. We don't expect that app code actually depends on this accidental featur
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-beta.10"></a>
|
||||
# 1.3.0-beta.10 excessive-clarification (2014-05-23)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** retain inline styles for property-specific transitions
|
||||
([98b9d68e](https://github.com/angular/angular.js/commit/98b9d68ea3ecfb521e9279c9cbfe93f8ba7d626e),
|
||||
[#7503](https://github.com/angular/angular.js/issues/7503))
|
||||
- **$compile:** do not merge attrs that are the same for replace directives
|
||||
([1ab6e908](https://github.com/angular/angular.js/commit/1ab6e908b15470d59b52eb0ead20c755c66ec3b8),
|
||||
[#7463](https://github.com/angular/angular.js/issues/7463))
|
||||
- **$parse:** remove deprecated promise unwrapping
|
||||
([fa6e411d](https://github.com/angular/angular.js/commit/fa6e411da26824a5bae55f37ce7dbb859653276d))
|
||||
- **Scope:** $broadcast and $emit should set event.currentScope to null
|
||||
([82f45aee](https://github.com/angular/angular.js/commit/82f45aee5bd84d1cc53fb2e8f645d2263cdaacbc),
|
||||
[#7445](https://github.com/angular/angular.js/issues/7445), [#7523](https://github.com/angular/angular.js/issues/7523))
|
||||
- **ngModel:** do not dirty the input on $commitViewValue if nothing was changed
|
||||
([facd904a](https://github.com/angular/angular.js/commit/facd904a613e716151a13ab7460b5e6206e0442b),
|
||||
[#7457](https://github.com/angular/angular.js/issues/7457), [#7495](https://github.com/angular/angular.js/issues/7495))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$interpolate:** escaped interpolation expressions
|
||||
([e3f78c17](https://github.com/angular/angular.js/commit/e3f78c17d3b5d3a714402d7314094aabe7f6512a),
|
||||
[#5601](https://github.com/angular/angular.js/issues/5601), [#7517](https://github.com/angular/angular.js/issues/7517))
|
||||
- **{{ bindings }}:** lazy one-time binding support
|
||||
([cee429f0](https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4),
|
||||
[#7486](https://github.com/angular/angular.js/issues/7486), [#5408](https://github.com/angular/angular.js/issues/5408))
|
||||
- **ngMock:** add support of mocha tdd interface
|
||||
([854bf5b7](https://github.com/angular/angular.js/commit/854bf5b74d0395f4d2e30382102d3f5d1614ea11),
|
||||
[#7489](https://github.com/angular/angular.js/issues/7489))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$interpolate:** optimize value stringification
|
||||
([e927193d](https://github.com/angular/angular.js/commit/e927193de06500f01a2f893934250911cf1905e6),
|
||||
[#7501](https://github.com/angular/angular.js/issues/7501))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$compile:** due to [eec6394a](https://github.com/angular/angular.js/commit/eec6394a342fb92fba5270eee11c83f1d895e9fb), The `replace` flag for defining directives that
|
||||
replace the element that they are on will be removed in the next major angular version.
|
||||
This feature has difficult semantics (e.g. how attributes are merged) and leads to more
|
||||
problems compared to what it solves. Also, with Web Components it is normal to have
|
||||
custom elements in the DOM.
|
||||
|
||||
- **$parse:** due to [fa6e411d](https://github.com/angular/angular.js/commit/fa6e411da26824a5bae55f37ce7dbb859653276d),
|
||||
promise unwrapping has been removed. It has been deprecated since 1.2.0-rc.3.
|
||||
It can no longer be turned on.
|
||||
Two methods have been removed:
|
||||
* `$parseProvider.unwrapPromises`
|
||||
* `$parseProvider.logPromiseWarnings`
|
||||
|
||||
- **Scope:** due to [82f45aee](https://github.com/angular/angular.js/commit/82f45aee5bd84d1cc53fb2e8f645d2263cdaacbc),
|
||||
[#7445](https://github.com/angular/angular.js/issues/7445),
|
||||
[#7523](https://github.com/angular/angular.js/issues/7523)
|
||||
`$broadcast` and `$emit` will now reset the `currentScope` property of the event to
|
||||
null once the event finished propagating. If any code depends on asynchronously accessing their
|
||||
`currentScope` property, it should be migrated to use `targetScope` instead. All of these cases
|
||||
should be considered programming bugs.
|
||||
|
||||
|
||||
<a name="1.3.0-beta.9"></a>
|
||||
# 1.3.0-beta.9 release-naming (2014-05-16)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** pass `transcludeFn` down to nested transclude directives
|
||||
([4f03dc5a](https://github.com/angular/angular.js/commit/4f03dc5a9650f3f22f78b438474322b4b8871dec),
|
||||
[#7240](https://github.com/angular/angular.js/issues/7240), [#7387](https://github.com/angular/angular.js/issues/7387))
|
||||
- **jqLite:** use jQuery only if jQuery.fn.on present
|
||||
([e9bc51cb](https://github.com/angular/angular.js/commit/e9bc51cb0964ea682c1654919174dacebd09fcf6))
|
||||
- **ngClass:** handle index changes when an item is unshifted
|
||||
([5fbd618c](https://github.com/angular/angular.js/commit/5fbd618c2ff0dbaa4e19d0fd0e55921ce7d89478),
|
||||
[#7256](https://github.com/angular/angular.js/issues/7256))
|
||||
- **ngMessages:** annotate ngMessages controller for minification
|
||||
([0282ca97](https://github.com/angular/angular.js/commit/0282ca971df7923c8f3dba0eb0df544e244e5b93))
|
||||
- **numberFilter:** fix rounding error edge case
|
||||
([81d427b5](https://github.com/angular/angular.js/commit/81d427b5f0d3502f65e8db5beaa5ad837c9ede17),
|
||||
[#7453](https://github.com/angular/angular.js/issues/7453), [#7478](https://github.com/angular/angular.js/issues/7478))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **ngTouch:** add optional `ngSwipeDisableMouse` attribute to `ngSwipe` directives to ignore mouse events.
|
||||
([5a568b4f](https://github.com/angular/angular.js/commit/5a568b4f960cc5381b3911e3a6423aff2ff7f7f9),
|
||||
[#6627](https://github.com/angular/angular.js/issues/6627), [#6626](https://github.com/angular/angular.js/issues/6626))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **jqLite:** due to [d71dbb1a](https://github.com/angular/angular.js/commit/d71dbb1ae50f174680533492ce4c7db3ff74df00),
|
||||
the jQuery `detach()` method does not trigger the `$destroy` event.
|
||||
If you want to destroy Angular data attached to the element, use `remove()`.
|
||||
|
||||
|
||||
<a name="1.3.0-beta.8"></a>
|
||||
# 1.3.0-beta.8 accidental-haiku (2014-05-09)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** set $isolateScope correctly for sync template directives
|
||||
([562c4e42](https://github.com/angular/angular.js/commit/562c4e424b0ed5f8d4bffba0cd18e66db2059043),
|
||||
[#6942](https://github.com/angular/angular.js/issues/6942))
|
||||
- **$httpBackend:** Add missing expectHEAD() method
|
||||
([e1d61784](https://github.com/angular/angular.js/commit/e1d6178457045e721872022f71227b277cb88726),
|
||||
[#7320](https://github.com/angular/angular.js/issues/7320))
|
||||
- **$interpolate:** don't ReferenceError when context is undefined
|
||||
([924ee6db](https://github.com/angular/angular.js/commit/924ee6db06a2518224caada86769efedd21c0710),
|
||||
[#7230](https://github.com/angular/angular.js/issues/7230), [#7237](https://github.com/angular/angular.js/issues/7237))
|
||||
- **grunt-utils:** ensure special inline CSS works when `angular` is not a global
|
||||
([af72f40a](https://github.com/angular/angular.js/commit/af72f40a5512daa97c1f175a59b547c33cff1dc0),
|
||||
[#7176](https://github.com/angular/angular.js/issues/7176))
|
||||
- **injector:** invoke config blocks for module after all providers
|
||||
([c0b4e2db](https://github.com/angular/angular.js/commit/c0b4e2db9cbc8bc3164cedc4646145d3ab72536e),
|
||||
[#7139](https://github.com/angular/angular.js/issues/7139), [#7147](https://github.com/angular/angular.js/issues/7147))
|
||||
- **ngModelOptions:**
|
||||
- enable overriding the default with a debounce of zero
|
||||
([c56e32a7](https://github.com/angular/angular.js/commit/c56e32a7fa44e2edd2c70f663906720c7c9ad898),
|
||||
[#7205](https://github.com/angular/angular.js/issues/7205))
|
||||
- initialize ngModelOptions in prelink
|
||||
([fbf5ab8f](https://github.com/angular/angular.js/commit/fbf5ab8f17d28efeadb492c5a252f0778643f072),
|
||||
[#7281](https://github.com/angular/angular.js/issues/7281), [#7292](https://github.com/angular/angular.js/issues/7292))
|
||||
- **ngSanitize:** encode surrogate pair properly
|
||||
([627b0354](https://github.com/angular/angular.js/commit/627b0354ec35bef5c6dbfab6469168c2fadcbee5),
|
||||
[#5088](https://github.com/angular/angular.js/issues/5088), [#6911](https://github.com/angular/angular.js/issues/6911))
|
||||
- **ngSrc, ngSrcset:** only interpolate if all expressions are defined
|
||||
([8d180383](https://github.com/angular/angular.js/commit/8d180383014cbe38d58ff3eab083f51cfcfb8dde),
|
||||
[#6984](https://github.com/angular/angular.js/issues/6984))
|
||||
- **ngSwitch:** properly support case labels with different numbers of transclude fns
|
||||
([ac37915e](https://github.com/angular/angular.js/commit/ac37915ef64c60ec8f8d4e49e4d61d7baeb96ba0),
|
||||
[#7372](https://github.com/angular/angular.js/issues/7372), [#7373](https://github.com/angular/angular.js/issues/7373))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** allow SVG and MathML templates via special `type` property
|
||||
([f0e12ea7](https://github.com/angular/angular.js/commit/f0e12ea7fea853192e4eead00b40d6041c5f914a),
|
||||
[#7265](https://github.com/angular/angular.js/issues/7265))
|
||||
- **$interpolate:** add optional allOrNothing param
|
||||
([c2362e3f](https://github.com/angular/angular.js/commit/c2362e3f45e732a9defdb0ea59ce4ec5236fcd3a))
|
||||
- **FormController:** commit `$viewValue` of all child controls when form is submitted
|
||||
([a0ae07bd](https://github.com/angular/angular.js/commit/a0ae07bd4ee8d98654df4eb261d16ca55884e374),
|
||||
[#7017](https://github.com/angular/angular.js/issues/7017))
|
||||
- **NgMessages:** introduce the NgMessages module and directives
|
||||
([0f4016c8](https://github.com/angular/angular.js/commit/0f4016c84a47e01a0fb993867dfd0a64828c089c))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$http:** due to [ad4336f9](https://github.com/angular/angular.js/commit/ad4336f9359a073e272930f8f9bcd36587a8648f),
|
||||
|
||||
|
||||
Previously, it was possible to register a response interceptor like so:
|
||||
|
||||
```js
|
||||
// register the interceptor as a service
|
||||
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
|
||||
return function(promise) {
|
||||
return promise.then(function(response) {
|
||||
// do something on success
|
||||
return response;
|
||||
}, function(response) {
|
||||
// do something on error
|
||||
if (canRecover(response)) {
|
||||
return responseOrNewPromise
|
||||
}
|
||||
return $q.reject(response);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$httpProvider.responseInterceptors.push('myHttpInterceptor');
|
||||
```
|
||||
|
||||
Now, one must use the newer API introduced in v1.1.4 (4ae46814), like so:
|
||||
|
||||
```js
|
||||
$provide.factory('myHttpInterceptor', function($q) {
|
||||
return {
|
||||
response: function(response) {
|
||||
// do something on success
|
||||
return response;
|
||||
},
|
||||
responseError: function(response) {
|
||||
// do something on error
|
||||
if (canRecover(response)) {
|
||||
return responseOrNewPromise
|
||||
}
|
||||
return $q.reject(response);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
$httpProvider.interceptors.push('myHttpInterceptor');
|
||||
```
|
||||
|
||||
More details on the new interceptors API (which has been around as of v1.1.4) can be found at
|
||||
https://docs.angularjs.org/api/ng/service/$http#interceptors
|
||||
|
||||
|
||||
- **injector:** due to [c0b4e2db](https://github.com/angular/angular.js/commit/c0b4e2db9cbc8bc3164cedc4646145d3ab72536e),
|
||||
|
||||
Previously, config blocks would be able to control behaviour of provider registration, due to being
|
||||
invoked prior to provider registration. Now, provider registration always occurs prior to configuration
|
||||
for a given module, and therefore config blocks are not able to have any control over a providers
|
||||
registration.
|
||||
|
||||
**Example**:
|
||||
|
||||
Previously, the following:
|
||||
|
||||
```js
|
||||
angular.module('foo', [])
|
||||
.provider('$rootProvider', function() {
|
||||
this.$get = function() { ... }
|
||||
})
|
||||
.config(function($rootProvider) {
|
||||
$rootProvider.dependentMode = "B";
|
||||
})
|
||||
.provider('$dependentProvider', function($rootProvider) {
|
||||
if ($rootProvider.dependentMode === "A") {
|
||||
this.$get = function() {
|
||||
// Special mode!
|
||||
}
|
||||
} else {
|
||||
this.$get = function() {
|
||||
// something else
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
would have "worked", meaning behaviour of the config block between the registration of "$rootProvider"
|
||||
and "$dependentProvider" would have actually accomplished something and changed the behaviour of the
|
||||
app. This is no longer possible within a single module.
|
||||
|
||||
|
||||
- **ngModelOptions:** due to [adfc322b](https://github.com/angular/angular.js/commit/adfc322b04a58158fb9697e5b99aab9ca63c80bb),
|
||||
|
||||
|
||||
This commit changes the API on `NgModelController`, both semantically and
|
||||
in terms of adding and renaming methods.
|
||||
|
||||
* `$setViewValue(value)` -
|
||||
This method still changes the `$viewValue` but does not immediately commit this
|
||||
change through to the `$modelValue` as it did previously.
|
||||
Now the value is committed only when a trigger specified in an associated
|
||||
`ngModelOptions` directive occurs. If `ngModelOptions` also has a `debounce` delay
|
||||
specified for the trigger then the change will also be debounced before being
|
||||
committed.
|
||||
In most cases this should not have a significant impact on how `NgModelController`
|
||||
is used: If `updateOn` includes `default` then `$setViewValue` will trigger
|
||||
a (potentially debounced) commit immediately.
|
||||
* `$cancelUpdate()` - is renamed to `$rollbackViewValue()` and has the same meaning,
|
||||
which is to revert the current `$viewValue` back to the `$lastCommittedViewValue`,
|
||||
to cancel any pending debounced updates and to re-render the input.
|
||||
|
||||
To migrate code that used `$cancelUpdate()` follow the example below:
|
||||
|
||||
Before:
|
||||
|
||||
```js
|
||||
$scope.resetWithCancel = function (e) {
|
||||
if (e.keyCode == 27) {
|
||||
$scope.myForm.myInput1.$cancelUpdate();
|
||||
$scope.myValue = '';
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```js
|
||||
$scope.resetWithCancel = function (e) {
|
||||
if (e.keyCode == 27) {
|
||||
$scope.myForm.myInput1.$rollbackViewValue();
|
||||
$scope.myValue = '';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<a name="v1.3.0-beta.7"></a>
|
||||
# v1.3.0-beta.7 proper-attribution (2014-04-25)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$location:** don't clobber path during parsing of path
|
||||
([498835a1](https://github.com/angular/angular.js/commit/498835a1c4d0dc6397df4dd667796b09565fedf4),
|
||||
[#7199](https://github.com/angular/angular.js/issues/7199))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **scope:** ~10x speedup from sharing the child scope class.
|
||||
([8377e818](https://github.com/angular/angular.js/commit/8377e81827a840b9eb64f119de4bcbaba0ceb3be))
|
||||
|
||||
|
||||
<a name="v1.3.0-beta.6"></a>
|
||||
# v1.3.0-beta.6 expedient-caffeination (2014-04-21)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** ensure class-based animations always perform a domOperation if skipped
|
||||
([708f2ba9](https://github.com/angular/angular.js/commit/708f2ba9843b665e417b93c7df907194565db991),
|
||||
[#6957](https://github.com/angular/angular.js/issues/6957))
|
||||
- **$compile:**
|
||||
- reference correct directive name in ctreq error
|
||||
([1192531e](https://github.com/angular/angular.js/commit/1192531e9b48cd90cbb601b0c0fdeb12340c1885),
|
||||
[#7062](https://github.com/angular/angular.js/issues/7062), [#7067](https://github.com/angular/angular.js/issues/7067))
|
||||
- fix regression which affected old jQuery releases
|
||||
([ef64169d](https://github.com/angular/angular.js/commit/ef64169db32ffdf5e0e3ae2154ac434c6a55378b))
|
||||
- **$location:**
|
||||
- fix and test html5Mode url-parsing algorithm for legacy browsers
|
||||
([49e7c32b](https://github.com/angular/angular.js/commit/49e7c32bb45ce3984df6768ba7b2f6a723a4ebe7))
|
||||
- make legacy browsers behave like modern ones in html5Mode
|
||||
([3f047704](https://github.com/angular/angular.js/commit/3f047704c70a957596371fec554d3e1fb066a29d),
|
||||
[#6162](https://github.com/angular/angular.js/issues/6162), [#6421](https://github.com/angular/angular.js/issues/6421), [#6899](https://github.com/angular/angular.js/issues/6899), [#6832](https://github.com/angular/angular.js/issues/6832), [#6834](https://github.com/angular/angular.js/issues/6834))
|
||||
- **input:** don't dirty model when input event triggered due to placeholder change
|
||||
([ff428e72](https://github.com/angular/angular.js/commit/ff428e72837c85b9540ee9e5a3daa2c9477c90bb),
|
||||
[#2614](https://github.com/angular/angular.js/issues/2614), [#5960](https://github.com/angular/angular.js/issues/5960))
|
||||
- **limitTo:** do not convert Infinity to NaN
|
||||
([5dee9e4a](https://github.com/angular/angular.js/commit/5dee9e4a33ab2a0be6d8a8099297be3028771e0b),
|
||||
[#6771](https://github.com/angular/angular.js/issues/6771), [#7118](https://github.com/angular/angular.js/issues/7118))
|
||||
- **ngModelController:** introduce $cancelUpdate to cancel pending updates
|
||||
([940fcb40](https://github.com/angular/angular.js/commit/940fcb4090e96824a4abc50252aa36aaf239e937),
|
||||
[#6994](https://github.com/angular/angular.js/issues/6994), [#7014](https://github.com/angular/angular.js/issues/7014))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$resource:** Make stripping of trailing slashes configurable.
|
||||
([3878be52](https://github.com/angular/angular.js/commit/3878be52f6d95fca4c386d4a5523f3c8fcb04270))
|
||||
- **Scope:** add `$watchGroup` method for observing a set of expressions
|
||||
([21f93163](https://github.com/angular/angular.js/commit/21f93163384f36fc4ae0934387339380e3dc3e9c))
|
||||
- **injector:** "strict-DI" mode which disables "automatic" function annotation
|
||||
([4b1695ec](https://github.com/angular/angular.js/commit/4b1695ec61aac8de7fcac1dfe8b4b420f9842c38),
|
||||
[#6719](https://github.com/angular/angular.js/issues/6719), [#6717](https://github.com/angular/angular.js/issues/6717), [#4504](https://github.com/angular/angular.js/issues/4504), [#6069](https://github.com/angular/angular.js/issues/6069), [#3611](https://github.com/angular/angular.js/issues/3611))
|
||||
- **ngModelOptions:** custom triggers and debounce of ngModel updates
|
||||
([dbe381f2](https://github.com/angular/angular.js/commit/dbe381f29fc72490f8e3a5328d5c487b185fe652),
|
||||
[#1285](https://github.com/angular/angular.js/issues/1285))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** watch interpolated expressions individually
|
||||
([0ebfa0d1](https://github.com/angular/angular.js/commit/0ebfa0d112c8ba42242cb8353db91e93eb42b463))
|
||||
- **$interpolate:** speed up interpolation by recreating watchGroup approach
|
||||
([546cb429](https://github.com/angular/angular.js/commit/546cb429d9cea25a9bdadbb87dfd401366b0b908))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$interpolate:** due to [88c2193c](https://github.com/angular/angular.js/commit/88c2193c71954b9e7e7e4bdf636a2b168d36300d),
|
||||
the function returned by `$interpolate`
|
||||
no longer has a `.parts` array set on it.
|
||||
|
||||
Instead it has two arrays:
|
||||
* `.expressions`, an array of the expressions in the
|
||||
interpolated text. The expressions are parsed with
|
||||
`$parse`, with an extra layer converting them to strings
|
||||
when computed
|
||||
* `.separators`, an array of strings representing the
|
||||
separations between interpolations in the text.
|
||||
This array is **always** 1 item longer than the
|
||||
`.expressions` array for easy merging with it
|
||||
|
||||
|
||||
<a name="1.3.0-beta.5"></a>
|
||||
# 1.3.0-beta.5 chimeric-glitterfication (2014-04-03)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- insert elements at the start of the parent container instead of at the end
|
||||
([1cb8584e](https://github.com/angular/angular.js/commit/1cb8584e8490ecdb1b410a8846c4478c6c2c0e53),
|
||||
[#4934](https://github.com/angular/angular.js/issues/4934), [#6275](https://github.com/angular/angular.js/issues/6275))
|
||||
- ensure the CSS driver properly works with SVG elements
|
||||
([c67bd69c](https://github.com/angular/angular.js/commit/c67bd69c58812da82b1a3a31d430df7aad8a50a8),
|
||||
[#6030](https://github.com/angular/angular.js/issues/6030))
|
||||
- **$parse:** mark constant unary minus expressions as constant
|
||||
([7914d346](https://github.com/angular/angular.js/commit/7914d3463b5ec560c616a0c9fd008bc0e3f7c786),
|
||||
[#6932](https://github.com/angular/angular.js/issues/6932))
|
||||
- **Scope:**
|
||||
- revert the `__proto__` cleanup as that could cause regressions
|
||||
([71c11e96](https://github.com/angular/angular.js/commit/71c11e96c64d5d4eb71f48c1eb778c2ba5c63377))
|
||||
- more scope clean up on $destroy to minimize leaks
|
||||
([d64d41ed](https://github.com/angular/angular.js/commit/d64d41ed992430a4fc89cd415c03acf8d56022e6),
|
||||
[#6794](https://github.com/angular/angular.js/issues/6794), [#6856](https://github.com/angular/angular.js/issues/6856), [#6968](https://github.com/angular/angular.js/issues/6968))
|
||||
- **ngClass:** handle ngClassOdd/Even affecting the same classes
|
||||
([c9677920](https://github.com/angular/angular.js/commit/c9677920d462046710fc72ca422ab7400f551d2e),
|
||||
[#5271](https://github.com/angular/angular.js/issues/5271))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$animate:** due to [1cb8584e](https://github.com/angular/angular.js/commit/1cb8584e8490ecdb1b410a8846c4478c6c2c0e53),
|
||||
`$animate` will no longer default the after parameter to the last element of the parent
|
||||
container. Instead, when after is not specified, the new element will be inserted as the
|
||||
first child of the parent container.
|
||||
|
||||
To update existing code, change all instances of `$animate.enter()` or `$animate.move()` from:
|
||||
|
||||
`$animate.enter(element, parent);`
|
||||
|
||||
to:
|
||||
|
||||
`$animate.enter(element, parent, angular.element(parent[0].lastChild));`
|
||||
|
||||
|
||||
<a name="1.2.16"></a>
|
||||
# 1.2.16 badger-enumeration (2014-04-03)
|
||||
|
||||
@@ -1556,169 +1064,6 @@ to:
|
||||
[#2335](https://github.com/angular/angular.js/issues/2335), [#2665](https://github.com/angular/angular.js/issues/2665), [#6713](https://github.com/angular/angular.js/issues/6713))
|
||||
|
||||
|
||||
<a name="1.3.0-beta.4"></a>
|
||||
# 1.3.0-beta.4 inconspicuous-deception (2014-03-28)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- prevent cancellation timestamp from being too far in the future
|
||||
([ff5cf736](https://github.com/angular/angular.js/commit/ff5cf736e5b8073c8121295743873ccd04cc7d6b),
|
||||
[#6748](https://github.com/angular/angular.js/issues/6748))
|
||||
- make CSS blocking optional for class-based animations
|
||||
([1bebe36a](https://github.com/angular/angular.js/commit/1bebe36aa938890d61188762ed618b1b5e193634),
|
||||
[#6674](https://github.com/angular/angular.js/issues/6674), [#6739](https://github.com/angular/angular.js/issues/6739))
|
||||
- run CSS animations before JS animations to avoid style inheritance
|
||||
([2317af68](https://github.com/angular/angular.js/commit/2317af68510fe3b67526282dad697ad4dc621a19),
|
||||
[#6675](https://github.com/angular/angular.js/issues/6675))
|
||||
- **Scope:** aggressively clean up scope on $destroy to minimize leaks
|
||||
([f552f251](https://github.com/angular/angular.js/commit/f552f25171390e726ad7246ed18b994970bcf764),
|
||||
[#6794](https://github.com/angular/angular.js/issues/6794), [#6856](https://github.com/angular/angular.js/issues/6856))
|
||||
- **doc-gen:** Run Gulp on Windows too
|
||||
([47ba6014](https://github.com/angular/angular.js/commit/47ba60146032c0bfadeaa9f3816644b31fc33315),
|
||||
[#6346](https://github.com/angular/angular.js/issues/6346))
|
||||
- **filter.ngdoc:** Check if "input" variable is defined
|
||||
([4a6d4de5](https://github.com/angular/angular.js/commit/4a6d4de53ed1472c0cb2323292127495619d7ed9),
|
||||
[#6819](https://github.com/angular/angular.js/issues/6819))
|
||||
- **input:** don't perform HTML5 validation on updated model-value
|
||||
([b472d027](https://github.com/angular/angular.js/commit/b472d0275f2900beba3b1f2fcee821369f8c15c1),
|
||||
[#6796](https://github.com/angular/angular.js/issues/6796), [#6806](https://github.com/angular/angular.js/issues/6806))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$http:** add xhr statusText to completeRequest callback
|
||||
([1d2414ca](https://github.com/angular/angular.js/commit/1d2414ca93a0340840ea1e80c48edb51ec55cd48),
|
||||
[#2335](https://github.com/angular/angular.js/issues/2335), [#2665](https://github.com/angular/angular.js/issues/2665), [#6713](https://github.com/angular/angular.js/issues/6713))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$animate:** due to [1bebe36a](https://github.com/angular/angular.js/commit/1bebe36aa938890d61188762ed618b1b5e193634),
|
||||
|
||||
Any class-based animation code that makes use of transitions
|
||||
and uses the setup CSS classes (such as class-add and class-remove) must now
|
||||
provide a empty transition value to ensure that its styling is applied right
|
||||
away. In other words if your animation code is expecting any styling to be
|
||||
applied that is defined in the setup class then it will not be applied
|
||||
"instantly" unless a `transition:0s none` value is present in the styling
|
||||
for that CSS class. This situation is only the case if a transition is already
|
||||
present on the base CSS class once the animation kicks off.
|
||||
|
||||
Before:
|
||||
|
||||
.animated.my-class-add {
|
||||
opacity:0;
|
||||
transition:0.5s linear all;
|
||||
}
|
||||
.animated.my-class-add.my-class-add-active {
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
After:
|
||||
|
||||
.animated.my-class-add {
|
||||
transition:0s linear all;
|
||||
opacity:0;
|
||||
}
|
||||
.animated.my-class-add.my-class-add-active {
|
||||
transition:0.5s linear all;
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
Please view the documentation for ngAnimate for more info.
|
||||
|
||||
|
||||
<a name="1.3.0-beta.3"></a>
|
||||
# 1.3.0-beta.3 emotional-waffles (2014-03-21)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **ngAnimate:** support `webkitCancelRequestAnimationFrame` in addition to `webkitCancelAnimationFrame`
|
||||
([c839f78b](https://github.com/angular/angular.js/commit/c839f78b8f2d8d910bc2bfc9e41b3e3b67090ec1),
|
||||
[#6526](https://github.com/angular/angular.js/issues/6526))
|
||||
- **$http:** allow sending Blob data using `$http`
|
||||
([b8cc71d4](https://github.com/angular/angular.js/commit/b8cc71d476f76ff51e719fb76fb2348027c858ce),
|
||||
[#5012](https://github.com/angular/angular.js/issues/5012))
|
||||
- **$httpBackend:** don't error when JSONP callback is called with no parameter
|
||||
([6680b7b9](https://github.com/angular/angular.js/commit/6680b7b97c0326a80bdccaf0a35031e4af641e0e),
|
||||
[#4987](https://github.com/angular/angular.js/issues/4987), [#6735](https://github.com/angular/angular.js/issues/6735))
|
||||
- **$rootScope:** ng-repeat can't handle `NaN` values. #4605
|
||||
([fb6062fb](https://github.com/angular/angular.js/commit/fb6062fb9d83545730b993e94ac7482ffd43a62c),
|
||||
[#4605](https://github.com/angular/angular.js/issues/4605))
|
||||
- **$rootScope:** `$watchCollection` should call listener with old value
|
||||
([78057a94](https://github.com/angular/angular.js/commit/78057a945ef84cbb05f9417fe884cb8c28e67b44),
|
||||
[#2621](https://github.com/angular/angular.js/issues/2621), [#5661](https://github.com/angular/angular.js/issues/5661), [#5688](https://github.com/angular/angular.js/issues/5688), [#6736](https://github.com/angular/angular.js/issues/6736))
|
||||
- **angular.bootstrap:** allow angular to load only once
|
||||
([748a6c8d](https://github.com/angular/angular.js/commit/748a6c8d9d8d61c3ee18eec462abe8ff245d6a98),
|
||||
[#5863](https://github.com/angular/angular.js/issues/5863), [#5587](https://github.com/angular/angular.js/issues/5587))
|
||||
- **jqLite:** `inheritedData()` now traverses Shadow DOM boundaries via the `host` property of `DocumentFragment`
|
||||
([8a96f317](https://github.com/angular/angular.js/commit/8a96f317e594a5096d4fa56ceae4c685eec8ac8b),
|
||||
[#6637](https://github.com/angular/angular.js/issues/6637))
|
||||
- **ngCookie:** convert non-string values to string
|
||||
([36528310](https://github.com/angular/angular.js/commit/3652831084c3788f786046b907a7361d2e89c520),
|
||||
[#6151](https://github.com/angular/angular.js/issues/6151), [#6220](https://github.com/angular/angular.js/issues/6220))
|
||||
- **ngTouch:** update workaround for Webkit quirk
|
||||
([bc42950b](https://github.com/angular/angular.js/commit/bc42950b514b60f319812eeb87aae2915e394237),
|
||||
[#6302](https://github.com/angular/angular.js/issues/6302))
|
||||
- **orderBy:** support string predicates containing non-ident characters
|
||||
([37bc5ef4](https://github.com/angular/angular.js/commit/37bc5ef4d87f19da47d3ab454c43d1e532c4f924),
|
||||
[#6143](https://github.com/angular/angular.js/issues/6143), [#6144](https://github.com/angular/angular.js/issues/6144))
|
||||
- **select:** avoid checking option element's `selected` property in render
|
||||
([f40f54c6](https://github.com/angular/angular.js/commit/f40f54c6da4a5399fe18a89d068634bb491e9f1a),
|
||||
[#2448](https://github.com/angular/angular.js/issues/2448), [#5994](https://github.com/angular/angular.js/issues/5994))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** add support for `$observer` deregistration
|
||||
([299b220f](https://github.com/angular/angular.js/commit/299b220f5e05e1d4e26bfd58d0b2fd7329ca76b1),
|
||||
[#5609](https://github.com/angular/angular.js/issues/5609))
|
||||
- **ngMock.$httpBackend:** added support for function as URL matcher
|
||||
([d6cfcace](https://github.com/angular/angular.js/commit/d6cfcacee101f2738e0a224a3377232ff85f78a4),
|
||||
[#4580](https://github.com/angular/angular.js/issues/4580))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$compile:** due to [299b220f](https://github.com/angular/angular.js/commit/299b220f5e05e1d4e26bfd58d0b2fd7329ca76b1),
|
||||
calling `attr.$observe` no longer returns the observer function, but a
|
||||
deregistration function instead. To migrate the code follow the example below:
|
||||
|
||||
Before:
|
||||
|
||||
directive('directiveName', function() {
|
||||
return {
|
||||
link: function(scope, elm, attr) {
|
||||
var observer = attr.$observe('someAttr', function(value) {
|
||||
console.log(value);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
After:
|
||||
|
||||
directive('directiveName', function() {
|
||||
return {
|
||||
link: function(scope, elm, attr) {
|
||||
var observer = function(value) {
|
||||
console.log(value);
|
||||
};
|
||||
|
||||
attr.$observe('someAttr', observer);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
- **$httpBackend:** due to [6680b7b9](https://github.com/angular/angular.js/commit/6680b7b97c0326a80bdccaf0a35031e4af641e0e), the JSONP behavior for erroneous and empty responses changed:
|
||||
Previously, a JSONP response was regarded as erroneous if it was empty. Now Angular is listening to the
|
||||
correct events to detect errors, i.e. even empty responses can be successful.
|
||||
|
||||
|
||||
|
||||
<a name="v1.2.15"></a>
|
||||
# v1.2.15 beer-underestimating (2014-03-21)
|
||||
|
||||
@@ -1772,64 +1117,6 @@ After:
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-beta.2"></a>
|
||||
# 1.3.0-beta.2 silent-ventriloquism (2014-03-14)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$$rAF:** always fallback to a $timeout in case native rAF isn't supported
|
||||
([7b5e0199](https://github.com/angular/angular.js/commit/7b5e019981f352add88be2984de68e553d1bfa93),
|
||||
[#6654](https://github.com/angular/angular.js/issues/6654))
|
||||
- **$http:** don't convert 0 status codes to 404 for non-file protocols
|
||||
([56e73ea3](https://github.com/angular/angular.js/commit/56e73ea355c851fdfd574d6d2a9e2fcb75677945),
|
||||
[#6074](https://github.com/angular/angular.js/issues/6074), [#6155](https://github.com/angular/angular.js/issues/6155))
|
||||
- **ngAnimate:** setting classNameFilter disables animation inside ng-if
|
||||
([129e2e02](https://github.com/angular/angular.js/commit/129e2e021ab1d773874428cd1fb329eae72797c4),
|
||||
[#6539](https://github.com/angular/angular.js/issues/6539))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- whitelist blob urls for sanitization of data-bound image urls
|
||||
([47ab8df4](https://github.com/angular/angular.js/commit/47ab8df455df1f1391b760e1fbcc5c21645512b8),
|
||||
[#4623](https://github.com/angular/angular.js/issues/4623))
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-beta.1"></a>
|
||||
# 1.3.0-beta.1 retractable-eyebrow (2014-03-07)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** support templates with thead and tfoot root elements
|
||||
([53ec5e13](https://github.com/angular/angular.js/commit/53ec5e13e5955830b6751019eef232bd2125c0b6),
|
||||
[#6289](https://github.com/angular/angular.js/issues/6289))
|
||||
- **style:** expressions in style tags
|
||||
([0609453e](https://github.com/angular/angular.js/commit/0609453e1f9ae074f8d786df903096a6eadb6aa0),
|
||||
[#2387](https://github.com/angular/angular.js/issues/2387), [#6492](https://github.com/angular/angular.js/issues/6492))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **input:** support types date, time, datetime-local, month, week
|
||||
([46bd6dc8](https://github.com/angular/angular.js/commit/46bd6dc88de252886d75426efc2ce8107a5134e9),
|
||||
[#5864](https://github.com/angular/angular.js/issues/5864))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **build:** due to [eaa1d00b](https://github.com/angular/angular.js/commit/eaa1d00b24008f590b95ad099241b4003688cdda),
|
||||
As communicated before, IE8 is no longer supported.
|
||||
- **input:** types date, time, datetime-local, month, week now always
|
||||
require a `Date` object as model ([46bd6dc8](https://github.com/angular/angular.js/commit/46bd6dc88de252886d75426efc2ce8107a5134e9),
|
||||
[#5864](https://github.com/angular/angular.js/issues/5864))
|
||||
|
||||
For more info: http://blog.angularjs.org/2013/12/angularjs-13-new-release-approaches.html
|
||||
|
||||
|
||||
|
||||
<a name="1.2.14"></a>
|
||||
# 1.2.14 feisty-cryokinesis (2014-03-01)
|
||||
|
||||
@@ -2107,30 +1394,26 @@ The animation mock module has been renamed from `mock.animate` to `ngAnimateMock
|
||||
## Breaking Changes
|
||||
|
||||
- **$http:** due to [e1cfb195](https://github.com/angular/angular.js/commit/e1cfb1957feaf89408bccf48fae6f529e57a82fe),
|
||||
it is now necessary to seperately specify default HTTP headers for PUT, POST and PATCH requests, as these no longer share a single object.
|
||||
it is now necessary to separately specify default HTTP headers for PUT, POST and PATCH requests, as these no longer share a single object.
|
||||
|
||||
To migrate your code, follow the example below:
|
||||
To migrate your code, follow the example below:
|
||||
|
||||
Before:
|
||||
Before:
|
||||
|
||||
```
|
||||
// Will apply to POST, PUT and PATCH methods
|
||||
$httpProvider.defaults.headers.post = {
|
||||
"X-MY-CSRF-HEADER": "..."
|
||||
};
|
||||
```
|
||||
// Will apply to POST, PUT and PATCH methods
|
||||
$httpProvider.defaults.headers.post = {
|
||||
"X-MY-CSRF-HEADER": "..."
|
||||
};
|
||||
|
||||
After:
|
||||
After:
|
||||
|
||||
```
|
||||
// POST, PUT and PATCH default headers must be specified seperately,
|
||||
// as they do not share data.
|
||||
$httpProvider.defaults.headers.post =
|
||||
$httpProvider.defaults.headers.put =
|
||||
$httpProviders.defaults.headers.patch = {
|
||||
"X-MY-CSRF-HEADER": "..."
|
||||
};
|
||||
```
|
||||
// POST, PUT and PATCH default headers must be specified separately,
|
||||
// as they do not share data.
|
||||
$httpProvider.defaults.headers.post =
|
||||
$httpProvider.defaults.headers.put =
|
||||
$httpProviders.defaults.headers.patch = {
|
||||
"X-MY-CSRF-HEADER": "..."
|
||||
};
|
||||
|
||||
<a name="1.2.8"></a>
|
||||
# 1.2.8 interdimensional-cartography (2014-01-10)
|
||||
|
||||
+5
-7
@@ -40,13 +40,12 @@ would like to implement a new feature then consider what kind of change it is:
|
||||
[dev mailing list][angular-dev] or [IRC][irc] so that we can 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 Changes** can be crafted and submitted to the [GitHub Repository][github] as a Pull Request.
|
||||
* **Small Changes** can be crafted and submitted to [GitHub Repository][github] as a Pull Request.
|
||||
|
||||
|
||||
## <a name="docs"></a> Want a Doc Fix?
|
||||
If you want to help improve the docs, 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
|
||||
[Milestone:Docs Only](https://github.com/angular/angular.js/issues?milestone=24&state=open).
|
||||
If you want to help improve the docs, 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 [Milestone:Docs Only](https://github.com/angular/angular.js/issues?milestone=24&state=open).
|
||||
Comment on an issue to let others know what you're working on, or create a new issue if your work
|
||||
doesn't fit within the scope of any of the existing doc fix projects.
|
||||
|
||||
@@ -85,7 +84,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
|
||||
* Search [GitHub](https://github.com/angular/angular.js/pulls) for an open or closed Pull Request
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
* Please sign our [Contributor License Agreement (CLA)](#cla) before sending pull
|
||||
* Please sign our [Contributor License Agreement (CLA)](#signing-the-cla) before sending pull
|
||||
requests. We cannot accept code without this.
|
||||
* Make your changes in a new git branch
|
||||
|
||||
@@ -94,7 +93,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
```
|
||||
|
||||
* Create your patch, **including appropriate test cases**.
|
||||
* Follow our [Coding Rules](#rules).
|
||||
* Follow our [Coding Rules](#coding-rules).
|
||||
* Run the full Angular test suite, as described in the [developer documentation][dev-doc],
|
||||
and ensure that all tests pass.
|
||||
* Commit your changes using a descriptive commit message that follows our
|
||||
@@ -260,7 +259,6 @@ You can find out more detailed information about contributing in the
|
||||
[contribute]: http://docs.angularjs.org/misc/contribute
|
||||
[contributing]: http://docs.angularjs.org/misc/contribute
|
||||
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
[dev-doc]: https://docs.angularjs.org/guide
|
||||
[github]: https://github.com/angular/angular.js
|
||||
[groups]: https://groups.google.com/forum/?fromgroups#!forum/angular
|
||||
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
|
||||
|
||||
+2
-10
@@ -127,9 +127,6 @@ module.exports = function(grunt) {
|
||||
ngLocale: {
|
||||
files: { src: 'src/ngLocale/**/*.js' },
|
||||
},
|
||||
ngMessages: {
|
||||
files: { src: 'src/ngMessages/**/*.js' },
|
||||
},
|
||||
ngMock: {
|
||||
files: { src: 'src/ngMock/**/*.js' },
|
||||
},
|
||||
@@ -161,7 +158,7 @@ module.exports = function(grunt) {
|
||||
scenario: {
|
||||
dest: 'build/angular-scenario.js',
|
||||
src: [
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
'bower_components/jquery/jquery.js',
|
||||
util.wrap([files['angularSrc'], files['angularScenario']], 'ngScenario/angular')
|
||||
],
|
||||
styles: {
|
||||
@@ -198,10 +195,6 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-resource.js',
|
||||
src: util.wrap(files['angularModules']['ngResource'], 'module')
|
||||
},
|
||||
messages: {
|
||||
dest: 'build/angular-messages.js',
|
||||
src: util.wrap(files['angularModules']['ngMessages'], 'module')
|
||||
},
|
||||
animate: {
|
||||
dest: 'build/angular-animate.js',
|
||||
src: util.wrap(files['angularModules']['ngAnimate'], 'module')
|
||||
@@ -226,7 +219,6 @@ module.exports = function(grunt) {
|
||||
animate: 'build/angular-animate.js',
|
||||
cookies: 'build/angular-cookies.js',
|
||||
loader: 'build/angular-loader.js',
|
||||
messages: 'build/angular-messages.js',
|
||||
touch: 'build/angular-touch.js',
|
||||
resource: 'build/angular-resource.js',
|
||||
route: 'build/angular-route.js',
|
||||
@@ -239,7 +231,7 @@ module.exports = function(grunt) {
|
||||
'src/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/ngScenario/DescribeSpec.js',
|
||||
'!src/ng/directive/attrs.js', // legitimate xit here
|
||||
'!src/ng/directive/booleanAttrs.js', // legitimate xit here
|
||||
'!src/ngScenario/**/*.js'
|
||||
]
|
||||
},
|
||||
|
||||
Vendored
+3
-8
@@ -46,7 +46,7 @@ var angularFiles = {
|
||||
|
||||
'src/ng/directive/directives.js',
|
||||
'src/ng/directive/a.js',
|
||||
'src/ng/directive/attrs.js',
|
||||
'src/ng/directive/booleanAttrs.js',
|
||||
'src/ng/directive/form.js',
|
||||
'src/ng/directive/input.js',
|
||||
'src/ng/directive/ngBind.js',
|
||||
@@ -82,9 +82,6 @@ var angularFiles = {
|
||||
'ngCookies': [
|
||||
'src/ngCookies/cookies.js'
|
||||
],
|
||||
'ngMessages': [
|
||||
'src/ngMessages/messages.js'
|
||||
],
|
||||
'ngResource': [
|
||||
'src/ngResource/resource.js'
|
||||
],
|
||||
@@ -133,7 +130,6 @@ var angularFiles = {
|
||||
'test/auto/*.js',
|
||||
'test/ng/**/*.js',
|
||||
'test/ngAnimate/*.js',
|
||||
'test/ngMessages/*.js',
|
||||
'test/ngCookies/*.js',
|
||||
'test/ngResource/*.js',
|
||||
'test/ngRoute/**/*.js',
|
||||
@@ -143,7 +139,7 @@ var angularFiles = {
|
||||
],
|
||||
|
||||
'karma': [
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
'bower_components/jquery/jquery.js',
|
||||
'test/jquery_remove.js',
|
||||
'@angularSrc',
|
||||
'src/publishExternalApis.js',
|
||||
@@ -177,7 +173,7 @@ var angularFiles = {
|
||||
],
|
||||
|
||||
'karmaJquery': [
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
'bower_components/jquery/jquery.js',
|
||||
'test/jquery_alias.js',
|
||||
'@angularSrc',
|
||||
'src/publishExternalApis.js',
|
||||
@@ -195,7 +191,6 @@ var angularFiles = {
|
||||
|
||||
angularFiles['angularSrcModules'] = [].concat(
|
||||
angularFiles['angularModules']['ngAnimate'],
|
||||
angularFiles['angularModules']['ngMessages'],
|
||||
angularFiles['angularModules']['ngCookies'],
|
||||
angularFiles['angularModules']['ngResource'],
|
||||
angularFiles['angularModules']['ngRoute'],
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "AngularJS",
|
||||
"devDependencies": {
|
||||
"jquery": "2.1.1",
|
||||
"jquery": "1.10.2",
|
||||
"lunr.js": "0.4.3",
|
||||
"open-sans-fontface": "1.0.4",
|
||||
"google-code-prettify": "1.0.1",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
#!/usr/local/bin/node
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -123,12 +123,9 @@ then(function (tags) {
|
||||
value();
|
||||
}).
|
||||
then(function (tags) {
|
||||
var master = tags.pop();
|
||||
var stable = tags.pop();
|
||||
|
||||
return [
|
||||
{ name: stable.replace(/\d+$/, 'x'), tag: stable },
|
||||
{ name: 'master', tag: master}
|
||||
{ name: 'v1.0.x', tag: tags[0] },
|
||||
{ name: 'master', tag: tags[1] }
|
||||
];
|
||||
}).
|
||||
then(allInSeries(function (branch) {
|
||||
|
||||
+12
-1
@@ -2,10 +2,21 @@
|
||||
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
|
||||
.ng-cloak, .x-ng-cloak,
|
||||
.ng-hide:not(.ng-animate) {
|
||||
.ng-hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
ng\:form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ng-animate-block-transitions {
|
||||
transition:0s all!important;
|
||||
-webkit-transition:0s all!important;
|
||||
}
|
||||
|
||||
/* show the element during a show/hide animation when the
|
||||
* animation is ongoing, but the .ng-hide class is active */
|
||||
.ng-hide-add-active, .ng-hide-remove {
|
||||
display: block!important;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
|
||||
}
|
||||
});
|
||||
|
||||
element.on('$destroy', function() {
|
||||
element.bind('$destroy', function() {
|
||||
deregisterEmbedRootScope();
|
||||
embedRootScope.$destroy();
|
||||
});
|
||||
|
||||
+4
-4
@@ -274,13 +274,13 @@ var popoverElement = function() {
|
||||
this.contentElement = angular.element(inner.childNodes[1]);
|
||||
|
||||
//stop the click on the tooltip
|
||||
this.element.on('click', function(event) {
|
||||
this.element.bind('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
var self = this;
|
||||
angular.element(document.body).on('click',function(event) {
|
||||
angular.element(document.body).bind('click',function(event) {
|
||||
if(self.visible()) self.hide();
|
||||
});
|
||||
},
|
||||
@@ -359,7 +359,7 @@ directive.popover = ['popoverElement', function(popover) {
|
||||
restrict: 'A',
|
||||
priority : 500,
|
||||
link: function(scope, element, attrs) {
|
||||
element.on('click',function(event) {
|
||||
element.bind('click',function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if(popover.isSituatedAt(element) && popover.visible()) {
|
||||
@@ -396,7 +396,7 @@ directive.foldout = ['$http', '$animate','$window', function($http, $animate, $w
|
||||
if(/\/build\//.test($window.location.href)) {
|
||||
url = '/build/docs' + url;
|
||||
}
|
||||
element.on('click',function() {
|
||||
element.bind('click',function() {
|
||||
scope.$apply(function() {
|
||||
if(!container) {
|
||||
if(loading) return;
|
||||
|
||||
+5
-5
@@ -35,8 +35,8 @@ angular.module('ui.bootstrap.dropdown', [])
|
||||
|
||||
this.open = function( dropdownScope ) {
|
||||
if ( !openScope ) {
|
||||
$document.on('click', closeDropdown);
|
||||
$document.on('keydown', escapeKeyBind);
|
||||
$document.bind('click', closeDropdown);
|
||||
$document.bind('keydown', escapeKeyBind);
|
||||
}
|
||||
|
||||
if ( openScope && openScope !== dropdownScope ) {
|
||||
@@ -49,8 +49,8 @@ angular.module('ui.bootstrap.dropdown', [])
|
||||
this.close = function( dropdownScope ) {
|
||||
if ( openScope === dropdownScope ) {
|
||||
openScope = null;
|
||||
$document.off('click', closeDropdown);
|
||||
$document.off('keydown', escapeKeyBind);
|
||||
$document.unbind('click', closeDropdown);
|
||||
$document.unbind('keydown', escapeKeyBind);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -124,7 +124,7 @@ angular.module('ui.bootstrap.dropdown', [])
|
||||
return;
|
||||
}
|
||||
|
||||
element.on('click', function(event) {
|
||||
element.bind('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ angular.module('directives', [])
|
||||
terminal: true,
|
||||
compile: function(element) {
|
||||
var linenums = element.hasClass('linenum');// || element.parent()[0].nodeName === 'PRE';
|
||||
var match = /lang-(\S+)/.exec(element[0].className);
|
||||
var match = /lang-(\S)+/.exec(element.className);
|
||||
var lang = match && match[1];
|
||||
var html = element.html();
|
||||
element.html(window.prettyPrintOne(html, lang, linenums));
|
||||
|
||||
@@ -131,7 +131,7 @@ angular.module('search', [])
|
||||
return function(scope, element, attrs) {
|
||||
var ESCAPE_KEY_KEYCODE = 27,
|
||||
FORWARD_SLASH_KEYCODE = 191;
|
||||
angular.element($document[0].body).on('keydown', function(event) {
|
||||
angular.element($document[0].body).bind('keydown', function(event) {
|
||||
var input = element[0];
|
||||
if(event.keyCode == FORWARD_SLASH_KEYCODE && document.activeElement != input) {
|
||||
event.stopPropagation();
|
||||
@@ -140,7 +140,7 @@ angular.module('search', [])
|
||||
}
|
||||
});
|
||||
|
||||
element.on('keydown', function(event) {
|
||||
element.bind('keydown', function(event) {
|
||||
if(event.keyCode == ESCAPE_KEY_KEYCODE) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
describe("code", function() {
|
||||
var prettyPrintOne, oldPP;
|
||||
var compile, scope;
|
||||
|
||||
var any = jasmine.any;
|
||||
|
||||
beforeEach(module('directives'));
|
||||
|
||||
beforeEach(inject(function($rootScope, $compile) {
|
||||
// Provide stub for pretty print function
|
||||
oldPP = window.prettyPrintOne;
|
||||
prettyPrintOne = window.prettyPrintOne = jasmine.createSpy();
|
||||
|
||||
scope = $rootScope.$new();
|
||||
compile = $compile;
|
||||
}));
|
||||
|
||||
afterEach(function() {
|
||||
window.prettyPrintOne = oldPP;
|
||||
});
|
||||
|
||||
|
||||
it('should pretty print innerHTML', function() {
|
||||
compile('<code>var x;</code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith('var x;', null, false);
|
||||
});
|
||||
|
||||
it('should allow language declaration', function() {
|
||||
compile('<code class="lang-javascript"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), 'javascript', false);
|
||||
});
|
||||
|
||||
it('supports allow line numbers', function() {
|
||||
compile('<code class="linenum"></code>')(scope);
|
||||
expect(prettyPrintOne).toHaveBeenCalledWith(any(String), null, true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $injector:strictdi
|
||||
@fullName Explicit annotation required
|
||||
@description
|
||||
|
||||
This error occurs when attempting to invoke a function or provider which
|
||||
has not been explicitly annotated, while the application is running with
|
||||
strict-di mode enabled.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
angular.module("myApp", [])
|
||||
// BadController cannot be invoked, because
|
||||
// the dependencies to be injected are not
|
||||
// explicitly listed.
|
||||
.controller("BadController", function($scope, $http, $filter) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
To fix the error, explicitly annotate the function using either the inline
|
||||
bracket notation, or with the $inject property:
|
||||
|
||||
```
|
||||
function GoodController1($scope, $http, $filter) {
|
||||
// ...
|
||||
}
|
||||
GoodController1.$inject = ["$scope", "$http", "$filter"];
|
||||
|
||||
angular.module("myApp", [])
|
||||
// GoodController1 can be invoked because it
|
||||
// had an $inject property, which is an array
|
||||
// containing the dependency names to be
|
||||
// injected.
|
||||
.controller("GoodController1", GoodController1)
|
||||
|
||||
// GoodController2 can also be invoked, because
|
||||
// the dependencies to inject are listed, in
|
||||
// order, in the array, with the function to be
|
||||
// invoked trailing on the end.
|
||||
.controller("GoodController2", [
|
||||
"$scope",
|
||||
"$http",
|
||||
"$filter",
|
||||
function($scope, $http, $filter) {
|
||||
// ...
|
||||
}
|
||||
]);
|
||||
|
||||
```
|
||||
|
||||
For more information about strict-di mode, see {@link ng.directive:ngApp ngApp}
|
||||
and {@link api/angular.bootstrap angular.bootstrap}.
|
||||
@@ -1,21 +0,0 @@
|
||||
@ngdoc error
|
||||
@name ngModel:constexpr
|
||||
@fullName Non-Constant Expression
|
||||
@description
|
||||
|
||||
Some attributes used in conjunction with ngModel (such as ngTrueValue or ngFalseValue) will only
|
||||
accept constant expressions.
|
||||
|
||||
Examples using constant expressions include:
|
||||
|
||||
```
|
||||
<input type="checkbox" ng-model="..." ng-true-value="'truthyValue'">
|
||||
<input type="checkbox" ng-model="..." ng-false-value="0">
|
||||
```
|
||||
|
||||
Examples of non-constant expressions include:
|
||||
|
||||
```
|
||||
<input type="checkbox" ng-model="..." ng-true-value="someValue">
|
||||
<input type="checkbox" ng-model="..." ng-false-value="{foo: someScopeValue}">
|
||||
```
|
||||
@@ -808,21 +808,27 @@ then uses the information it obtains to compose hashbang URLs (such as
|
||||
|
||||
## Two-way binding to $location
|
||||
|
||||
Because `$location` uses getters/setters, you can use `ng-model-options="{ getterSetter: true }"`
|
||||
to bind it to `ngModel`:
|
||||
|
||||
The Angular's compiler currently does not support two-way binding for methods (see [issue](https://github.com/angular/angular.js/issues/404)). If you should require two-way binding
|
||||
to the $location object (using {@link input[text] ngModel} directive on an input
|
||||
field), you will need to specify an extra model property (e.g. `locationPath`) with two {@link ng.$rootScope.Scope#$watch $watchers}
|
||||
which push $location updates in both directions. For example:
|
||||
<example module="locationExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="LocationController">
|
||||
<input type="text" ng-model="locationPath" ng-model-options="{ getterSetter: true }" />
|
||||
<input type="text" ng-model="locationPath" />
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('locationExample', [])
|
||||
.controller('LocationController', ['$scope', '$location', function($scope, $location) {
|
||||
$scope.locationPath = function (newLocation) {
|
||||
return $location.path(newLocation);
|
||||
};
|
||||
.controller('LocationController', ['$scope', '$location', function ($scope, $location) {
|
||||
$scope.$watch('locationPath', function(path) {
|
||||
$location.path(path);
|
||||
});
|
||||
$scope.$watch(function() {
|
||||
return $location.path();
|
||||
}, function(path) {
|
||||
$scope.locationPath = path;
|
||||
});
|
||||
}]);
|
||||
</file>
|
||||
</example>
|
||||
|
||||
@@ -33,14 +33,23 @@ Below is a quick example of animations being enabled for `ngShow` and `ngHide`:
|
||||
background:white;
|
||||
}
|
||||
|
||||
.sample-show-hide {
|
||||
.sample-show-hide.ng-hide-add, .sample-show-hide.ng-hide-remove {
|
||||
-webkit-transition:all linear 0.5s;
|
||||
-moz-transition:all linear 0.5s;
|
||||
-o-transition:all linear 0.5s;
|
||||
transition:all linear 0.5s;
|
||||
display:block!important;
|
||||
}
|
||||
|
||||
.sample-show-hide.ng-hide {
|
||||
.sample-show-hide.ng-hide-add.ng-hide-add-active,
|
||||
.sample-show-hide.ng-hide-remove {
|
||||
opacity:0;
|
||||
}
|
||||
|
||||
.sample-show-hide.ng-hide-add,
|
||||
.sample-show-hide.ng-hide-remove.ng-hide-remove-active {
|
||||
opacity:1;
|
||||
}
|
||||
</file>
|
||||
</example>
|
||||
|
||||
@@ -242,15 +251,18 @@ Although the CSS is a little different then what we saw before, the idea is the
|
||||
A handful of common AngularJS directives support and trigger animation hooks whenever any major event occurs during its life cycle.
|
||||
The table below explains in detail which animation events are triggered
|
||||
|
||||
| Directive | Supported Animations |
|
||||
|-------------------------------------------------------------------------------------|------------------------------------------|
|
||||
| {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave, and move |
|
||||
| {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
|
||||
| {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
|
||||
| {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
|
||||
| {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
|
||||
| {@link ng.directive:ngClass#usage_animations ngClass or {{class}}} | add and remove |
|
||||
| {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
|
||||
-| Directive | Supported Animations |
|
||||
-|-----------------------------------------------------------------|--------------------------------------------------------------------------|
|
||||
-| {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move |
|
||||
-| {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
|
||||
-| {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
|
||||
-| {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
|
||||
-| {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
|
||||
-| {@link ng.directive:ngClass#usage_animations ngClass} | add and remove |
|
||||
-| {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
|
||||
-| {@link ng.directive:form#usage_animations form} | add and remove (dirty, pristine, valid, invalid & all other validations) |
|
||||
-| {@link ng.directive:ngModel#usage_animations ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
|
||||
|
||||
|
||||
For a full breakdown of the steps involved during each animation event, refer to the {@link ngAnimate.$animate API docs}.
|
||||
|
||||
@@ -261,8 +273,8 @@ making calls to it when needed.
|
||||
|
||||
```js
|
||||
myModule.directive('my-directive', ['$animate', function($animate) {
|
||||
return function(scope, element, attrs) {
|
||||
element.on('click', function() {
|
||||
return function(element, scope, attrs) {
|
||||
element.bind('click', function() {
|
||||
if(element.hasClass('clicked')) {
|
||||
$animate.removeClass(element, 'clicked');
|
||||
} else {
|
||||
|
||||
@@ -38,7 +38,11 @@ initialization.
|
||||
|
||||
<html ng-app>
|
||||
|
||||
3. If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
|
||||
3. If you require IE7 support add `id="ng-app"`
|
||||
|
||||
<html ng-app id="ng-app">
|
||||
|
||||
4. If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
|
||||
to make IE happy. (This is here for historical reasons, and we no longer recommend use of
|
||||
`ng:`.)
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
|
||||
}
|
||||
|
||||
function mouseup() {
|
||||
$document.off('mousemove', mousemove);
|
||||
$document.off('mouseup', mouseup);
|
||||
$document.unbind('mousemove', mousemove);
|
||||
$document.unbind('mouseup', mouseup);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -37,10 +37,10 @@ Let's start with input fields for quantity and cost whose values are multiplied
|
||||
<div ng-app ng-init="qty=1;cost=2">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" min="0" ng-model="qty">
|
||||
Quantity: <input type="number" ng-model="qty">
|
||||
</div>
|
||||
<div>
|
||||
Costs: <input type="number" min="0" ng-model="cost">
|
||||
Costs: <input type="number" ng-model="cost">
|
||||
</div>
|
||||
<div>
|
||||
<b>Total:</b> {{qty * cost | currency}}
|
||||
@@ -128,10 +128,10 @@ different currencies and also pay the invoice.
|
||||
<div ng-app="invoice1" ng-controller="InvoiceController as invoice">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
|
||||
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||
</div>
|
||||
<div>
|
||||
Costs: <input type="number" min="0" ng-model="invoice.cost" required >
|
||||
Costs: <input type="number" ng-model="invoice.cost" required >
|
||||
<select ng-model="invoice.inCurr">
|
||||
<option ng-repeat="c in invoice.currencies">{{c}}</option>
|
||||
</select>
|
||||
@@ -228,10 +228,10 @@ Let's refactor our example and move the currency conversion into a service in an
|
||||
<div ng-app="invoice2" ng-controller="InvoiceController as invoice">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
|
||||
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||
</div>
|
||||
<div>
|
||||
Costs: <input type="number" min="0" ng-model="invoice.cost" required >
|
||||
Costs: <input type="number" ng-model="invoice.cost" required >
|
||||
<select ng-model="invoice.inCurr">
|
||||
<option ng-repeat="c in invoice.currencies">{{c}}</option>
|
||||
</select>
|
||||
@@ -356,10 +356,10 @@ The following example shows how this is done with Angular:
|
||||
<div ng-app="invoice3" ng-controller="InvoiceController as invoice">
|
||||
<b>Invoice:</b>
|
||||
<div>
|
||||
Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
|
||||
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||
</div>
|
||||
<div>
|
||||
Costs: <input type="number" min="0" ng-model="invoice.cost" required >
|
||||
Costs: <input type="number" ng-model="invoice.cost" required >
|
||||
<select ng-model="invoice.inCurr">
|
||||
<option ng-repeat="c in invoice.currencies">{{c}}</option>
|
||||
</select>
|
||||
|
||||
@@ -158,7 +158,7 @@ Things to notice in the example above:
|
||||
- The `ng-controller` directive is used to (implicitly) create a scope for our template, and the
|
||||
scope is augmented (managed) by the `SpicyController` Controller.
|
||||
- `SpicyController` is just a plain JavaScript function. As an (optional) naming convention the name
|
||||
starts with capital letter and ends with "Controller".
|
||||
starts with capital letter and ends with "Controller" or "Controller".
|
||||
- Assigning a property to `$scope` creates or updates the model.
|
||||
- Controller methods can be created through direct assignment to scope (see the `chiliSpicy` method)
|
||||
- The Controller methods and properties are available in the template (for the `<div>` element and
|
||||
|
||||
@@ -797,8 +797,8 @@ element?
|
||||
}
|
||||
|
||||
function mouseup() {
|
||||
$document.off('mousemove', mousemove);
|
||||
$document.off('mouseup', mouseup);
|
||||
$document.unbind('mousemove', mousemove);
|
||||
$document.unbind('mouseup', mouseup);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -12,7 +12,7 @@ is now in maintenance mode.
|
||||
</div>
|
||||
|
||||
As applications grow in size and complexity, it becomes unrealistic to rely on manual testing to
|
||||
verify the correctness of new features, catch bugs and notice regressions. Unit tests
|
||||
verify the correctness of new features, catch bugs and notice regressions. End to end tests
|
||||
are the first line of defense for catching bugs, but sometimes issues come up with integration
|
||||
between components which can't be captured in a unit test. End to end tests are made to find
|
||||
these problems.
|
||||
@@ -27,7 +27,7 @@ Protractor is a [Node.js](http://nodejs.org) program, and runs end to end tests
|
||||
written in JavaScript and run with node. Protractor uses [WebDriver](https://code.google.com/p/selenium/wiki/GettingStarted)
|
||||
to control browsers and simulate user actions.
|
||||
|
||||
For more information on Protractor, view [getting started](https://github.com/angular/protractor/blob/master/docs/overview.md)
|
||||
For more information on Protractor, view [getting started](https://github.com/angular/protractor/blob/master/docs/getting-started.md)
|
||||
or the [api docs](https://github.com/angular/protractor/blob/master/docs/api.md).
|
||||
|
||||
Protractor uses [Jasmine](http://jasmine.github.io/1.3/introduction.html) for its test syntax.
|
||||
|
||||
@@ -202,122 +202,3 @@ expose a `$event` object within the scope of that expression.
|
||||
|
||||
Note in the example above how we can pass in `$event` to `clickMe`, but how it does not show up
|
||||
in `{{$event}}`. This is because `$event` is outside the scope of that binding.
|
||||
|
||||
|
||||
## One-time binding
|
||||
|
||||
An expression that starts with `::` is considered a one-time expression. One-time expressions
|
||||
will stop recalculating once they are stable, which happens after the first digest if the expression
|
||||
result is a non-undefined value (see value stabilization algorithm below).
|
||||
|
||||
<example module="oneTimeBidingExampleApp">
|
||||
<file name="index.html">
|
||||
<div ng-controller="EventController">
|
||||
<button ng-click="clickMe($event)">Click Me</button>
|
||||
<p id="one-time-binding-example">One time binding: {{::name}}</p>
|
||||
<p id="normal-binding-example">Normal binding: {{name}}</p>
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('oneTimeBidingExampleApp', []).
|
||||
controller('EventController', ['$scope', function($scope) {
|
||||
var counter = 0;
|
||||
var names = ['Igor', 'Misko', 'Chirayu', 'Lucas'];
|
||||
/*
|
||||
* expose the event object to the scope
|
||||
*/
|
||||
$scope.clickMe = function(clickEvent) {
|
||||
$scope.name = names[counter % names.length];
|
||||
counter++;
|
||||
};
|
||||
}]);
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should freeze binding after its value has stabilized', function() {
|
||||
var oneTimeBiding = element(by.id('one-time-binding-example'));
|
||||
var normalBinding = element(by.id('normal-binding-example'));
|
||||
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding:');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding:');
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Igor');
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Misko');
|
||||
|
||||
element(by.buttonText('Click Me')).click();
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Lucas');
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
### Why this feature
|
||||
|
||||
The main purpose of one-time binding expression is to provide a way to create a binding
|
||||
that gets deregistered and frees up resources once the binding is stabilized.
|
||||
Reducing the number of expressions being watched makes the digest loop faster and allows more
|
||||
information to be displayed at the same time.
|
||||
|
||||
|
||||
### Value stabilization algorithm
|
||||
|
||||
One-time binding expressions will retain the value of the expression at the end of the
|
||||
digest cycle as long as that value is not undefined. If the value of the expression is set
|
||||
within the digest loop and later, within the same digest loop, it is set to undefined,
|
||||
then the expression is not fulfilled and will remain watched.
|
||||
|
||||
1. Given an expression that starts with `::` when a digest loop is entered and expression
|
||||
is dirty-checked store the value as V
|
||||
2. If V is not undefined mark the result of the expression as stable and schedule a task
|
||||
to deregister the watch for this expression when we exit the digest loop
|
||||
3. Process the digest loop as normal
|
||||
4. When digest loop is done and all the values have settled process the queue of watch
|
||||
deregistration tasks. For each watch to be deregistered check if it still evaluates
|
||||
to value that is not `undefined`. If that's the case, deregister the watch. Otherwise
|
||||
keep dirty-checking the watch in the future digest loops by following the same
|
||||
algorithm starting from step 1
|
||||
|
||||
|
||||
### How to benefit from one-time binding
|
||||
|
||||
When interpolating text or attributes. If the expression, once set, will not change
|
||||
then it is a candidate for one-time expression.
|
||||
|
||||
```html
|
||||
<div name="attr: {{::color}}">text: {{::name}}</div>
|
||||
```
|
||||
|
||||
When using a directive with bidirectional binding and the parameters will not change
|
||||
|
||||
```js
|
||||
someModule.directive('someDirective', function() {
|
||||
return {
|
||||
scope: {
|
||||
name: '=',
|
||||
color: '@'
|
||||
},
|
||||
template: '{{name}}: {{color}}'
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
<div some-directive name=“::myName” color=“My color is {{::myColor}}”></div>
|
||||
```
|
||||
|
||||
|
||||
When using a directive that takes an expression
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li ng-repeat="item in ::items">{{item.name}};</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
|
||||
@@ -63,8 +63,6 @@ To allow styling of form as well as controls, `ngModel` adds these CSS classes:
|
||||
- `ng-invalid`
|
||||
- `ng-pristine`
|
||||
- `ng-dirty`
|
||||
- `ng-touched`
|
||||
- `ng-untouched`
|
||||
|
||||
The following example uses the CSS to display validity of each form control.
|
||||
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
|
||||
@@ -186,84 +184,6 @@ This allows us to extend the above example with these features:
|
||||
|
||||
|
||||
|
||||
# Custom triggers
|
||||
|
||||
By default, any change to the content will trigger a model update and form validation. You can
|
||||
override this behavior using the {@link ng.directive:ngModelOptions ngModelOptions} directive to
|
||||
bind only to specified list of events. I.e. `ng-model-options="{ updateOn: 'blur' }"` will update
|
||||
and validate only after the control loses focus. You can set several events using a space delimited
|
||||
list. I.e. `ng-model-options="{ updateOn: 'mousedown blur' }"`
|
||||
|
||||
If you want to keep the default behavior and just add new events that may trigger the model update
|
||||
and validation, add "default" as one of the specified events.
|
||||
|
||||
I.e. `ng-model-options="{ updateOn: 'default blur' }"`
|
||||
|
||||
The following example shows how to override immediate updates. Changes on the inputs within the form will update the model
|
||||
only when the control loses focus (blur event).
|
||||
|
||||
<example module="customTriggerExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="ExampleController">
|
||||
<form>
|
||||
Name:
|
||||
<input type="text" ng-model="user.name" ng-model-options="{ updateOn: 'blur' }" /><br />
|
||||
Other data:
|
||||
<input type="text" ng-model="user.data" /><br />
|
||||
</form>
|
||||
<pre>username = "{{user.name}}"</pre>
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('customTriggerExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.user = {};
|
||||
}]);
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
|
||||
# Non-immediate (debounced) model updates
|
||||
|
||||
You can delay the model update/validation by using the `debounce` key with the
|
||||
{@link ng.directive:ngModelOptions ngModelOptions} directive. This delay will also apply to
|
||||
parsers, validators and model flags like `$dirty` or `$pristine`.
|
||||
|
||||
I.e. `ng-model-options="{ debounce: 500 }"` will wait for half a second since
|
||||
the last content change before triggering the model update and form validation.
|
||||
|
||||
If custom triggers are used, custom debouncing timeouts can be set for each event using an object
|
||||
in `debounce`. This can be useful to force immediate updates on some specific circumstances
|
||||
(like blur events).
|
||||
|
||||
I.e. `ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"`
|
||||
|
||||
If those attributes are added to an element, they will be applied to all the child elements and controls that inherit from it unless they are
|
||||
overridden.
|
||||
|
||||
This example shows how to debounce model changes. Model will be updated only 250 milliseconds after last change.
|
||||
|
||||
<example module="debounceExample">
|
||||
<file name="index.html">
|
||||
<div ng-controller="ExampleController">
|
||||
<form>
|
||||
Name:
|
||||
<input type="text" ng-model="user.name" ng-model-options="{ debounce: 250 }" /><br />
|
||||
</form>
|
||||
<pre>username = "{{user.name}}"</pre>
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('debounceExample', [])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.user = {};
|
||||
}]);
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
|
||||
# Custom Validation
|
||||
|
||||
Angular provides basic implementation for most common html5 {@link ng.directive:input input}
|
||||
|
||||
@@ -81,7 +81,7 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
|
||||
### General
|
||||
|
||||
* **Javascript minification: **[Background](http://thegreenpizza.github.io/2013/05/25/building-minification-safe-angular.js-applications/), [ng-annotate automation tool](https://github.com/olov/ng-annotate)
|
||||
* **Javascript minification: **[Background](http://thegreenpizza.github.io/2013/05/25/building-minification-safe-angular.js-applications/), [ngmin automation tool](http://www.thinkster.io/pick/XlWneEZCqY/angularjs-ngmin)
|
||||
* **Analytics and Logging:** [Angularyitcs (Google Analytics)](http://ngmodules.org/modules/angularytics), [Angulartics (Analytics)](https://github.com/luisfarzati/angulartics), [Logging Client-Side Errors](http://www.bennadel.com/blog/2542-Logging-Client-Side-Errors-With-AngularJS-And-Stacktrace-js.htm)
|
||||
* **SEO:** [By hand](http://www.yearofmoo.com/2012/11/angularjs-and-seo.html), [prerender.io](http://prerender.io/), [Brombone](http://www.brombone.com/), [SEO.js](http://getseojs.com/), [SEO4Ajax](http://www.seo4ajax.com/)
|
||||
|
||||
|
||||
@@ -1,391 +1,17 @@
|
||||
@ngdoc overview
|
||||
@name Migrating from Previous Versions
|
||||
@name Migrating from 1.0 to 1.2
|
||||
@description
|
||||
|
||||
Minor version releases in AngularJS introduce several breaking changes that may require changes to your
|
||||
application's source code; for instance from 1.0 to 1.2 and from 1.2 to 1.3.
|
||||
|
||||
Although we try to avoid breaking changes, there are some cases where it is unavoidable.
|
||||
|
||||
* AngularJS has undergone thorough security reviews to make applications safer by default,
|
||||
which drives many of these changes.
|
||||
* Several new features, especially animations, would not be possible without a few changes.
|
||||
* Finally, some outstanding bugs were best fixed by changing an existing API.
|
||||
|
||||
# Migrating from 1.2 to 1.3
|
||||
|
||||
- **$parse:**
|
||||
- due to [77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5),
|
||||
|
||||
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
|
||||
This is to disallow changing the behaviour of existing functions
|
||||
in an unforseen fashion.
|
||||
- due to [6081f207](https://github.com/angular/angular.js/commit/6081f20769e64a800ee8075c168412b21f026d99),
|
||||
|
||||
The (deprecated) __proto__ propery does not work inside angular expressions
|
||||
anymore.
|
||||
- due to [48fa3aad](https://github.com/angular/angular.js/commit/48fa3aadd546036c7e69f71046f659ab1de244c6),
|
||||
|
||||
This prevents the use of __{define,lookup}{Getter,Setter}__ inside angular
|
||||
expressions. If you really need them for some reason, please wrap/bind them to make them
|
||||
less dangerous, then make them available through the scope object.
|
||||
- due to [528be29d](https://github.com/angular/angular.js/commit/528be29d1662122a34e204dd607e1c0bd9c16bbc),
|
||||
|
||||
This prevents the use of `Object` inside angular expressions.
|
||||
If you need Object.keys, make it accessible in the scope.
|
||||
- **Angular.copy:** due to [b59b04f9](https://github.com/angular/angular.js/commit/b59b04f98a0b59eead53f6a53391ce1bbcbe9b57),
|
||||
|
||||
|
||||
This changes `angular.copy` so that it applies the prototype of the original
|
||||
object to the copied object. Previously, `angular.copy` would copy properties
|
||||
of the original object's prototype chain directly onto the copied object.
|
||||
|
||||
This means that if you iterate over only the copied object's `hasOwnProperty`
|
||||
properties, it will no longer contain the properties from the prototype.
|
||||
This is actually much more reasonable behaviour and it is unlikely that
|
||||
applications are actually relying on this.
|
||||
|
||||
If this behaviour is relied upon, in an app, then one should simply iterate
|
||||
over all the properties on the object (and its inherited properties) and
|
||||
not filter them with `hasOwnProperty`.
|
||||
|
||||
**Be aware that this change also uses a feature that is not compatible with
|
||||
IE8.** If you need this to work on IE8 then you would need to provide a polyfill
|
||||
for `Object.create` and `Object.getPrototypeOf`.
|
||||
- **core:** due to [bdfc9c02](https://github.com/angular/angular.js/commit/bdfc9c02d021e08babfbc966a007c71b4946d69d),
|
||||
values 'f', '0', 'false', 'no', 'n', '[]' are no longer
|
||||
treated as falsy. Only JavaScript falsy values are now treated as falsy by the
|
||||
expression parser; there are six of them: false, null, undefined, NaN, 0 and "".
|
||||
|
||||
Closes #3969
|
||||
Closes #4277
|
||||
Closes #7960
|
||||
|
||||
|
||||
- **$compile:** due to [2cde927e](https://github.com/angular/angular.js/commit/2cde927e58c8d1588569d94a797e43cdfbcedaf9),
|
||||
|
||||
|
||||
Requesting isolate scope and any other scope on a single element is an error.
|
||||
Before this change, the compiler let two directives request a child scope
|
||||
and an isolate scope if the compiler applied them in the order of non-isolate
|
||||
scope directive followed by isolate scope directive.
|
||||
|
||||
Now the compiler will error regardless of the order.
|
||||
|
||||
If you find that your code is now throwing a `$compile:multidir` error,
|
||||
check that you do not have directives on the same element that are trying
|
||||
to request both an isolate and a non-isolate scope and fix your code.
|
||||
|
||||
Closes #4402
|
||||
Closes #4421
|
||||
- **NgModel:** due to [1be9bb9d](https://github.com/angular/angular.js/commit/1be9bb9d3527e0758350c4f7417a4228d8571440),
|
||||
|
||||
|
||||
If an expression is used on ng-pattern (such as `ng-pattern="exp"`) or on the
|
||||
pattern attribute (something like on `pattern="{{ exp }}"`) and the expression
|
||||
itself evaluates to a string then the validator will not parse the string as a
|
||||
literal regular expression object (a value like `/abc/i`). Instead, the entire
|
||||
string will be created as the regular expression to test against. This means
|
||||
that any expression flags will not be placed on the RegExp object. To get around
|
||||
this limitation, use a regular expression object as the value for the expression.
|
||||
|
||||
//before
|
||||
$scope.exp = '/abc/i';
|
||||
|
||||
//after
|
||||
$scope.exp = /abc/i;
|
||||
- **Scope:** due to [8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d),
|
||||
Scope#$id is now of time number rather than string. Since the
|
||||
id is primarily being used for debugging purposes this change should not affect
|
||||
anyone.
|
||||
- **forEach:** due to [55991e33](https://github.com/angular/angular.js/commit/55991e33af6fece07ea347a059da061b76fc95f5),
|
||||
forEach will iterate only over the initial number of items in
|
||||
the array. So if items are added to the array during the iteration, these won't
|
||||
be iterated over during the initial forEach call.
|
||||
|
||||
This change also makes our forEach behave more like Array#forEach.
|
||||
- **jqLite:** due to [a196c8bc](https://github.com/angular/angular.js/commit/a196c8bca82a28c08896d31f1863cf4ecd11401c),
|
||||
previously it was possible to set jqLite data on Text/Comment
|
||||
nodes, but now that is allowed only on Element and Document nodes just like in
|
||||
jQuery. We don't expect that app code actually depends on this accidental feature.
|
||||
|
||||
- **$resource:** due to [d3c50c84](https://github.com/angular/angular.js/commit/d3c50c845671f0f8bcc3f7842df9e2fb1d1b1c40),
|
||||
|
||||
If you expected `$resource` to strip these types of properties before,
|
||||
you will have to manually do this yourself now.
|
||||
|
||||
- **angular.toJson:** due to [c054288c](https://github.com/angular/angular.js/commit/c054288c9722875e3595e6e6162193e0fb67a251),
|
||||
|
||||
If you expected `toJson` to strip these types of properties before,
|
||||
you will have to manually do this yourself now.
|
||||
|
||||
- **$compile:** due to [eec6394a](https://github.com/angular/angular.js/commit/eec6394a342fb92fba5270eee11c83f1d895e9fb), The `replace` flag for defining directives that
|
||||
replace the element that they are on will be removed in the next major angular version.
|
||||
This feature has difficult semantics (e.g. how attributes are merged) and leads to more
|
||||
problems compared to what it solves. Also, with Web Components it is normal to have
|
||||
custom elements in the DOM.
|
||||
|
||||
- **$parse:** due to [fa6e411d](https://github.com/angular/angular.js/commit/fa6e411da26824a5bae55f37ce7dbb859653276d),
|
||||
promise unwrapping has been removed. It has been deprecated since 1.2.0-rc.3.
|
||||
It can no longer be turned on.
|
||||
Two methods have been removed:
|
||||
* `$parseProvider.unwrapPromises`
|
||||
* `$parseProvider.logPromiseWarnings`
|
||||
|
||||
- **Scope:** due to [82f45aee](https://github.com/angular/angular.js/commit/82f45aee5bd84d1cc53fb2e8f645d2263cdaacbc),
|
||||
[#7445](https://github.com/angular/angular.js/issues/7445),
|
||||
[#7523](https://github.com/angular/angular.js/issues/7523)
|
||||
`$broadcast` and `$emit` will now reset the `currentScope` property of the event to
|
||||
null once the event finished propagating. If any code depends on asynchronously accessing their
|
||||
`currentScope` property, it should be migrated to use `targetScope` instead. All of these cases
|
||||
should be considered programming bugs.
|
||||
|
||||
- **jqLite:** due to [d71dbb1a](https://github.com/angular/angular.js/commit/d71dbb1ae50f174680533492ce4c7db3ff74df00),
|
||||
the jQuery `detach()` method does not trigger the `$destroy` event.
|
||||
If you want to destroy Angular data attached to the element, use `remove()`.
|
||||
|
||||
|
||||
- **$http:** due to [ad4336f9](https://github.com/angular/angular.js/commit/ad4336f9359a073e272930f8f9bcd36587a8648f),
|
||||
|
||||
|
||||
Previously, it was possible to register a response interceptor like so:
|
||||
|
||||
```js
|
||||
// register the interceptor as a service
|
||||
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
|
||||
return function(promise) {
|
||||
return promise.then(function(response) {
|
||||
// do something on success
|
||||
return response;
|
||||
}, function(response) {
|
||||
// do something on error
|
||||
if (canRecover(response)) {
|
||||
return responseOrNewPromise
|
||||
}
|
||||
return $q.reject(response);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$httpProvider.responseInterceptors.push('myHttpInterceptor');
|
||||
```
|
||||
|
||||
Now, one must use the newer API introduced in v1.1.4 (4ae46814), like so:
|
||||
|
||||
```js
|
||||
$provide.factory('myHttpInterceptor', function($q) {
|
||||
return {
|
||||
response: function(response) {
|
||||
// do something on success
|
||||
return response;
|
||||
},
|
||||
responseError: function(response) {
|
||||
// do something on error
|
||||
if (canRecover(response)) {
|
||||
return responseOrNewPromise
|
||||
}
|
||||
return $q.reject(response);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
$httpProvider.interceptors.push('myHttpInterceptor');
|
||||
```
|
||||
|
||||
More details on the new interceptors API (which has been around as of v1.1.4) can be found at
|
||||
https://docs.angularjs.org/api/ng/service/$http#interceptors
|
||||
|
||||
|
||||
- **injector:** due to [c0b4e2db](https://github.com/angular/angular.js/commit/c0b4e2db9cbc8bc3164cedc4646145d3ab72536e),
|
||||
|
||||
Previously, config blocks would be able to control behaviour of provider registration, due to being
|
||||
invoked prior to provider registration. Now, provider registration always occurs prior to configuration
|
||||
for a given module, and therefore config blocks are not able to have any control over a providers
|
||||
registration.
|
||||
|
||||
**Example**:
|
||||
|
||||
Previously, the following:
|
||||
|
||||
```js
|
||||
angular.module('foo', [])
|
||||
.provider('$rootProvider', function() {
|
||||
this.$get = function() { ... }
|
||||
})
|
||||
.config(function($rootProvider) {
|
||||
$rootProvider.dependentMode = "B";
|
||||
})
|
||||
.provider('$dependentProvider', function($rootProvider) {
|
||||
if ($rootProvider.dependentMode === "A") {
|
||||
this.$get = function() {
|
||||
// Special mode!
|
||||
}
|
||||
} else {
|
||||
this.$get = function() {
|
||||
// something else
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
would have "worked", meaning behaviour of the config block between the registration of "$rootProvider"
|
||||
and "$dependentProvider" would have actually accomplished something and changed the behaviour of the
|
||||
app. This is no longer possible within a single module.
|
||||
|
||||
|
||||
- **ngModelOptions:** due to [adfc322b](https://github.com/angular/angular.js/commit/adfc322b04a58158fb9697e5b99aab9ca63c80bb),
|
||||
|
||||
|
||||
This commit changes the API on `NgModelController`, both semantically and
|
||||
in terms of adding and renaming methods.
|
||||
|
||||
* `$setViewValue(value)` -
|
||||
This method still changes the `$viewValue` but does not immediately commit this
|
||||
change through to the `$modelValue` as it did previously.
|
||||
Now the value is committed only when a trigger specified in an associated
|
||||
`ngModelOptions` directive occurs. If `ngModelOptions` also has a `debounce` delay
|
||||
specified for the trigger then the change will also be debounced before being
|
||||
committed.
|
||||
In most cases this should not have a significant impact on how `NgModelController`
|
||||
is used: If `updateOn` includes `default` then `$setViewValue` will trigger
|
||||
a (potentially debounced) commit immediately.
|
||||
* `$cancelUpdate()` - is renamed to `$rollbackViewValue()` and has the same meaning,
|
||||
which is to revert the current `$viewValue` back to the `$lastCommittedViewValue`,
|
||||
to cancel any pending debounced updates and to re-render the input.
|
||||
|
||||
To migrate code that used `$cancelUpdate()` follow the example below:
|
||||
|
||||
Before:
|
||||
|
||||
```js
|
||||
$scope.resetWithCancel = function (e) {
|
||||
if (e.keyCode == 27) {
|
||||
$scope.myForm.myInput1.$cancelUpdate();
|
||||
$scope.myValue = '';
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```js
|
||||
$scope.resetWithCancel = function (e) {
|
||||
if (e.keyCode == 27) {
|
||||
$scope.myForm.myInput1.$rollbackViewValue();
|
||||
$scope.myValue = '';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **$interpolate:** due to [88c2193c](https://github.com/angular/angular.js/commit/88c2193c71954b9e7e7e4bdf636a2b168d36300d),
|
||||
the function returned by `$interpolate`
|
||||
no longer has a `.parts` array set on it.
|
||||
|
||||
Instead it has two arrays:
|
||||
* `.expressions`, an array of the expressions in the
|
||||
interpolated text. The expressions are parsed with
|
||||
`$parse`, with an extra layer converting them to strings
|
||||
when computed
|
||||
* `.separators`, an array of strings representing the
|
||||
separations between interpolations in the text.
|
||||
This array is **always** 1 item longer than the
|
||||
`.expressions` array for easy merging with it
|
||||
|
||||
|
||||
- **$animate:** due to [1cb8584e](https://github.com/angular/angular.js/commit/1cb8584e8490ecdb1b410a8846c4478c6c2c0e53),
|
||||
`$animate` will no longer default the after parameter to the last element of the parent
|
||||
container. Instead, when after is not specified, the new element will be inserted as the
|
||||
first child of the parent container.
|
||||
|
||||
To update existing code, change all instances of `$animate.enter()` or `$animate.move()` from:
|
||||
|
||||
`$animate.enter(element, parent);`
|
||||
|
||||
to:
|
||||
|
||||
`$animate.enter(element, parent, angular.element(parent[0].lastChild));`
|
||||
|
||||
|
||||
|
||||
- **$animate:** due to [1bebe36a](https://github.com/angular/angular.js/commit/1bebe36aa938890d61188762ed618b1b5e193634),
|
||||
|
||||
Any class-based animation code that makes use of transitions
|
||||
and uses the setup CSS classes (such as class-add and class-remove) must now
|
||||
provide a empty transition value to ensure that its styling is applied right
|
||||
away. In other words if your animation code is expecting any styling to be
|
||||
applied that is defined in the setup class then it will not be applied
|
||||
"instantly" unless a `transition:0s none` value is present in the styling
|
||||
for that CSS class. This situation is only the case if a transition is already
|
||||
present on the base CSS class once the animation kicks off.
|
||||
|
||||
Before:
|
||||
|
||||
.animated.my-class-add {
|
||||
opacity:0;
|
||||
transition:0.5s linear all;
|
||||
}
|
||||
.animated.my-class-add.my-class-add-active {
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
After:
|
||||
|
||||
.animated.my-class-add {
|
||||
transition:0s linear all;
|
||||
opacity:0;
|
||||
}
|
||||
.animated.my-class-add.my-class-add-active {
|
||||
transition:0.5s linear all;
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
Please view the documentation for ngAnimate for more info.
|
||||
|
||||
|
||||
- **$compile:** due to [299b220f](https://github.com/angular/angular.js/commit/299b220f5e05e1d4e26bfd58d0b2fd7329ca76b1),
|
||||
calling `attr.$observe` no longer returns the observer function, but a
|
||||
deregistration function instead. To migrate the code follow the example below:
|
||||
|
||||
Before:
|
||||
|
||||
directive('directiveName', function() {
|
||||
return {
|
||||
link: function(scope, elm, attr) {
|
||||
var observer = attr.$observe('someAttr', function(value) {
|
||||
console.log(value);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
After:
|
||||
|
||||
directive('directiveName', function() {
|
||||
return {
|
||||
link: function(scope, elm, attr) {
|
||||
var observer = function(value) {
|
||||
console.log(value);
|
||||
};
|
||||
|
||||
attr.$observe('someAttr', observer);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
- **$httpBackend:** due to [6680b7b9](https://github.com/angular/angular.js/commit/6680b7b97c0326a80bdccaf0a35031e4af641e0e), the JSONP behavior for erroneous and empty responses changed:
|
||||
Previously, a JSONP response was regarded as erroneous if it was empty. Now Angular is listening to the
|
||||
correct events to detect errors, i.e. even empty responses can be successful.
|
||||
|
||||
- **build:** due to [eaa1d00b](https://github.com/angular/angular.js/commit/eaa1d00b24008f590b95ad099241b4003688cdda),
|
||||
As communicated before, IE8 is no longer supported.
|
||||
- **input:** types date, time, datetime-local, month, week now always
|
||||
require a `Date` object as model ([46bd6dc8](https://github.com/angular/angular.js/commit/46bd6dc88de252886d75426efc2ce8107a5134e9),
|
||||
[#5864](https://github.com/angular/angular.js/issues/5864))
|
||||
|
||||
|
||||
|
||||
# Migrating from 1.0 to 1.2
|
||||
|
||||
AngularJS version 1.2 introduces several breaking changes that may require changes to your
|
||||
application's source code.
|
||||
|
||||
Although we try to avoid breaking changes, there are some cases where it is unavoidable.
|
||||
AngularJS 1.2 has undergone a thorough security review to make applications safer by default,
|
||||
which has driven many of these changes. Several new features, especially animations, would not
|
||||
be possible without a few changes. Finally, some outstanding bugs were best fixed by changing
|
||||
an existing API.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<p>**Note:** AngularJS versions 1.1.x are considered "experimental" with breaking changes between minor releases.
|
||||
|
||||
@@ -135,8 +135,8 @@ code, your variable names will get renamed unless you use one of the annotation
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
If you use a tool like [ng-annotate](https://github.com/olov/ng-annotate) in your workflow you can
|
||||
use implicit dependency notation within your codebase and let **ng-annotate** automatically convert such
|
||||
If you use a tool like [ngmin](https://github.com/btford/ngmin#ngmin) in your workflow you can
|
||||
use implicit dependency notation within your codebase and let **ngmin** automatically convert such
|
||||
injectable functions to the array notation prior to minifying.
|
||||
</div>
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ function MyClass() {
|
||||
```
|
||||
|
||||
While no new dependency instance is created, it is fundamentally the same as `new` in
|
||||
that no way exists to intercept the call to `global.xhr` for testing purposes, other than
|
||||
that no way exists to intercept the call to `global.xhr` for testing purposes, other then
|
||||
through monkey patching. The basic issue for testing is that a global variable needs to be mutated in
|
||||
order to replace it with call to a mock method. For further explanation of why this is bad see: [Brittle Global
|
||||
State & Singletons](http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/)
|
||||
|
||||
@@ -51,7 +51,7 @@ Yes. See instructions in {@link downloading}.
|
||||
### What browsers does Angular work with?
|
||||
|
||||
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
|
||||
IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). See {@link guide/ie Internet
|
||||
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). See {@link guide/ie Internet
|
||||
Explorer Compatibility} for more details in supporting legacy IE browsers.
|
||||
|
||||
|
||||
@@ -75,15 +75,14 @@ The size of the file is < 36KB compressed and minified.
|
||||
Yes, you can use widgets from the [Closure Library](https://developers.google.com/closure/library/)
|
||||
in Angular.
|
||||
|
||||
|
||||
### Does Angular use the jQuery library?
|
||||
|
||||
Yes, Angular can use [jQuery](http://jquery.com/) if it's present in your app when the
|
||||
application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
|
||||
to its own implementation of the subset of jQuery that we call {@link angular.element jQLite}.
|
||||
|
||||
Angular 1.3 only supports jQuery 2.1 or above. jQuery 1.7 and newer might work correctly with Angular
|
||||
but we don't guarantee that.
|
||||
Due to a change to use `on()`/`off()` rather than `bind()`/`unbind()`, Angular 1.2 only operates with
|
||||
jQuery 1.7.1 or above. However, Angular does not currently support jQuery 2.x or above.
|
||||
|
||||
|
||||
### What is testability like in Angular?
|
||||
|
||||
@@ -195,11 +195,6 @@ You can now browse to the application at:
|
||||
http://localhost:8000/app/index.html
|
||||
```
|
||||
|
||||
<div class="alert alert-info">
|
||||
To serve the web app on a different ip address or port, edit the "start" script within package.json.
|
||||
You can `-a` to set the address and `-p` to set the port.
|
||||
</div>
|
||||
|
||||
### Running Unit Tests
|
||||
|
||||
We use unit tests to ensure that the JavaScript code in our application is operating correctly.
|
||||
|
||||
@@ -67,7 +67,7 @@ __`app/index.html`:__
|
||||
<html ng-app>
|
||||
|
||||
The `ng-app` attribute represents an Angular directive named `ngApp` (Angular uses
|
||||
`spinal-case` for its custom attributes and `camelCase` for the corresponding directives
|
||||
`name-with-dashes` for its custom attributes and `camelCase` for the corresponding directives
|
||||
which implement them).
|
||||
This directive is used to flag the html element that Angular should consider to be the root element
|
||||
of our application.
|
||||
|
||||
@@ -252,7 +252,7 @@ Our application routes are defined as follows:
|
||||
controller.
|
||||
|
||||
* `when('/phones/:phoneId')`: The phone details view will be shown when the URL hash fragment
|
||||
matches '/phones/:phoneId', where `:phoneId` is a variable part of the URL. To construct the phone
|
||||
matches '/phone/:phoneId', where `:phoneId` is a variable part of the URL. To construct the phone
|
||||
details view, Angular will use the `phone-detail.html` template and the `PhoneDetailCtrl`
|
||||
controller.
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ __`app/js/app.js`:__
|
||||
|
||||
```js
|
||||
...
|
||||
angular.module('phonecatApp', ['ngRoute','phonecatControllers','phonecatFilters']);
|
||||
angular.module('phonecatApp', ['ngRoute','phonecatControllers','phonecatFilters']).
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -104,8 +104,7 @@ __`app/index.html`.__
|
||||
```
|
||||
|
||||
<div class="alert alert-error">
|
||||
**Important:** Be sure to use jQuery version 2.1 or newer when using Angular 1.3; jQuery 1.x is
|
||||
not officially supported.
|
||||
**Important:** Be sure to use jQuery version `1.10.x`. AngularJS does not yet support jQuery `2.x`.
|
||||
Be sure to load jQuery before all AngularJS scripts, otherwise AngularJS won't detect jQuery and
|
||||
animations will not work as expected.
|
||||
</div>
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
|
||||
goog.provide('goog.i18n.currency');
|
||||
goog.provide('goog.i18n.currency.CurrencyInfo');
|
||||
goog.provide('goog.i18n.currency.CurrencyInfoTier2');
|
||||
|
||||
|
||||
/**
|
||||
@@ -48,7 +46,7 @@ goog.i18n.currency.PRECISION_MASK_ = 0x07;
|
||||
* Whether the currency sign should be positioned after the number.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.currency.POSITION_FLAG_ = 0x10;
|
||||
goog.i18n.currency.POSITION_FLAG_ = 0x08;
|
||||
|
||||
|
||||
/**
|
||||
@@ -58,13 +56,6 @@ goog.i18n.currency.POSITION_FLAG_ = 0x10;
|
||||
goog.i18n.currency.SPACE_FLAG_ = 0x20;
|
||||
|
||||
|
||||
/**
|
||||
* Whether tier2 was enabled already by calling addTier2Support().
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.currency.tier2Enabled_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* This function will add tier2 currency support. Be default, only tier1
|
||||
* (most popular currencies) are supported. If an application really needs
|
||||
@@ -72,13 +63,9 @@ goog.i18n.currency.tier2Enabled_ = false;
|
||||
* before any other functions in this namespace.
|
||||
*/
|
||||
goog.i18n.currency.addTier2Support = function() {
|
||||
// Protection from executing this these again and again.
|
||||
if (!goog.i18n.currency.tier2Enabled_) {
|
||||
for (var key in goog.i18n.currency.CurrencyInfoTier2) {
|
||||
goog.i18n.currency.CurrencyInfo[key] =
|
||||
goog.i18n.currency.CurrencyInfoTier2[key];
|
||||
}
|
||||
goog.i18n.currency.tier2Enabled_ = true;
|
||||
for (var key in goog.i18n.currency.CurrencyInfoTier2) {
|
||||
goog.i18n.currency.CurrencyInfo[key] =
|
||||
goog.i18n.currency.CurrencyInfoTier2[key];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -257,7 +244,7 @@ goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
|
||||
* the currency sign should be positioned after the number. Valid values are 0
|
||||
* (before the number) or 16 (after the number). The space flag indicates
|
||||
* whether a space should be inserted between the currency sign and number.
|
||||
* Valid values are 0 (no space) and 32 (space).
|
||||
* Valid values are 0 (no space) and 24 (space).
|
||||
*
|
||||
* The number in the array is calculated by adding together the mask and flag
|
||||
* values. For example:
|
||||
@@ -265,67 +252,52 @@ goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
|
||||
* 0: no precision (0), currency sign first (0), no space (0)
|
||||
* 2: two decimals precision (2), currency sign first (0), no space (0)
|
||||
* 18: two decimals precision (2), currency sign last (16), no space (0)
|
||||
* 50: two decimals precision (2), currency sign last (16), space (32)
|
||||
* 42: two decimals precision (2), currency sign last (16), space (24)
|
||||
*
|
||||
* @type {!Object.<!Array>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfo = {
|
||||
'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
|
||||
'ALL': [0, 'Lek', 'Lek'],
|
||||
'AUD': [2, '$', 'AU$'],
|
||||
'BDT': [2, '\u09F3', 'Tk'],
|
||||
'BGN': [2, 'lev', 'lev'],
|
||||
'BRL': [2, 'R$', 'R$'],
|
||||
'CAD': [2, '$', 'C$'],
|
||||
'CDF': [2, 'FrCD', 'CDF'],
|
||||
'CHF': [2, 'CHF', 'CHF'],
|
||||
'CLP': [0, '$', 'CL$'],
|
||||
'CNY': [2, '¥', 'RMB¥'],
|
||||
'COP': [0, '$', 'COL$'],
|
||||
'CRC': [0, '\u20a1', 'CR\u20a1'],
|
||||
'CZK': [50, 'K\u010d', 'K\u010d'],
|
||||
'CZK': [2, 'K\u010d', 'K\u010d'],
|
||||
'DKK': [18, 'kr', 'kr'],
|
||||
'DOP': [2, '$', 'RD$'],
|
||||
'EGP': [2, '£', 'LE'],
|
||||
'ETB': [2, 'Birr', 'Birr'],
|
||||
'EUR': [2, '€', '€'],
|
||||
'EUR': [18, '€', '€'],
|
||||
'GBP': [2, '£', 'GB£'],
|
||||
'HKD': [2, '$', 'HK$'],
|
||||
'HRK': [2, 'kn', 'kn'],
|
||||
'HUF': [0, 'Ft', 'Ft'],
|
||||
'IDR': [0, 'Rp', 'Rp'],
|
||||
'ILS': [2, '\u20AA', 'IL\u20AA'],
|
||||
'INR': [2, '\u20B9', 'Rs'],
|
||||
'IRR': [0, 'Rial', 'IRR'],
|
||||
'ISK': [0, 'kr', 'kr'],
|
||||
'JMD': [2, '$', 'JA$'],
|
||||
'JPY': [0, '¥', 'JP¥'],
|
||||
'KRW': [0, '\u20A9', 'KR₩'],
|
||||
'LKR': [2, 'Rs', 'SLRs'],
|
||||
'LTL': [2, 'Lt', 'Lt'],
|
||||
'LVL': [2, 'Ls', 'Ls'],
|
||||
'MNT': [0, '\u20AE', 'MN₮'],
|
||||
'MXN': [2, '$', 'Mex$'],
|
||||
'MYR': [2, 'RM', 'RM'],
|
||||
'NOK': [50, 'kr', 'NOkr'],
|
||||
'NOK': [18, 'kr', 'NOkr'],
|
||||
'PAB': [2, 'B/.', 'B/.'],
|
||||
'PEN': [2, 'S/.', 'S/.'],
|
||||
'PHP': [2, '\u20B1', 'Php'],
|
||||
'PKR': [0, 'Rs', 'PKRs.'],
|
||||
'PLN': [50, 'z\u0142', 'z\u0142'],
|
||||
'RON': [2, 'RON', 'RON'],
|
||||
'RSD': [0, 'din', 'RSD'],
|
||||
'RUB': [50, 'руб.', 'руб.'],
|
||||
'RUB': [42, 'руб.', 'руб.'],
|
||||
'SAR': [2, 'Rial', 'Rial'],
|
||||
'SEK': [2, 'kr', 'kr'],
|
||||
'SGD': [2, '$', 'S$'],
|
||||
'THB': [2, '\u0e3f', 'THB'],
|
||||
'TRY': [2, 'TL', 'YTL'],
|
||||
'TWD': [2, 'NT$', 'NT$'],
|
||||
'TZS': [0, 'TSh', 'TSh'],
|
||||
'UAH': [2, '\u20B4', 'UAH'],
|
||||
'USD': [2, '$', 'US$'],
|
||||
'UYU': [2, '$', '$U'],
|
||||
'UYU': [2, '$', 'UY$'],
|
||||
'VND': [0, '\u20AB', 'VN\u20AB'],
|
||||
'YER': [0, 'Rial', 'Rial'],
|
||||
'ZAR': [2, 'R', 'ZAR']
|
||||
@@ -337,14 +309,16 @@ goog.i18n.currency.CurrencyInfo = {
|
||||
* @type {!Object.<!Array>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'AFN': [48, 'Af.', 'AFN'],
|
||||
'AFN': [16, 'Af.', 'AFN'],
|
||||
'ALL': [0, 'Lek', 'Lek'],
|
||||
'AMD': [0, 'Dram', 'dram'],
|
||||
'AOA': [2, 'Kz', 'Kz'],
|
||||
'ARS': [2, '$', 'AR$'],
|
||||
'AWG': [2, 'Afl.', 'Afl.'],
|
||||
'AZN': [2, 'man.', 'man.'],
|
||||
'BAM': [2, 'KM', 'KM'],
|
||||
'BAM': [18, 'KM', 'KM'],
|
||||
'BBD': [2, '$', 'Bds$'],
|
||||
'BGN': [2, 'lev', 'lev'],
|
||||
'BHD': [3, 'din', 'din'],
|
||||
'BIF': [0, 'FBu', 'FBu'],
|
||||
'BMD': [2, '$', 'BD$'],
|
||||
@@ -355,12 +329,14 @@ goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'BWP': [2, 'P', 'pula'],
|
||||
'BYR': [0, 'BYR', 'BYR'],
|
||||
'BZD': [2, '$', 'BZ$'],
|
||||
'CDF': [2, 'FrCD', 'CDF'],
|
||||
'CUC': [1, '$', 'CUC$'],
|
||||
'CUP': [2, '$', 'CU$'],
|
||||
'CVE': [2, 'CVE', 'Esc'],
|
||||
'DJF': [0, 'Fdj', 'Fdj'],
|
||||
'DZD': [2, 'din', 'din'],
|
||||
'ERN': [2, 'Nfk', 'Nfk'],
|
||||
'ETB': [2, 'Birr', 'Birr'],
|
||||
'FJD': [2, '$', 'FJ$'],
|
||||
'FKP': [2, '£', 'FK£'],
|
||||
'GEL': [2, 'GEL', 'GEL'],
|
||||
@@ -371,8 +347,12 @@ goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'GTQ': [2, 'Q', 'GTQ'],
|
||||
'GYD': [0, '$', 'GY$'],
|
||||
'HNL': [2, 'L', 'HNL'],
|
||||
'HRK': [2, 'kn', 'kn'],
|
||||
'HTG': [2, 'HTG', 'HTG'],
|
||||
'HUF': [0, 'Ft', 'Ft'],
|
||||
'IDR': [0, 'Rp', 'Rp'],
|
||||
'IQD': [0, 'din', 'IQD'],
|
||||
'IRR': [0, 'Rial', 'IRR'],
|
||||
'JOD': [3, 'din', 'JOD'],
|
||||
'KES': [2, 'Ksh', 'Ksh'],
|
||||
'KGS': [2, 'KGS', 'KGS'],
|
||||
@@ -386,6 +366,8 @@ goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'LBP': [0, 'L£', 'LBP'],
|
||||
'LRD': [2, '$', 'L$'],
|
||||
'LSL': [2, 'LSL', 'LSL'],
|
||||
'LTL': [2, 'Lt', 'Lt'],
|
||||
'LVL': [2, 'Ls', 'Ls'],
|
||||
'LYD': [3, 'din', 'LD'],
|
||||
'MAD': [2, 'dh', 'MAD'],
|
||||
'MDL': [2, 'MDL', 'MDL'],
|
||||
@@ -404,8 +386,11 @@ goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'NZD': [2, '$', 'NZ$'],
|
||||
'OMR': [3, 'Rial', 'OMR'],
|
||||
'PGK': [2, 'PGK', 'PGK'],
|
||||
'PLN': [2, 'z\u0142', 'z\u0142'],
|
||||
'PYG': [0, 'Gs', 'PYG'],
|
||||
'QAR': [2, 'Rial', 'QR'],
|
||||
'RON': [2, 'RON', 'RON'],
|
||||
'RSD': [0, 'din', 'RSD'],
|
||||
'RWF': [0, 'RF', 'RF'],
|
||||
'SBD': [2, '$', 'SI$'],
|
||||
'SCR': [2, 'SCR', 'SCR'],
|
||||
@@ -415,13 +400,16 @@ goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'SOS': [0, 'SOS', 'SOS'],
|
||||
'SRD': [2, '$', 'SR$'],
|
||||
'STD': [0, 'Db', 'Db'],
|
||||
'SYP': [0, '£', 'SY£'],
|
||||
'SYP': [16, '£', 'SY£'],
|
||||
'SZL': [2, 'SZL', 'SZL'],
|
||||
'TJS': [2, 'Som', 'TJS'],
|
||||
'TND': [3, 'din', 'DT'],
|
||||
'TOP': [2, 'T$', 'T$'],
|
||||
'TTD': [2, '$', 'TT$'],
|
||||
'TZS': [0, 'TSh', 'TSh'],
|
||||
'UAH': [2, '\u20B4', 'UAH'],
|
||||
'UGX': [0, 'UGX', 'UGX'],
|
||||
'UYU': [1, '$', '$U'],
|
||||
'UZS': [0, 'so\u02bcm', 'UZS'],
|
||||
'VEF': [2, 'Bs', 'Bs'],
|
||||
'VUV': [0, 'VUV', 'VUV'],
|
||||
|
||||
+5017
-11469
File diff suppressed because it is too large
Load Diff
+1244
-2138
File diff suppressed because it is too large
Load Diff
+114
-972
File diff suppressed because it is too large
Load Diff
+482
-777
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -7,7 +7,7 @@ echo "#################################"
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
# This is the default set of browsers to use on the CI server unless overridden via env variable
|
||||
# Define reasonable set of browsers in case we are running manually from commandline
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh"
|
||||
|
||||
+15
-4
@@ -9,7 +9,7 @@ module.exports = function(config, specificOptions) {
|
||||
browsers: ['Chrome'],
|
||||
browserDisconnectTimeout: 10000,
|
||||
browserDisconnectTolerance: 2,
|
||||
browserNoActivityTimeout: 30000,
|
||||
browserNoActivityTimeout: 20000,
|
||||
|
||||
|
||||
// SauceLabs config for local development.
|
||||
@@ -17,7 +17,7 @@ module.exports = function(config, specificOptions) {
|
||||
testName: specificOptions.testName || 'AngularJS',
|
||||
startConnect: true,
|
||||
options: {
|
||||
'selenium-version': '2.41.0'
|
||||
'selenium-version': '2.37.0'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -48,6 +48,12 @@ module.exports = function(config, specificOptions) {
|
||||
platform: 'OS X 10.9',
|
||||
version: '7'
|
||||
},
|
||||
'SL_IE_8': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 7',
|
||||
version: '8'
|
||||
},
|
||||
'SL_IE_9': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'internet explorer',
|
||||
@@ -85,6 +91,13 @@ module.exports = function(config, specificOptions) {
|
||||
os: 'Windows',
|
||||
os_version: '8'
|
||||
},
|
||||
'BS_IE_8': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '8.0',
|
||||
os: 'Windows',
|
||||
os_version: '7'
|
||||
},
|
||||
'BS_IE_9': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
@@ -115,7 +128,6 @@ module.exports = function(config, specificOptions) {
|
||||
|
||||
config.logLevel = config.LOG_DEBUG;
|
||||
config.transports = ['websocket', 'xhr-polling'];
|
||||
config.captureTimeout = 0; // rely on SL timeout
|
||||
|
||||
config.browserStack.build = buildLabel;
|
||||
config.browserStack.startTunnel = false;
|
||||
@@ -123,7 +135,6 @@ module.exports = function(config, specificOptions) {
|
||||
config.sauceLabs.build = buildLabel;
|
||||
config.sauceLabs.startConnect = false;
|
||||
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
config.sauceLabs.recordScreenshots = true;
|
||||
|
||||
// TODO(vojta): remove once SauceLabs supports websockets.
|
||||
// This speeds up the capturing a bit, as browsers don't even try to use websocket.
|
||||
|
||||
Generated
+6
-6
@@ -2837,13 +2837,10 @@
|
||||
"version": "0.1.1"
|
||||
},
|
||||
"glob": {
|
||||
"version": "3.2.11",
|
||||
"version": "3.2.9",
|
||||
"dependencies": {
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "0.3.0",
|
||||
"version": "0.2.14",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "2.5.0"
|
||||
@@ -2852,6 +2849,9 @@
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2865,7 +2865,7 @@
|
||||
"version": "0.0.2"
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10"
|
||||
"version": "0.0.8"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+2
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"branchVersion": "1.3.*",
|
||||
"branchVersion": "1.2.*",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
@@ -53,8 +53,7 @@
|
||||
"jshint-stylish": "~0.1.5",
|
||||
"node-html-encoder": "0.0.2",
|
||||
"sorted-object": "^1.0.0",
|
||||
"qq": "^0.3.5",
|
||||
"benchmark": "1.x.x"
|
||||
"qq": "^0.3.5"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
var app = angular.module('perf', ['ngBench'])
|
||||
.directive('noopDir', function() {
|
||||
return {
|
||||
compile: function($element, $attrs) {
|
||||
return function($scope, $element) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
app.directive('nativeClick', ['$parse', function($parse) {
|
||||
return {
|
||||
compile: function($element, $attrs) {
|
||||
var expr = $parse($attrs.tstEvent);
|
||||
return function($scope, $element) {
|
||||
$element[0].addEventListener('click', function() {
|
||||
console.log('clicked');
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
}])
|
||||
.directive('dlgtClick', function() {
|
||||
return {
|
||||
compile: function($element, $attrs) {
|
||||
var evt = $attrs.dlgtClick;
|
||||
// We don't setup the global event listeners as the costs are small and one time only...
|
||||
}
|
||||
};
|
||||
})
|
||||
.controller('MainCtrl', ['$compile', '$rootScope', '$templateCache',
|
||||
function($compile, $rootScope, $templateCache) {
|
||||
// TODO: Make ngRepeatCount configurable via the UI!
|
||||
var self = this;
|
||||
this.ngRepeatCount = 20;
|
||||
this.manualRepeatCount = 5;
|
||||
this.benchmarks = [{
|
||||
title: 'ng-click',
|
||||
factory: function() {
|
||||
return createBenchmark({
|
||||
directive: 'ng-click="a()"'
|
||||
});
|
||||
},
|
||||
active: true
|
||||
},{
|
||||
title: 'ng-click without jqLite',
|
||||
factory: function() {
|
||||
return createBenchmark({
|
||||
directive: 'native-click="a()"'
|
||||
});
|
||||
},
|
||||
active: true
|
||||
},{
|
||||
title: 'baseline: ng-show',
|
||||
factory: function() {
|
||||
return createBenchmark({
|
||||
directive: 'ng-show="true"'
|
||||
});
|
||||
},
|
||||
active: true
|
||||
},{
|
||||
title: 'baseline: text interpolation',
|
||||
factory: function() {
|
||||
return createBenchmark({
|
||||
text: '{{row}}'
|
||||
});
|
||||
},
|
||||
active: true
|
||||
},{
|
||||
title: 'delegate event directive (only compile)',
|
||||
factory: function() {
|
||||
return createBenchmark({
|
||||
directive: 'dlgt-click="a()"'
|
||||
});
|
||||
},
|
||||
active: true
|
||||
},{
|
||||
title: 'baseline: noop directive (compile and link)',
|
||||
factory: function() {
|
||||
return createBenchmark({
|
||||
directive: 'noop-dir'
|
||||
});
|
||||
},
|
||||
active: true
|
||||
},{
|
||||
title: 'baseline: no directive',
|
||||
factory: function() {
|
||||
return createBenchmark({});
|
||||
},
|
||||
active: true
|
||||
}];
|
||||
|
||||
function createBenchmark(options) {
|
||||
options.directive = options.directive || '';
|
||||
options.text = options.text || '';
|
||||
|
||||
var templateHtml = '<div><span ng-repeat="row in rows">';
|
||||
for (var i=0; i<self.manualRepeatCount; i++) {
|
||||
templateHtml += '<span '+options.directive+'>'+options.text+'</span>';
|
||||
}
|
||||
templateHtml += '</span></div>';
|
||||
|
||||
var compiledTemplate = $compile(templateHtml);
|
||||
var rows = [];
|
||||
for (var i=0; i<self.ngRepeatCount; i++) {
|
||||
rows.push('row'+i);
|
||||
}
|
||||
return function(container) {
|
||||
var scope = $rootScope.$new();
|
||||
try {
|
||||
scope.rows = rows;
|
||||
compiledTemplate(scope, function(clone) {
|
||||
container.appendChild(clone[0]);
|
||||
});
|
||||
scope.$digest();
|
||||
} finally {
|
||||
scope.$destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}])
|
||||
@@ -1,69 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="perf" ng-controller="MainCtrl as ctrl">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Event delegation</title>
|
||||
|
||||
<script src="../../../build/angular.js"></script>
|
||||
<script src="../../../node_modules/benchmark/benchmark.js"></script>
|
||||
<script src="ng_benchmark.js"></script>
|
||||
<script src="app.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>
|
||||
Benchmark: impact of event delegation
|
||||
</h1>
|
||||
|
||||
How to run:
|
||||
<ul>
|
||||
<li>For most stable results, run this in Chrome with the following command line option:
|
||||
<pre>--js-flags="--expose-gc"</pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
How to read the results:
|
||||
<ul>
|
||||
<li>The benchmark measures how long it takes to instantiate a given number of directives</li>
|
||||
<li>ngClick is compared against ngShow and text interpolation as baseline. The results show
|
||||
how expensive ngClick is compared to other very simple directives that touch the DOM.
|
||||
</li>
|
||||
<li>To measure the impact of jqLite.on vs element.addEventListener there is also a benchmark
|
||||
that as a modified version of ngClick that uses element.addEventListener.
|
||||
</li>
|
||||
<li>The delegate event directive is compared against a noop directive with a compile and link function and the case with no directives.
|
||||
The result shows how expensive it is to add a link function to a directive, as the delegate event directive has none.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Results as of 7/31/2014:
|
||||
<ul>
|
||||
<li>ngClick is very close to ngShow and text interpolation, especially when looking at a version of ngClick that does not use jqLite.on but element.addEventListener instead.</li>
|
||||
<li>A delegate event directive that has no link function has the same speed as a directive with link function. I.e. ngClick is slower compared to the delegate event directive only because ngClick touches
|
||||
the DOM for every element</li>
|
||||
<li>A delegate event directive could be about 2x faster than ngClick. However, the overall performance
|
||||
benefit depends on how many (and which) other directives are used on the same element
|
||||
and what other things are part of the measures use case.
|
||||
E.g. rows of a table with ngRepeat that use ngClick will probably also contain text interpolation.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Benchmark Options:
|
||||
<p>
|
||||
<label>
|
||||
Number of ngRepeats:
|
||||
<input type="number" ng-model="ctrl.ngRepeatCount">
|
||||
</label>
|
||||
<br>
|
||||
<label>
|
||||
Number of manual repeats inside the ngRepeat:
|
||||
<input type="number" ng-model="ctrl.manualRepeatCount">
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<div ng-bench="ctrl.benchmarks"></div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,27 +0,0 @@
|
||||
Benchmarks:
|
||||
<table>
|
||||
<thead>
|
||||
<td>Name</td>
|
||||
<td>State</td>
|
||||
<td>Result</td>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="bench in benchmarks">
|
||||
<td>
|
||||
<label><input type="checkbox" ng-model="bench.active">{{bench.title}}
|
||||
</label>
|
||||
</td>
|
||||
<td>{{bench.state}}</td>
|
||||
<td>{{bench.lastResult}}</td>
|
||||
</tr>
|
||||
<tbody>
|
||||
</table>
|
||||
|
||||
<div>
|
||||
<button ng-click="ngBenchCtrl.toggleAll()">Toggle all</button>
|
||||
<button ng-click="ngBenchCtrl.run()">Run</button>
|
||||
<button ng-click="ngBenchCtrl.runOnce()">Debug once</button>
|
||||
</div>
|
||||
|
||||
Benchmark work area:
|
||||
<div class="work" style="height:20px; overflow: auto"></div>
|
||||
@@ -1,104 +0,0 @@
|
||||
(function() {
|
||||
|
||||
var ngBenchmarkTemplateUrl = getCurrentScript().replace('.js', '.html');
|
||||
|
||||
angular.module('ngBench', []).directive('ngBench', function() {
|
||||
return {
|
||||
scope: {
|
||||
'benchmarks': '=ngBench'
|
||||
},
|
||||
templateUrl: ngBenchmarkTemplateUrl,
|
||||
controllerAs: 'ngBenchCtrl',
|
||||
controller: ['$scope', '$element', NgBenchController]
|
||||
};
|
||||
});
|
||||
|
||||
function NgBenchController($scope, $element) {
|
||||
var container = $element[0].querySelector('.work');
|
||||
|
||||
this.toggleAll = function() {
|
||||
var newState = !$scope.benchmarks[0].active;
|
||||
$scope.benchmarks.forEach(function(benchmark) {
|
||||
benchmark.active = newState;
|
||||
});
|
||||
};
|
||||
|
||||
this.run = function() {
|
||||
var suite = new Benchmark.Suite();
|
||||
$scope.benchmarks.forEach(function(benchmark) {
|
||||
var options = {
|
||||
'model': benchmark,
|
||||
'onStart': function() {
|
||||
benchmark.state = 'running';
|
||||
$scope.$digest();
|
||||
},
|
||||
'setup': function() {
|
||||
window.gc && window.gc();
|
||||
},
|
||||
'onComplete': function(event) {
|
||||
benchmark.state = '';
|
||||
if (this.error) {
|
||||
benchmark.lastResult = this.error.stack;
|
||||
} else {
|
||||
benchmark.lastResult = benchResultToString(this);
|
||||
}
|
||||
$scope.$digest();
|
||||
},
|
||||
delegate: createBenchmarkFn(benchmark.factory)
|
||||
};
|
||||
benchmark.state = '';
|
||||
if (benchmark.active) {
|
||||
benchmark.state = 'waiting';
|
||||
suite.add(benchmark.title, 'this.delegate()', options);
|
||||
}
|
||||
});
|
||||
suite.run({'async': true});
|
||||
};
|
||||
|
||||
this.runOnce = function() {
|
||||
window.setTimeout(function() {
|
||||
$scope.benchmarks.forEach(function(benchmark) {
|
||||
benchmark.state = '';
|
||||
if (benchmark.active) {
|
||||
try {
|
||||
createBenchmarkFn(benchmark.factory)();
|
||||
benchmark.lastResult = '';
|
||||
} catch (e) {
|
||||
benchmark.lastResult = e.message;
|
||||
}
|
||||
}
|
||||
});
|
||||
$scope.$digest();
|
||||
});
|
||||
};
|
||||
|
||||
function createBenchmarkFn(factory) {
|
||||
var instance = factory();
|
||||
return function() {
|
||||
container.innerHTML = '';
|
||||
instance(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See benchmark.js, toStringBench,
|
||||
// but without showing the name
|
||||
function benchResultToString(bench) {
|
||||
var me = bench,
|
||||
hz = me.hz,
|
||||
stats = me.stats,
|
||||
size = stats.sample.length;
|
||||
|
||||
return Benchmark.formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec +/-' +
|
||||
stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)';
|
||||
}
|
||||
|
||||
function getCurrentScript() {
|
||||
var script = document.currentScript;
|
||||
if (!script) {
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
script = scripts[scripts.length - 1];
|
||||
}
|
||||
return script.src;
|
||||
}
|
||||
})();
|
||||
@@ -26,7 +26,6 @@ function init {
|
||||
angular-sanitize
|
||||
angular-scenario
|
||||
angular-touch
|
||||
angular-messages
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
if [ $JOB = "unit" ]; then
|
||||
grunt ci-checks
|
||||
grunt test:promises-aplus
|
||||
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
|
||||
grunt tests:docs --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
|
||||
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
|
||||
grunt tests:docs --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
|
||||
elif [ $JOB = "e2e" ]; then
|
||||
export TARGET_SPECS="build/docs/ptore2e/**/*jqlite_test.js"
|
||||
if [ $TEST_TARGET = "jquery" ]; then
|
||||
|
||||
+1
-6
@@ -19,7 +19,6 @@
|
||||
"nodeName_": false,
|
||||
"uid": false,
|
||||
|
||||
"REGEX_STRING_REGEXP" : false,
|
||||
"lowercase": false,
|
||||
"uppercase": false,
|
||||
"manualLowercase": false,
|
||||
@@ -71,6 +70,7 @@
|
||||
"toJsonReplacer": false,
|
||||
"toJson": false,
|
||||
"fromJson": false,
|
||||
"toBoolean": false,
|
||||
"startingTag": false,
|
||||
"tryDecodeURIComponent": false,
|
||||
"parseKeyValue": false,
|
||||
@@ -88,9 +88,6 @@
|
||||
"getBlockElements": false,
|
||||
"VALIDITY_STATE_PROPERTY": false,
|
||||
|
||||
/* filters.js */
|
||||
"getFirstThursdayOfYear": false,
|
||||
|
||||
/* AngularPublic.js */
|
||||
"version": false,
|
||||
"publishExternalAPI": false,
|
||||
@@ -103,7 +100,6 @@
|
||||
|
||||
/* jqLite.js */
|
||||
"BOOLEAN_ATTR": false,
|
||||
"ALIASED_ATTR": false,
|
||||
"jqNextId": false,
|
||||
"camelCase": false,
|
||||
"jqLitePatchJQueryRemove": false,
|
||||
@@ -121,7 +117,6 @@
|
||||
"jqLiteController": false,
|
||||
"jqLiteInheritedData": false,
|
||||
"getBooleanAttrName": false,
|
||||
"getAliasedAttrName": false,
|
||||
"createEventHandler": false,
|
||||
"JQLitePrototype": false,
|
||||
"addEventListenerFn": false,
|
||||
|
||||
+207
-287
@@ -2,87 +2,87 @@
|
||||
|
||||
/* We need to tell jshint what variables are being exported */
|
||||
/* global angular: true,
|
||||
msie: true,
|
||||
jqLite: true,
|
||||
jQuery: true,
|
||||
slice: true,
|
||||
push: true,
|
||||
toString: true,
|
||||
ngMinErr: true,
|
||||
angularModule: true,
|
||||
nodeName_: true,
|
||||
uid: true,
|
||||
REGEX_STRING_REGEXP: true,
|
||||
VALIDITY_STATE_PROPERTY: true,
|
||||
msie: true,
|
||||
jqLite: true,
|
||||
jQuery: true,
|
||||
slice: true,
|
||||
push: true,
|
||||
toString: true,
|
||||
ngMinErr: true,
|
||||
angularModule: true,
|
||||
nodeName_: true,
|
||||
uid: true,
|
||||
VALIDITY_STATE_PROPERTY: true,
|
||||
|
||||
lowercase: true,
|
||||
uppercase: true,
|
||||
manualLowercase: true,
|
||||
manualUppercase: true,
|
||||
nodeName_: true,
|
||||
isArrayLike: true,
|
||||
forEach: true,
|
||||
sortedKeys: true,
|
||||
forEachSorted: true,
|
||||
reverseParams: true,
|
||||
nextUid: true,
|
||||
setHashKey: true,
|
||||
extend: true,
|
||||
int: true,
|
||||
inherit: true,
|
||||
noop: true,
|
||||
identity: true,
|
||||
valueFn: true,
|
||||
isUndefined: true,
|
||||
isDefined: true,
|
||||
isObject: true,
|
||||
isString: true,
|
||||
isNumber: true,
|
||||
isDate: true,
|
||||
isArray: true,
|
||||
isFunction: true,
|
||||
isRegExp: true,
|
||||
isWindow: true,
|
||||
isScope: true,
|
||||
isFile: true,
|
||||
isBlob: true,
|
||||
isBoolean: true,
|
||||
isPromiseLike: true,
|
||||
trim: true,
|
||||
isElement: true,
|
||||
makeMap: true,
|
||||
map: true,
|
||||
size: true,
|
||||
includes: true,
|
||||
indexOf: true,
|
||||
arrayRemove: true,
|
||||
isLeafNode: true,
|
||||
copy: true,
|
||||
shallowCopy: true,
|
||||
equals: true,
|
||||
csp: true,
|
||||
concat: true,
|
||||
sliceArgs: true,
|
||||
bind: true,
|
||||
toJsonReplacer: true,
|
||||
toJson: true,
|
||||
fromJson: true,
|
||||
startingTag: true,
|
||||
tryDecodeURIComponent: true,
|
||||
parseKeyValue: true,
|
||||
toKeyValue: true,
|
||||
encodeUriSegment: true,
|
||||
encodeUriQuery: true,
|
||||
angularInit: true,
|
||||
bootstrap: true,
|
||||
snake_case: true,
|
||||
bindJQuery: true,
|
||||
assertArg: true,
|
||||
assertArgFn: true,
|
||||
assertNotHasOwnProperty: true,
|
||||
getter: true,
|
||||
getBlockElements: true,
|
||||
hasOwnProperty: true,
|
||||
lowercase: true,
|
||||
uppercase: true,
|
||||
manualLowercase: true,
|
||||
manualUppercase: true,
|
||||
nodeName_: true,
|
||||
isArrayLike: true,
|
||||
forEach: true,
|
||||
sortedKeys: true,
|
||||
forEachSorted: true,
|
||||
reverseParams: true,
|
||||
nextUid: true,
|
||||
setHashKey: true,
|
||||
extend: true,
|
||||
int: true,
|
||||
inherit: true,
|
||||
noop: true,
|
||||
identity: true,
|
||||
valueFn: true,
|
||||
isUndefined: true,
|
||||
isDefined: true,
|
||||
isObject: true,
|
||||
isString: true,
|
||||
isNumber: true,
|
||||
isDate: true,
|
||||
isArray: true,
|
||||
isFunction: true,
|
||||
isRegExp: true,
|
||||
isWindow: true,
|
||||
isScope: true,
|
||||
isFile: true,
|
||||
isBlob: true,
|
||||
isBoolean: true,
|
||||
isPromiseLike: true,
|
||||
trim: true,
|
||||
isElement: true,
|
||||
makeMap: true,
|
||||
map: true,
|
||||
size: true,
|
||||
includes: true,
|
||||
indexOf: true,
|
||||
arrayRemove: true,
|
||||
isLeafNode: true,
|
||||
copy: true,
|
||||
shallowCopy: true,
|
||||
equals: true,
|
||||
csp: true,
|
||||
concat: true,
|
||||
sliceArgs: true,
|
||||
bind: true,
|
||||
toJsonReplacer: true,
|
||||
toJson: true,
|
||||
fromJson: true,
|
||||
toBoolean: true,
|
||||
startingTag: true,
|
||||
tryDecodeURIComponent: true,
|
||||
parseKeyValue: true,
|
||||
toKeyValue: true,
|
||||
encodeUriSegment: true,
|
||||
encodeUriQuery: true,
|
||||
angularInit: true,
|
||||
bootstrap: true,
|
||||
snake_case: true,
|
||||
bindJQuery: true,
|
||||
assertArg: true,
|
||||
assertArgFn: true,
|
||||
assertNotHasOwnProperty: true,
|
||||
getter: true,
|
||||
getBlockElements: true,
|
||||
hasOwnProperty: true,
|
||||
*/
|
||||
|
||||
////////////////////////////////////
|
||||
@@ -102,8 +102,6 @@
|
||||
* <div doc-module-components="ng"></div>
|
||||
*/
|
||||
|
||||
var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
|
||||
|
||||
// The name of a form control's ValidityState property.
|
||||
// This is used so that it's possible for internal tests to create mock ValidityStates.
|
||||
var VALIDITY_STATE_PROPERTY = 'validity';
|
||||
@@ -170,7 +168,7 @@ var /** holds major version number for IE or NaN for real browsers */
|
||||
angular = window.angular || (window.angular = {}),
|
||||
angularModule,
|
||||
nodeName_,
|
||||
uid = 0;
|
||||
uid = ['0', '0', '0'];
|
||||
|
||||
/**
|
||||
* IE 11 changed the format of the UserAgent string.
|
||||
@@ -232,9 +230,8 @@ function isArrayLike(obj) {
|
||||
* @param {Object=} context Object to become context (`this`) for the iterator function.
|
||||
* @returns {Object|Array} Reference to `obj`.
|
||||
*/
|
||||
|
||||
function forEach(obj, iterator, context) {
|
||||
var key, length;
|
||||
var key;
|
||||
if (obj) {
|
||||
if (isFunction(obj)) {
|
||||
for (key in obj) {
|
||||
@@ -245,7 +242,7 @@ function forEach(obj, iterator, context) {
|
||||
}
|
||||
}
|
||||
} else if (isArray(obj) || isArrayLike(obj)) {
|
||||
for (key = 0, length = obj.length; key < length; key++) {
|
||||
for (key = 0; key < obj.length; key++) {
|
||||
iterator.call(context, obj[key], key);
|
||||
}
|
||||
} else if (obj.forEach && obj.forEach !== forEach) {
|
||||
@@ -290,17 +287,33 @@ function reverseParams(iteratorFn) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistent way of creating unique IDs in angular.
|
||||
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
|
||||
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
|
||||
* the number string gets longer over time, and it can also overflow, where as the nextId
|
||||
* will grow much slower, it is a string, and it will never overflow.
|
||||
*
|
||||
* Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
|
||||
* we hit number precision issues in JavaScript.
|
||||
*
|
||||
* Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
|
||||
*
|
||||
* @returns {number} an unique alpha-numeric string
|
||||
* @returns {string} an unique alpha-numeric string
|
||||
*/
|
||||
function nextUid() {
|
||||
return ++uid;
|
||||
var index = uid.length;
|
||||
var digit;
|
||||
|
||||
while(index) {
|
||||
index--;
|
||||
digit = uid[index].charCodeAt(0);
|
||||
if (digit == 57 /*'9'*/) {
|
||||
uid[index] = 'A';
|
||||
return uid.join('');
|
||||
}
|
||||
if (digit == 90 /*'Z'*/) {
|
||||
uid[index] = '0';
|
||||
} else {
|
||||
uid[index] = String.fromCharCode(digit + 1);
|
||||
return uid.join('');
|
||||
}
|
||||
}
|
||||
uid.unshift('0');
|
||||
return uid.join('');
|
||||
}
|
||||
|
||||
|
||||
@@ -546,7 +559,7 @@ function isRegExp(value) {
|
||||
* @returns {boolean} True if `obj` is a window obj.
|
||||
*/
|
||||
function isWindow(obj) {
|
||||
return obj && obj.window === obj;
|
||||
return obj && obj.document && obj.location && obj.alert && obj.setInterval;
|
||||
}
|
||||
|
||||
|
||||
@@ -623,14 +636,12 @@ function makeMap(str) {
|
||||
if (msie < 9) {
|
||||
nodeName_ = function(element) {
|
||||
element = element.nodeName ? element : element[0];
|
||||
return lowercase(
|
||||
(element.scopeName && element.scopeName != 'HTML')
|
||||
? element.scopeName + ':' + element.nodeName : element.nodeName
|
||||
);
|
||||
return (element.scopeName && element.scopeName != 'HTML')
|
||||
? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
|
||||
};
|
||||
} else {
|
||||
nodeName_ = function(element) {
|
||||
return lowercase(element.nodeName ? element.nodeName : element[0].nodeName);
|
||||
return element.nodeName ? element.nodeName : element[0].nodeName;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -693,10 +704,10 @@ function arrayRemove(array, value) {
|
||||
|
||||
function isLeafNode (node) {
|
||||
if (node) {
|
||||
switch (nodeName_(node)) {
|
||||
case "option":
|
||||
case "pre":
|
||||
case "title":
|
||||
switch (node.nodeName) {
|
||||
case "OPTION":
|
||||
case "PRE":
|
||||
case "TITLE":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -778,8 +789,7 @@ function copy(source, destination, stackSource, stackDest) {
|
||||
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
||||
destination.lastIndex = source.lastIndex;
|
||||
} else if (isObject(source)) {
|
||||
var emptyObject = Object.create(Object.getPrototypeOf(source));
|
||||
destination = copy(source, emptyObject, stackSource, stackDest);
|
||||
destination = copy(source, {}, stackSource, stackDest);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -814,14 +824,12 @@ function copy(source, destination, stackSource, stackDest) {
|
||||
delete destination[key];
|
||||
});
|
||||
for ( var key in source) {
|
||||
if(source.hasOwnProperty(key)) {
|
||||
result = copy(source[key], null, stackSource, stackDest);
|
||||
if (isObject(source[key])) {
|
||||
stackSource.push(source[key]);
|
||||
stackDest.push(result);
|
||||
}
|
||||
destination[key] = result;
|
||||
result = copy(source[key], null, stackSource, stackDest);
|
||||
if (isObject(source[key])) {
|
||||
stackSource.push(source[key]);
|
||||
stackDest.push(result);
|
||||
}
|
||||
destination[key] = result;
|
||||
}
|
||||
setHashKey(destination,h);
|
||||
}
|
||||
@@ -834,22 +842,17 @@ function copy(source, destination, stackSource, stackDest) {
|
||||
* Creates a shallow copy of an object, an array or a primitive
|
||||
*/
|
||||
function shallowCopy(src, dst) {
|
||||
var i = 0;
|
||||
if (isArray(src)) {
|
||||
dst = dst || [];
|
||||
|
||||
for (; i < src.length; i++) {
|
||||
for ( var i = 0; i < src.length; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
} else if (isObject(src)) {
|
||||
dst = dst || {};
|
||||
|
||||
var keys = Object.keys(src);
|
||||
|
||||
for (var l = keys.length; i < l; i++) {
|
||||
var key = keys[i];
|
||||
|
||||
if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
|
||||
for (var key in src) {
|
||||
if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
@@ -1001,7 +1004,7 @@ function bind(self, fn) {
|
||||
function toJsonReplacer(key, value) {
|
||||
var val = value;
|
||||
|
||||
if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
|
||||
if (typeof key === 'string' && key.charAt(0) === '$') {
|
||||
val = undefined;
|
||||
} else if (isWindow(value)) {
|
||||
val = '$WINDOW';
|
||||
@@ -1022,7 +1025,7 @@ function toJsonReplacer(key, value) {
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
|
||||
* Serializes input into a JSON-formatted string. Properties with leading $ characters will be
|
||||
* stripped since angular uses this notation internally.
|
||||
*
|
||||
* @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
|
||||
@@ -1054,6 +1057,18 @@ function fromJson(json) {
|
||||
}
|
||||
|
||||
|
||||
function toBoolean(value) {
|
||||
if (typeof value === 'function') {
|
||||
value = true;
|
||||
} else if (value && value.length !== 0) {
|
||||
var v = lowercase("" + value);
|
||||
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
|
||||
} else {
|
||||
value = false;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} Returns the string representation of the element.
|
||||
*/
|
||||
@@ -1176,23 +1191,9 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
||||
replace(/%3A/gi, ':').
|
||||
replace(/%24/g, '$').
|
||||
replace(/%2C/gi, ',').
|
||||
replace(/%3B/gi, ';').
|
||||
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
||||
}
|
||||
|
||||
var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
|
||||
|
||||
function getNgAttribute(element, ngAttr) {
|
||||
var attr, i, ii = ngAttrPrefixes.length;
|
||||
element = jqLite(element);
|
||||
for (i=0; i<ii; ++i) {
|
||||
attr = ngAttrPrefixes[i] + ngAttr;
|
||||
if (isString(attr = element.attr(attr))) {
|
||||
return attr;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
@@ -1202,11 +1203,6 @@ function getNgAttribute(element, ngAttr) {
|
||||
* @element ANY
|
||||
* @param {angular.Module} ngApp an optional application
|
||||
* {@link angular.module module} name to load.
|
||||
* @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
|
||||
* created in "strict-di" mode. This means that the application will fail to invoke functions which
|
||||
* do not use explicit function annotation (and are thus unsuitable for minification), as described
|
||||
* in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
|
||||
* tracking down the root of these bugs.
|
||||
*
|
||||
* @description
|
||||
*
|
||||
@@ -1244,109 +1240,48 @@ function getNgAttribute(element, ngAttr) {
|
||||
</file>
|
||||
</example>
|
||||
*
|
||||
* Using `ngStrictDi`, you would see something like this:
|
||||
*
|
||||
<example ng-app-included="true">
|
||||
<file name="index.html">
|
||||
<div ng-app="ngAppStrictDemo" ng-strict-di>
|
||||
<div ng-controller="GoodController1">
|
||||
I can add: {{a}} + {{b}} = {{ a+b }}
|
||||
|
||||
<p>This renders because the controller does not fail to
|
||||
instantiate, by using explicit annotation style (see
|
||||
script.js for details)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div ng-controller="GoodController2">
|
||||
Name: <input ng-model="name"><br />
|
||||
Hello, {{name}}!
|
||||
|
||||
<p>This renders because the controller does not fail to
|
||||
instantiate, by using explicit annotation style
|
||||
(see script.js for details)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div ng-controller="BadController">
|
||||
I can add: {{a}} + {{b}} = {{ a+b }}
|
||||
|
||||
<p>The controller could not be instantiated, due to relying
|
||||
on automatic function annotations (which are disabled in
|
||||
strict mode). As such, the content of this section is not
|
||||
interpolated, and there should be an error in your web console.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('ngAppStrictDemo', [])
|
||||
// BadController will fail to instantiate, due to relying on automatic function annotation,
|
||||
// rather than an explicit annotation
|
||||
.controller('BadController', function($scope) {
|
||||
$scope.a = 1;
|
||||
$scope.b = 2;
|
||||
})
|
||||
// Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
|
||||
// due to using explicit annotations using the array style and $inject property, respectively.
|
||||
.controller('GoodController1', ['$scope', function($scope) {
|
||||
$scope.a = 1;
|
||||
$scope.b = 2;
|
||||
}])
|
||||
.controller('GoodController2', GoodController2);
|
||||
function GoodController2($scope) {
|
||||
$scope.name = "World";
|
||||
}
|
||||
GoodController2.$inject = ['$scope'];
|
||||
</file>
|
||||
<file name="style.css">
|
||||
div[ng-controller] {
|
||||
margin-bottom: 1em;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid;
|
||||
padding: .5em;
|
||||
}
|
||||
div[ng-controller^=Good] {
|
||||
border-color: #d6e9c6;
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
}
|
||||
div[ng-controller^=Bad] {
|
||||
border-color: #ebccd1;
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
function angularInit(element, bootstrap) {
|
||||
var appElement,
|
||||
var elements = [element],
|
||||
appElement,
|
||||
module,
|
||||
config = {};
|
||||
names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
|
||||
NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
|
||||
|
||||
// The element `element` has priority over any other element
|
||||
forEach(ngAttrPrefixes, function(prefix) {
|
||||
var name = prefix + 'app';
|
||||
function append(element) {
|
||||
element && elements.push(element);
|
||||
}
|
||||
|
||||
if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
|
||||
appElement = element;
|
||||
module = element.getAttribute(name);
|
||||
forEach(names, function(name) {
|
||||
names[name] = true;
|
||||
append(document.getElementById(name));
|
||||
name = name.replace(':', '\\:');
|
||||
if (element.querySelectorAll) {
|
||||
forEach(element.querySelectorAll('.' + name), append);
|
||||
forEach(element.querySelectorAll('.' + name + '\\:'), append);
|
||||
forEach(element.querySelectorAll('[' + name + ']'), append);
|
||||
}
|
||||
});
|
||||
forEach(ngAttrPrefixes, function(prefix) {
|
||||
var name = prefix + 'app';
|
||||
var candidate;
|
||||
|
||||
if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
|
||||
appElement = candidate;
|
||||
module = candidate.getAttribute(name);
|
||||
forEach(elements, function(element) {
|
||||
if (!appElement) {
|
||||
var className = ' ' + element.className + ' ';
|
||||
var match = NG_APP_CLASS_REGEXP.exec(className);
|
||||
if (match) {
|
||||
appElement = element;
|
||||
module = (match[2] || '').replace(/\s+/g, ',');
|
||||
} else {
|
||||
forEach(element.attributes, function(attr) {
|
||||
if (!appElement && names[attr.name]) {
|
||||
appElement = element;
|
||||
module = attr.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
if (appElement) {
|
||||
config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
|
||||
bootstrap(appElement, module ? [module] : [], config);
|
||||
bootstrap(appElement, module ? [module] : []);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1359,7 +1294,7 @@ function angularInit(element, bootstrap) {
|
||||
*
|
||||
* See: {@link guide/bootstrap Bootstrap}
|
||||
*
|
||||
* Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
|
||||
* Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
|
||||
* They must use {@link ng.directive:ngApp ngApp}.
|
||||
*
|
||||
* Angular will detect if it has been loaded into the browser more than once and only allow the
|
||||
@@ -1367,45 +1302,44 @@ function angularInit(element, bootstrap) {
|
||||
* each of the subsequent scripts. This prevents strange results in applications, where otherwise
|
||||
* multiple instances of Angular try to work on the DOM.
|
||||
*
|
||||
* ```html
|
||||
* <!doctype html>
|
||||
* <html>
|
||||
* <body>
|
||||
* <div ng-controller="WelcomeController">
|
||||
* {{greeting}}
|
||||
* <example name="multi-bootstrap" module="multi-bootstrap">
|
||||
* <file name="index.html">
|
||||
* <script src="../../../angular.js"></script>
|
||||
* <div ng-controller="BrokenTable">
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th ng-repeat="heading in headings">{{heading}}</th>
|
||||
* </tr>
|
||||
* <tr ng-repeat="filling in fillings">
|
||||
* <td ng-repeat="fill in filling">{{fill}}</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="controller.js">
|
||||
* var app = angular.module('multi-bootstrap', [])
|
||||
*
|
||||
* <script src="angular.js"></script>
|
||||
* <script>
|
||||
* var app = angular.module('demo', [])
|
||||
* .controller('WelcomeController', function($scope) {
|
||||
* $scope.greeting = 'Welcome!';
|
||||
* });
|
||||
* angular.bootstrap(document, ['demo']);
|
||||
* </script>
|
||||
* </body>
|
||||
* </html>
|
||||
* ```
|
||||
* .controller('BrokenTable', function($scope) {
|
||||
* $scope.headings = ['One', 'Two', 'Three'];
|
||||
* $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
|
||||
* });
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
* it('should only insert one table cell for each item in $scope.fillings', function() {
|
||||
* expect(element.all(by.css('td')).count())
|
||||
* .toBe(9);
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* @param {DOMElement} element DOM element which is the root of angular application.
|
||||
* @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
|
||||
* Each item in the array should be the name of a predefined module or a (DI annotated)
|
||||
* function that will be invoked by the injector as a run block.
|
||||
* See: {@link angular.module modules}
|
||||
* @param {Object=} config an object for defining configuration options for the application. The
|
||||
* following keys are supported:
|
||||
*
|
||||
* - `strictDi`: disable automatic function annotation for the application. This is meant to
|
||||
* assist in finding bugs which break minified code.
|
||||
*
|
||||
* @returns {auto.$injector} Returns the newly created injector for this app.
|
||||
*/
|
||||
function bootstrap(element, modules, config) {
|
||||
if (!isObject(config)) config = {};
|
||||
var defaultConfig = {
|
||||
strictDi: false
|
||||
};
|
||||
config = extend(defaultConfig, config);
|
||||
function bootstrap(element, modules) {
|
||||
var doBootstrap = function() {
|
||||
element = jqLite(element);
|
||||
|
||||
@@ -1419,9 +1353,9 @@ function bootstrap(element, modules, config) {
|
||||
$provide.value('$rootElement', element);
|
||||
}]);
|
||||
modules.unshift('ng');
|
||||
var injector = createInjector(modules, config.strictDi);
|
||||
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
|
||||
function(scope, element, compile, injector) {
|
||||
var injector = createInjector(modules);
|
||||
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
|
||||
function(scope, element, compile, injector, animate) {
|
||||
scope.$apply(function() {
|
||||
element.data('$injector', injector);
|
||||
compile(element)(scope);
|
||||
@@ -1455,13 +1389,10 @@ function snake_case(name, separator) {
|
||||
}
|
||||
|
||||
function bindJQuery() {
|
||||
var originalCleanData;
|
||||
// bind to jQuery if present;
|
||||
jQuery = window.jQuery;
|
||||
// Use jQuery if it exists with proper functionality, otherwise default to us.
|
||||
// Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
|
||||
// Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
|
||||
// versions. It will not work for sure with jQuery <1.7, though.
|
||||
// Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
|
||||
if (jQuery && jQuery.fn.on) {
|
||||
jqLite = jQuery;
|
||||
extend(jQuery.fn, {
|
||||
@@ -1471,25 +1402,14 @@ function bindJQuery() {
|
||||
injector: JQLitePrototype.injector,
|
||||
inheritedData: JQLitePrototype.inheritedData
|
||||
});
|
||||
|
||||
originalCleanData = jQuery.cleanData;
|
||||
// Prevent double-proxying.
|
||||
originalCleanData = originalCleanData.$$original || originalCleanData;
|
||||
|
||||
// All nodes removed from the DOM via various jQuery APIs like .remove()
|
||||
// are passed through jQuery.cleanData. Monkey-patch this method to fire
|
||||
// the $destroy event on all removed nodes.
|
||||
jQuery.cleanData = function(elems) {
|
||||
for (var i = 0, elem; (elem = elems[i]) != null; i++) {
|
||||
jQuery(elem).triggerHandler('$destroy');
|
||||
}
|
||||
originalCleanData(elems);
|
||||
};
|
||||
jQuery.cleanData.$$original = originalCleanData;
|
||||
// Method signature:
|
||||
// jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
|
||||
jqLitePatchJQueryRemove('remove', true, true, false);
|
||||
jqLitePatchJQueryRemove('empty', false, false, false);
|
||||
jqLitePatchJQueryRemove('html', false, false, true);
|
||||
} else {
|
||||
jqLite = JQLite;
|
||||
}
|
||||
|
||||
angular.element = jqLite;
|
||||
}
|
||||
|
||||
|
||||
+68
-84
@@ -6,82 +6,74 @@
|
||||
$LocaleProvider,
|
||||
$CompileProvider,
|
||||
|
||||
htmlAnchorDirective,
|
||||
inputDirective,
|
||||
inputDirective,
|
||||
formDirective,
|
||||
scriptDirective,
|
||||
selectDirective,
|
||||
styleDirective,
|
||||
optionDirective,
|
||||
ngBindDirective,
|
||||
ngBindHtmlDirective,
|
||||
ngBindTemplateDirective,
|
||||
ngClassDirective,
|
||||
ngClassEvenDirective,
|
||||
ngClassOddDirective,
|
||||
ngCspDirective,
|
||||
ngCloakDirective,
|
||||
ngControllerDirective,
|
||||
ngFormDirective,
|
||||
ngHideDirective,
|
||||
ngIfDirective,
|
||||
ngIncludeDirective,
|
||||
ngIncludeFillContentDirective,
|
||||
ngInitDirective,
|
||||
ngNonBindableDirective,
|
||||
ngPluralizeDirective,
|
||||
ngRepeatDirective,
|
||||
ngShowDirective,
|
||||
ngStyleDirective,
|
||||
ngSwitchDirective,
|
||||
ngSwitchWhenDirective,
|
||||
ngSwitchDefaultDirective,
|
||||
ngOptionsDirective,
|
||||
ngTranscludeDirective,
|
||||
ngModelDirective,
|
||||
ngListDirective,
|
||||
ngChangeDirective,
|
||||
patternDirective,
|
||||
patternDirective,
|
||||
requiredDirective,
|
||||
requiredDirective,
|
||||
minlengthDirective,
|
||||
minlengthDirective,
|
||||
maxlengthDirective,
|
||||
maxlengthDirective,
|
||||
ngValueDirective,
|
||||
ngModelOptionsDirective,
|
||||
ngAttributeAliasDirectives,
|
||||
ngEventDirectives,
|
||||
htmlAnchorDirective,
|
||||
inputDirective,
|
||||
inputDirective,
|
||||
formDirective,
|
||||
scriptDirective,
|
||||
selectDirective,
|
||||
styleDirective,
|
||||
optionDirective,
|
||||
ngBindDirective,
|
||||
ngBindHtmlDirective,
|
||||
ngBindTemplateDirective,
|
||||
ngClassDirective,
|
||||
ngClassEvenDirective,
|
||||
ngClassOddDirective,
|
||||
ngCspDirective,
|
||||
ngCloakDirective,
|
||||
ngControllerDirective,
|
||||
ngFormDirective,
|
||||
ngHideDirective,
|
||||
ngIfDirective,
|
||||
ngIncludeDirective,
|
||||
ngIncludeFillContentDirective,
|
||||
ngInitDirective,
|
||||
ngNonBindableDirective,
|
||||
ngPluralizeDirective,
|
||||
ngRepeatDirective,
|
||||
ngShowDirective,
|
||||
ngStyleDirective,
|
||||
ngSwitchDirective,
|
||||
ngSwitchWhenDirective,
|
||||
ngSwitchDefaultDirective,
|
||||
ngOptionsDirective,
|
||||
ngTranscludeDirective,
|
||||
ngModelDirective,
|
||||
ngListDirective,
|
||||
ngChangeDirective,
|
||||
requiredDirective,
|
||||
requiredDirective,
|
||||
ngValueDirective,
|
||||
ngAttributeAliasDirectives,
|
||||
ngEventDirectives,
|
||||
|
||||
$AnchorScrollProvider,
|
||||
$AnimateProvider,
|
||||
$BrowserProvider,
|
||||
$CacheFactoryProvider,
|
||||
$ControllerProvider,
|
||||
$DocumentProvider,
|
||||
$ExceptionHandlerProvider,
|
||||
$FilterProvider,
|
||||
$InterpolateProvider,
|
||||
$IntervalProvider,
|
||||
$HttpProvider,
|
||||
$HttpBackendProvider,
|
||||
$LocationProvider,
|
||||
$LogProvider,
|
||||
$ParseProvider,
|
||||
$RootScopeProvider,
|
||||
$QProvider,
|
||||
$$QProvider,
|
||||
$$SanitizeUriProvider,
|
||||
$SceProvider,
|
||||
$SceDelegateProvider,
|
||||
$SnifferProvider,
|
||||
$TemplateCacheProvider,
|
||||
$TimeoutProvider,
|
||||
$$RAFProvider,
|
||||
$$AsyncCallbackProvider,
|
||||
$WindowProvider
|
||||
$AnchorScrollProvider,
|
||||
$AnimateProvider,
|
||||
$BrowserProvider,
|
||||
$CacheFactoryProvider,
|
||||
$ControllerProvider,
|
||||
$DocumentProvider,
|
||||
$ExceptionHandlerProvider,
|
||||
$FilterProvider,
|
||||
$InterpolateProvider,
|
||||
$IntervalProvider,
|
||||
$HttpProvider,
|
||||
$HttpBackendProvider,
|
||||
$LocationProvider,
|
||||
$LogProvider,
|
||||
$ParseProvider,
|
||||
$RootScopeProvider,
|
||||
$QProvider,
|
||||
$$SanitizeUriProvider,
|
||||
$SceProvider,
|
||||
$SceDelegateProvider,
|
||||
$SnifferProvider,
|
||||
$TemplateCacheProvider,
|
||||
$TimeoutProvider,
|
||||
$$RAFProvider,
|
||||
$$AsyncCallbackProvider,
|
||||
$WindowProvider
|
||||
*/
|
||||
|
||||
|
||||
@@ -188,16 +180,9 @@ function publishExternalAPI(angular){
|
||||
ngModel: ngModelDirective,
|
||||
ngList: ngListDirective,
|
||||
ngChange: ngChangeDirective,
|
||||
pattern: patternDirective,
|
||||
ngPattern: patternDirective,
|
||||
required: requiredDirective,
|
||||
ngRequired: requiredDirective,
|
||||
minlength: minlengthDirective,
|
||||
ngMinlength: minlengthDirective,
|
||||
maxlength: maxlengthDirective,
|
||||
ngMaxlength: maxlengthDirective,
|
||||
ngValue: ngValueDirective,
|
||||
ngModelOptions: ngModelOptionsDirective
|
||||
ngValue: ngValueDirective
|
||||
}).
|
||||
directive({
|
||||
ngInclude: ngIncludeFillContentDirective
|
||||
@@ -222,7 +207,6 @@ function publishExternalAPI(angular){
|
||||
$parse: $ParseProvider,
|
||||
$rootScope: $RootScopeProvider,
|
||||
$q: $QProvider,
|
||||
$$q: $$QProvider,
|
||||
$sce: $SceProvider,
|
||||
$sceDelegate: $SceDelegateProvider,
|
||||
$sniffer: $SnifferProvider,
|
||||
|
||||
+21
-52
@@ -23,7 +23,7 @@
|
||||
*
|
||||
* // use the injector to kick off your application
|
||||
* // use the type inference to auto inject arguments, or use implicit injection
|
||||
* $injector.invoke(function($rootScope, $compile, $document) {
|
||||
* $injector.invoke(function($rootScope, $compile, $document){
|
||||
* $compile($document)($rootScope);
|
||||
* $rootScope.$digest();
|
||||
* });
|
||||
@@ -66,19 +66,7 @@ var FN_ARG_SPLIT = /,/;
|
||||
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
|
||||
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
||||
var $injectorMinErr = minErr('$injector');
|
||||
|
||||
function anonFn(fn) {
|
||||
// For anonymous functions, showing at the very least the function signature can help in
|
||||
// debugging.
|
||||
var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
|
||||
args = fnText.match(FN_ARGS);
|
||||
if (args) {
|
||||
return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
|
||||
}
|
||||
return 'fn';
|
||||
}
|
||||
|
||||
function annotate(fn, strictDi, name) {
|
||||
function annotate(fn) {
|
||||
var $inject,
|
||||
fnText,
|
||||
argDecl,
|
||||
@@ -88,17 +76,10 @@ function annotate(fn, strictDi, name) {
|
||||
if (!($inject = fn.$inject)) {
|
||||
$inject = [];
|
||||
if (fn.length) {
|
||||
if (strictDi) {
|
||||
if (!isString(name) || !name) {
|
||||
name = fn.name || anonFn(fn);
|
||||
}
|
||||
throw $injectorMinErr('strictdi',
|
||||
'{0} is not using explicit annotation and cannot be invoked in strict mode', name);
|
||||
}
|
||||
fnText = fn.toString().replace(STRIP_COMMENTS, '');
|
||||
argDecl = fnText.match(FN_ARGS);
|
||||
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
|
||||
arg.replace(FN_ARG, function(all, underscore, name) {
|
||||
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
|
||||
arg.replace(FN_ARG, function(all, underscore, name){
|
||||
$inject.push(name);
|
||||
});
|
||||
});
|
||||
@@ -133,7 +114,7 @@ function annotate(fn, strictDi, name) {
|
||||
* ```js
|
||||
* var $injector = angular.injector();
|
||||
* expect($injector.get('$injector')).toBe($injector);
|
||||
* expect($injector.invoke(function($injector) {
|
||||
* expect($injector.invoke(function($injector){
|
||||
* return $injector;
|
||||
* }).toBe($injector);
|
||||
* ```
|
||||
@@ -606,8 +587,7 @@ function annotate(fn, strictDi, name) {
|
||||
*/
|
||||
|
||||
|
||||
function createInjector(modulesToLoad, strictDi) {
|
||||
strictDi = (strictDi === true);
|
||||
function createInjector(modulesToLoad) {
|
||||
var INSTANTIATING = {},
|
||||
providerSuffix = 'Provider',
|
||||
path = [],
|
||||
@@ -625,13 +605,13 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
providerInjector = (providerCache.$injector =
|
||||
createInternalInjector(providerCache, function() {
|
||||
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
|
||||
}, strictDi)),
|
||||
})),
|
||||
instanceCache = {},
|
||||
instanceInjector = (instanceCache.$injector =
|
||||
createInternalInjector(instanceCache, function(servicename) {
|
||||
var provider = providerInjector.get(servicename + providerSuffix);
|
||||
return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
|
||||
}, strictDi));
|
||||
return instanceInjector.invoke(provider.$get, provider);
|
||||
}));
|
||||
|
||||
|
||||
forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
|
||||
@@ -693,27 +673,22 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
// Module Loading
|
||||
////////////////////////////////////
|
||||
function loadModules(modulesToLoad){
|
||||
var runBlocks = [], moduleFn, invokeQueue;
|
||||
var runBlocks = [], moduleFn, invokeQueue, i, ii;
|
||||
forEach(modulesToLoad, function(module) {
|
||||
if (loadedModules.get(module)) return;
|
||||
loadedModules.put(module, true);
|
||||
|
||||
function runInvokeQueue(queue) {
|
||||
var i, ii;
|
||||
for(i = 0, ii = queue.length; i < ii; i++) {
|
||||
var invokeArgs = queue[i],
|
||||
provider = providerInjector.get(invokeArgs[0]);
|
||||
|
||||
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (isString(module)) {
|
||||
moduleFn = angularModule(module);
|
||||
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
|
||||
runInvokeQueue(moduleFn._invokeQueue);
|
||||
runInvokeQueue(moduleFn._configBlocks);
|
||||
|
||||
for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
|
||||
var invokeArgs = invokeQueue[i],
|
||||
provider = providerInjector.get(invokeArgs[0]);
|
||||
|
||||
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
|
||||
}
|
||||
} else if (isFunction(module)) {
|
||||
runBlocks.push(providerInjector.invoke(module));
|
||||
} else if (isArray(module)) {
|
||||
@@ -769,14 +744,9 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
}
|
||||
}
|
||||
|
||||
function invoke(fn, self, locals, serviceName) {
|
||||
if (typeof locals === 'string') {
|
||||
serviceName = locals;
|
||||
locals = null;
|
||||
}
|
||||
|
||||
function invoke(fn, self, locals){
|
||||
var args = [],
|
||||
$inject = annotate(fn, strictDi, serviceName),
|
||||
$inject = annotate(fn),
|
||||
length, i,
|
||||
key;
|
||||
|
||||
@@ -801,7 +771,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
return fn.apply(self, args);
|
||||
}
|
||||
|
||||
function instantiate(Type, locals, serviceName) {
|
||||
function instantiate(Type, locals) {
|
||||
var Constructor = function() {},
|
||||
instance, returnedValue;
|
||||
|
||||
@@ -809,7 +779,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
||||
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
|
||||
instance = new Constructor();
|
||||
returnedValue = invoke(Type, instance, locals, serviceName);
|
||||
returnedValue = invoke(Type, instance, locals);
|
||||
|
||||
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
|
||||
}
|
||||
@@ -826,4 +796,3 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
}
|
||||
}
|
||||
|
||||
createInjector.$$annotate = annotate;
|
||||
|
||||
+102
-97
@@ -3,8 +3,7 @@
|
||||
/* global JQLitePrototype: true,
|
||||
addEventListenerFn: true,
|
||||
removeEventListenerFn: true,
|
||||
BOOLEAN_ATTR: true,
|
||||
ALIASED_ATTR: true,
|
||||
BOOLEAN_ATTR: true
|
||||
*/
|
||||
|
||||
//////////////////////////////////
|
||||
@@ -136,6 +135,49 @@ function camelCase(name) {
|
||||
replace(MOZ_HACK_REGEXP, 'Moz$1');
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// jQuery mutation patch
|
||||
//
|
||||
// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
|
||||
// $destroy event on all DOM nodes being removed.
|
||||
//
|
||||
/////////////////////////////////////////////
|
||||
|
||||
function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
|
||||
var originalJqFn = jQuery.fn[name];
|
||||
originalJqFn = originalJqFn.$original || originalJqFn;
|
||||
removePatch.$original = originalJqFn;
|
||||
jQuery.fn[name] = removePatch;
|
||||
|
||||
function removePatch(param) {
|
||||
// jshint -W040
|
||||
var list = filterElems && param ? [this.filter(param)] : [this],
|
||||
fireEvent = dispatchThis,
|
||||
set, setIndex, setLength,
|
||||
element, childIndex, childLength, children;
|
||||
|
||||
if (!getterIfNoArguments || param != null) {
|
||||
while(list.length) {
|
||||
set = list.shift();
|
||||
for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
|
||||
element = jqLite(set[setIndex]);
|
||||
if (fireEvent) {
|
||||
element.triggerHandler('$destroy');
|
||||
} else {
|
||||
fireEvent = !fireEvent;
|
||||
}
|
||||
for(childIndex = 0, childLength = (children = element.children()).length;
|
||||
childIndex < childLength;
|
||||
childIndex++) {
|
||||
list.push(jQuery(children[childIndex]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return originalJqFn.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
|
||||
var HTML_REGEXP = /<|&#?\w+;/;
|
||||
var TAG_NAME_REGEXP = /<([\w:]+)/;
|
||||
@@ -159,26 +201,22 @@ function jqLiteIsTextNode(html) {
|
||||
return !HTML_REGEXP.test(html);
|
||||
}
|
||||
|
||||
function jqLiteAcceptsData(node) {
|
||||
// The window object can accept data but has no nodeType
|
||||
// Otherwise we are only interested in elements (1) and documents (9)
|
||||
return !node.nodeType || node.nodeType === 1 || node.nodeType === 9;
|
||||
}
|
||||
|
||||
function jqLiteBuildFragment(html, context) {
|
||||
var elem, tmp, tag, wrap,
|
||||
fragment = context.createDocumentFragment(),
|
||||
nodes = [], i;
|
||||
nodes = [], i, j, jj;
|
||||
|
||||
if (jqLiteIsTextNode(html)) {
|
||||
// Convert non-html into a text node
|
||||
nodes.push(context.createTextNode(html));
|
||||
} else {
|
||||
tmp = fragment.appendChild(context.createElement('div'));
|
||||
// Convert html into DOM nodes
|
||||
tmp = tmp || fragment.appendChild(context.createElement("div"));
|
||||
tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
|
||||
wrap = wrapMap[tag] || wrapMap._default;
|
||||
tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
|
||||
tmp.innerHTML = '<div> </div>' +
|
||||
wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
|
||||
tmp.removeChild(tmp.firstChild);
|
||||
|
||||
// Descend through wrappers to the right content
|
||||
i = wrap[0];
|
||||
@@ -186,7 +224,7 @@ function jqLiteBuildFragment(html, context) {
|
||||
tmp = tmp.lastChild;
|
||||
}
|
||||
|
||||
nodes = concat(nodes, tmp.childNodes);
|
||||
for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);
|
||||
|
||||
tmp = fragment.firstChild;
|
||||
tmp.textContent = "";
|
||||
@@ -195,11 +233,7 @@ function jqLiteBuildFragment(html, context) {
|
||||
// Remove wrapper from fragment
|
||||
fragment.textContent = "";
|
||||
fragment.innerHTML = ""; // Clear inner HTML
|
||||
forEach(nodes, function(node) {
|
||||
fragment.appendChild(node);
|
||||
});
|
||||
|
||||
return fragment;
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function jqLiteParseHTML(html, context) {
|
||||
@@ -210,11 +244,7 @@ function jqLiteParseHTML(html, context) {
|
||||
return [context.createElement(parsed[1])];
|
||||
}
|
||||
|
||||
if ((parsed = jqLiteBuildFragment(html, context))) {
|
||||
return parsed.childNodes;
|
||||
}
|
||||
|
||||
return [];
|
||||
return jqLiteBuildFragment(html, context);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
@@ -234,6 +264,8 @@ function JQLite(element) {
|
||||
|
||||
if (isString(element)) {
|
||||
jqLiteAddNodes(this, jqLiteParseHTML(element));
|
||||
var fragment = jqLite(document.createDocumentFragment());
|
||||
fragment.append(this);
|
||||
} else {
|
||||
jqLiteAddNodes(this, element);
|
||||
}
|
||||
@@ -243,16 +275,10 @@ function jqLiteClone(element) {
|
||||
return element.cloneNode(true);
|
||||
}
|
||||
|
||||
function jqLiteDealoc(element, onlyDescendants){
|
||||
if (!onlyDescendants) jqLiteRemoveData(element);
|
||||
|
||||
if (element.childNodes && element.childNodes.length) {
|
||||
// we use querySelectorAll because documentFragments don't have getElementsByTagName
|
||||
var descendants = element.getElementsByTagName ? sliceArgs(element.getElementsByTagName('*')) :
|
||||
element.querySelectorAll ? element.querySelectorAll('*') : [];
|
||||
for (var i = 0, l = descendants.length; i < l; i++) {
|
||||
jqLiteRemoveData(descendants[i]);
|
||||
}
|
||||
function jqLiteDealoc(element){
|
||||
jqLiteRemoveData(element);
|
||||
for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
|
||||
jqLiteDealoc(children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,29 +342,27 @@ function jqLiteExpandoStore(element, key, value) {
|
||||
}
|
||||
|
||||
function jqLiteData(element, key, value) {
|
||||
if (jqLiteAcceptsData(element)) {
|
||||
var data = jqLiteExpandoStore(element, 'data'),
|
||||
isSetter = isDefined(value),
|
||||
keyDefined = !isSetter && isDefined(key),
|
||||
isSimpleGetter = keyDefined && !isObject(key);
|
||||
var data = jqLiteExpandoStore(element, 'data'),
|
||||
isSetter = isDefined(value),
|
||||
keyDefined = !isSetter && isDefined(key),
|
||||
isSimpleGetter = keyDefined && !isObject(key);
|
||||
|
||||
if (!data && !isSimpleGetter) {
|
||||
jqLiteExpandoStore(element, 'data', data = {});
|
||||
}
|
||||
if (!data && !isSimpleGetter) {
|
||||
jqLiteExpandoStore(element, 'data', data = {});
|
||||
}
|
||||
|
||||
if (isSetter) {
|
||||
data[key] = value;
|
||||
} else {
|
||||
if (keyDefined) {
|
||||
if (isSimpleGetter) {
|
||||
// don't create data in this case.
|
||||
return data && data[key];
|
||||
} else {
|
||||
extend(data, key);
|
||||
}
|
||||
if (isSetter) {
|
||||
data[key] = value;
|
||||
} else {
|
||||
if (keyDefined) {
|
||||
if (isSimpleGetter) {
|
||||
// don't create data in this case.
|
||||
return data && data[key];
|
||||
} else {
|
||||
return data;
|
||||
extend(data, key);
|
||||
}
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -377,35 +401,17 @@ function jqLiteAddClass(element, cssClasses) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function jqLiteAddNodes(root, elements) {
|
||||
// THIS CODE IS VERY HOT. Don't make changes without benchmarking.
|
||||
|
||||
if (elements) {
|
||||
|
||||
// if a Node (the most common case)
|
||||
if (elements.nodeType) {
|
||||
root[root.length++] = elements;
|
||||
} else {
|
||||
var length = elements.length;
|
||||
|
||||
// if an Array or NodeList and not a Window
|
||||
if (typeof length === 'number' && elements.window !== elements) {
|
||||
if (length) {
|
||||
if (elements.item) {
|
||||
// convert NodeList to an Array to make PhantomJS 1.x happy
|
||||
elements = slice.call(elements);
|
||||
}
|
||||
push.apply(root, elements);
|
||||
}
|
||||
} else {
|
||||
root[root.length++] = elements;
|
||||
}
|
||||
elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
|
||||
? elements
|
||||
: [ elements ];
|
||||
for(var i=0; i < elements.length; i++) {
|
||||
root.push(elements[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function jqLiteController(element, name) {
|
||||
return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
|
||||
}
|
||||
@@ -431,7 +437,9 @@ function jqLiteInheritedData(element, name, value) {
|
||||
}
|
||||
|
||||
function jqLiteEmpty(element) {
|
||||
jqLiteDealoc(element, true);
|
||||
for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
|
||||
jqLiteDealoc(childNodes[i]);
|
||||
}
|
||||
while (element.firstChild) {
|
||||
element.removeChild(element.firstChild);
|
||||
}
|
||||
@@ -488,25 +496,15 @@ forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','),
|
||||
});
|
||||
var BOOLEAN_ELEMENTS = {};
|
||||
forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
|
||||
BOOLEAN_ELEMENTS[value] = true;
|
||||
BOOLEAN_ELEMENTS[uppercase(value)] = true;
|
||||
});
|
||||
var ALIASED_ATTR = {
|
||||
'ngMinlength' : 'minlength',
|
||||
'ngMaxlength' : 'maxlength',
|
||||
'ngPattern' : 'pattern'
|
||||
};
|
||||
|
||||
function getBooleanAttrName(element, name) {
|
||||
// check dom last since we will most likely fail on name
|
||||
var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
|
||||
|
||||
// booleanAttr is here twice to minimize DOM access
|
||||
return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
|
||||
}
|
||||
|
||||
function getAliasedAttrName(element, name) {
|
||||
var nodeName = element.nodeName;
|
||||
return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
|
||||
return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
|
||||
}
|
||||
|
||||
forEach({
|
||||
@@ -604,21 +602,29 @@ forEach({
|
||||
},
|
||||
|
||||
text: (function() {
|
||||
var NODE_TYPE_TEXT_PROPERTY = [];
|
||||
if (msie < 9) {
|
||||
NODE_TYPE_TEXT_PROPERTY[1] = 'innerText'; /** Element **/
|
||||
NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue'; /** Text **/
|
||||
} else {
|
||||
NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/
|
||||
NODE_TYPE_TEXT_PROPERTY[3] = 'textContent'; /** Text **/
|
||||
}
|
||||
getText.$dv = '';
|
||||
return getText;
|
||||
|
||||
function getText(element, value) {
|
||||
var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
|
||||
if (isUndefined(value)) {
|
||||
var nodeType = element.nodeType;
|
||||
return (nodeType === 1 || nodeType === 3) ? element.textContent : '';
|
||||
return textProp ? element[textProp] : '';
|
||||
}
|
||||
element.textContent = value;
|
||||
element[textProp] = value;
|
||||
}
|
||||
})(),
|
||||
|
||||
val: function(element, value) {
|
||||
if (isUndefined(value)) {
|
||||
if (element.multiple && nodeName_(element) === 'select') {
|
||||
if (nodeName_(element) === 'SELECT' && element.multiple) {
|
||||
var result = [];
|
||||
forEach(element.options, function (option) {
|
||||
if (option.selected) {
|
||||
@@ -636,7 +642,9 @@ forEach({
|
||||
if (isUndefined(value)) {
|
||||
return element.innerHTML;
|
||||
}
|
||||
jqLiteDealoc(element, true);
|
||||
for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
|
||||
jqLiteDealoc(childNodes[i]);
|
||||
}
|
||||
element.innerHTML = value;
|
||||
},
|
||||
|
||||
@@ -756,14 +764,11 @@ function createEventHandler(element, events) {
|
||||
forEach({
|
||||
removeData: jqLiteRemoveData,
|
||||
|
||||
dealoc: jqLiteDealoc,
|
||||
|
||||
on: function onFn(element, type, fn, unsupported){
|
||||
if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
|
||||
|
||||
// Do not add event handlers to non-elements because they will not be cleaned up.
|
||||
if (!jqLiteAcceptsData(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var events = jqLiteExpandoStore(element, 'events'),
|
||||
handle = jqLiteExpandoStore(element, 'handle');
|
||||
|
||||
|
||||
+3
-8
@@ -99,19 +99,15 @@ function setupModuleLoader(window) {
|
||||
/** @type {!Array.<Array.<*>>} */
|
||||
var invokeQueue = [];
|
||||
|
||||
/** @type {!Array.<Function>} */
|
||||
var configBlocks = [];
|
||||
|
||||
/** @type {!Array.<Function>} */
|
||||
var runBlocks = [];
|
||||
|
||||
var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
|
||||
var config = invokeLater('$injector', 'invoke');
|
||||
|
||||
/** @type {angular.Module} */
|
||||
var moduleInstance = {
|
||||
// Private state
|
||||
_invokeQueue: invokeQueue,
|
||||
_configBlocks: configBlocks,
|
||||
_runBlocks: runBlocks,
|
||||
|
||||
/**
|
||||
@@ -303,10 +299,9 @@ function setupModuleLoader(window) {
|
||||
* @param {String=} insertMethod
|
||||
* @returns {angular.Module}
|
||||
*/
|
||||
function invokeLater(provider, method, insertMethod, queue) {
|
||||
if (!queue) queue = invokeQueue;
|
||||
function invokeLater(provider, method, insertMethod) {
|
||||
return function() {
|
||||
queue[insertMethod || 'push']([provider, method, arguments]);
|
||||
invokeQueue[insertMethod || 'push']([provider, method, arguments]);
|
||||
return moduleInstance;
|
||||
};
|
||||
}
|
||||
|
||||
+12
-14
@@ -17,26 +17,24 @@
|
||||
* This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
|
||||
*
|
||||
* @example
|
||||
<example module="anchorScrollExample">
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<div id="scrollArea" ng-controller="ScrollController">
|
||||
<div id="scrollArea" ng-controller="ScrollCtrl">
|
||||
<a ng-click="gotoBottom()">Go to bottom</a>
|
||||
<a id="bottom"></a> You're at the bottom!
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('anchorScrollExample', [])
|
||||
.controller('ScrollController', ['$scope', '$location', '$anchorScroll',
|
||||
function ($scope, $location, $anchorScroll) {
|
||||
$scope.gotoBottom = function() {
|
||||
// set the location.hash to the id of
|
||||
// the element you wish to scroll to.
|
||||
$location.hash('bottom');
|
||||
function ScrollCtrl($scope, $location, $anchorScroll) {
|
||||
$scope.gotoBottom = function (){
|
||||
// set the location.hash to the id of
|
||||
// the element you wish to scroll to.
|
||||
$location.hash('bottom');
|
||||
|
||||
// call $anchorScroll()
|
||||
$anchorScroll();
|
||||
};
|
||||
}]);
|
||||
// call $anchorScroll()
|
||||
$anchorScroll();
|
||||
};
|
||||
}
|
||||
</file>
|
||||
<file name="style.css">
|
||||
#scrollArea {
|
||||
@@ -69,7 +67,7 @@ function $AnchorScrollProvider() {
|
||||
function getFirstAnchor(list) {
|
||||
var result = null;
|
||||
forEach(list, function(element) {
|
||||
if (!result && nodeName_(element) === 'a') result = element;
|
||||
if (!result && lowercase(element.nodeName) === 'a') result = element;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
+14
-15
@@ -111,9 +111,8 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @ngdoc method
|
||||
* @name $animate#enter
|
||||
* @kind function
|
||||
* @description Inserts the element into the DOM either after the `after` element or
|
||||
* as the first child within the `parent` element. Once complete, the done() callback
|
||||
* will be fired (if provided).
|
||||
* @description Inserts the element into the DOM either after the `after` element or within
|
||||
* the `parent` element. Once complete, the done() callback will be fired (if provided).
|
||||
* @param {DOMElement} element the element which will be inserted into the DOM
|
||||
* @param {DOMElement} parent the parent element which will append the element as
|
||||
* a child (if the after element is not present)
|
||||
@@ -123,11 +122,15 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* inserted into the DOM
|
||||
*/
|
||||
enter : function(element, parent, after, done) {
|
||||
after
|
||||
? after.after(element)
|
||||
: parent.prepend(element);
|
||||
if (after) {
|
||||
after.after(element);
|
||||
} else {
|
||||
if (!parent || !parent[0]) {
|
||||
parent = after.parent();
|
||||
}
|
||||
parent.append(element);
|
||||
}
|
||||
async(done);
|
||||
return noop;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -144,7 +147,6 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
leave : function(element, done) {
|
||||
element.remove();
|
||||
async(done);
|
||||
return noop;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -168,7 +170,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
move : function(element, parent, after, done) {
|
||||
// Do not remove element before insert. Removing will cause data associated with the
|
||||
// element to be dropped. Insert will implicitly do the remove.
|
||||
return this.enter(element, parent, after, done);
|
||||
this.enter(element, parent, after, done);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -185,14 +187,13 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* className value has been added to the element
|
||||
*/
|
||||
addClass : function(element, className, done) {
|
||||
className = !isString(className)
|
||||
? (isArray(className) ? className.join(' ') : '')
|
||||
: className;
|
||||
className = isString(className) ?
|
||||
className :
|
||||
isArray(className) ? className.join(' ') : '';
|
||||
forEach(element, function (element) {
|
||||
jqLiteAddClass(element, className);
|
||||
});
|
||||
async(done);
|
||||
return noop;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -216,7 +217,6 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
jqLiteRemoveClass(element, className);
|
||||
});
|
||||
async(done);
|
||||
return noop;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -239,7 +239,6 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
jqLiteRemoveClass(element, remove);
|
||||
});
|
||||
async(done);
|
||||
return noop;
|
||||
},
|
||||
|
||||
enabled : noop
|
||||
|
||||
+5
-4
@@ -280,15 +280,16 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* @returns {Object} Hash of all cookies (if called without any parameter)
|
||||
*/
|
||||
self.cookies = function(name, value) {
|
||||
/* global escape: false, unescape: false */
|
||||
var cookieLength, cookieArray, cookie, i, index;
|
||||
|
||||
if (name) {
|
||||
if (value === undefined) {
|
||||
rawDocument.cookie = encodeURIComponent(name) + "=;path=" + cookiePath +
|
||||
rawDocument.cookie = escape(name) + "=;path=" + cookiePath +
|
||||
";expires=Thu, 01 Jan 1970 00:00:00 GMT";
|
||||
} else {
|
||||
if (isString(value)) {
|
||||
cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) +
|
||||
cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
|
||||
';path=' + cookiePath).length + 1;
|
||||
|
||||
// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
|
||||
@@ -312,12 +313,12 @@ function Browser(window, document, $log, $sniffer) {
|
||||
cookie = cookieArray[i];
|
||||
index = cookie.indexOf('=');
|
||||
if (index > 0) { //ignore nameless cookies
|
||||
name = decodeURIComponent(cookie.substring(0, index));
|
||||
name = unescape(cookie.substring(0, index));
|
||||
// the first value that is seen for a cookie is the most
|
||||
// specific one. values for the same cookie name that
|
||||
// follow are for less specific paths.
|
||||
if (lastCookies[name] === undefined) {
|
||||
lastCookies[name] = decodeURIComponent(cookie.substring(index + 1));
|
||||
lastCookies[name] = unescape(cookie.substring(index + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+60
-150
@@ -111,13 +111,6 @@
|
||||
* The directive definition object provides instructions to the {@link ng.$compile
|
||||
* compiler}. The attributes are:
|
||||
*
|
||||
* #### `multiElement`
|
||||
* When this property is set to true, the HTML compiler will collect DOM nodes between
|
||||
* nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
|
||||
* together as the directive elements. It is recomended that this feature be used on directives
|
||||
* which are not strictly behavioural (such as {@link api/ng.directive:ngClick ngClick}), and which
|
||||
* do not manipulate or replace child nodes (such as {@link api/ng.directive:ngInclude ngInclude}).
|
||||
*
|
||||
* #### `priority`
|
||||
* When there are multiple directives defined on a single DOM element, sometimes it
|
||||
* is necessary to specify the order in which the directives are applied. The `priority` is used
|
||||
@@ -213,25 +206,12 @@
|
||||
* String of subset of `EACM` which restricts the directive to a specific directive
|
||||
* declaration style. If omitted, the default (attributes only) is used.
|
||||
*
|
||||
* * `E` - Element name (default): `<my-directive></my-directive>`
|
||||
* * `E` - Element name: `<my-directive></my-directive>`
|
||||
* * `A` - Attribute (default): `<div my-directive="exp"></div>`
|
||||
* * `C` - Class: `<div class="my-directive: exp;"></div>`
|
||||
* * `M` - Comment: `<!-- directive: my-directive exp -->`
|
||||
*
|
||||
*
|
||||
* #### `type`
|
||||
* String representing the document type used by the markup. This is useful for templates where the root
|
||||
* node is non-HTML content (such as SVG or MathML). The default value is "html".
|
||||
*
|
||||
* * `html` - All root template nodes are HTML, and don't need to be wrapped. Root nodes may also be
|
||||
* top-level elements such as `<svg>` or `<math>`.
|
||||
* * `svg` - The template contains only SVG content, and must be wrapped in an `<svg>` node prior to
|
||||
* processing.
|
||||
* * `math` - The template contains only MathML content, and must be wrapped in an `<math>` node prior to
|
||||
* processing.
|
||||
*
|
||||
* If no `type` is specified, then the type is considered to be html.
|
||||
*
|
||||
* #### `template`
|
||||
* HTML markup that may:
|
||||
* * Replace the contents of the directive's element (default).
|
||||
@@ -537,8 +517,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var hasDirectives = {},
|
||||
Suffix = 'Directive',
|
||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/,
|
||||
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset');
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
|
||||
|
||||
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
|
||||
// The assumption is that future DOM event attribute names will begin with
|
||||
@@ -581,7 +560,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
directive.index = index;
|
||||
directive.name = directive.name || name;
|
||||
directive.require = directive.require || (directive.controller && directive.name);
|
||||
directive.restrict = directive.restrict || 'EA';
|
||||
directive.restrict = directive.restrict || 'A';
|
||||
directives.push(directive);
|
||||
} catch (e) {
|
||||
$exceptionHandler(e);
|
||||
@@ -745,19 +724,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
//is set through this function since it may cause $updateClass to
|
||||
//become unstable.
|
||||
|
||||
var node = this.$$element[0],
|
||||
booleanKey = getBooleanAttrName(node, key),
|
||||
aliasedKey = getAliasedAttrName(node, key),
|
||||
observer = key,
|
||||
var booleanKey = getBooleanAttrName(this.$$element[0], key),
|
||||
normalizedVal,
|
||||
nodeName;
|
||||
|
||||
if (booleanKey) {
|
||||
this.$$element.prop(key, value);
|
||||
attrName = booleanKey;
|
||||
} else if(aliasedKey) {
|
||||
this[aliasedKey] = value;
|
||||
observer = aliasedKey;
|
||||
}
|
||||
|
||||
this[key] = value;
|
||||
@@ -775,8 +748,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
nodeName = nodeName_(this.$$element);
|
||||
|
||||
// sanitize a[href] and img[src] values
|
||||
if ((nodeName === 'a' && key === 'href') ||
|
||||
(nodeName === 'img' && key === 'src')) {
|
||||
if ((nodeName === 'A' && key === 'href') ||
|
||||
(nodeName === 'IMG' && key === 'src')) {
|
||||
this[key] = value = $$sanitizeUri(value, key === 'src');
|
||||
}
|
||||
|
||||
@@ -790,7 +763,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
// fire observers
|
||||
var $$observers = this.$$observers;
|
||||
$$observers && forEach($$observers[observer], function(fn) {
|
||||
$$observers && forEach($$observers[key], function(fn) {
|
||||
try {
|
||||
fn(value);
|
||||
} catch (e) {
|
||||
@@ -816,7 +789,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
* @param {function(interpolatedValue)} fn Function that will be called whenever
|
||||
the interpolated value of the attribute changes.
|
||||
* See the {@link guide/directive#Attributes Directives} guide for more info.
|
||||
* @returns {function()} Returns a deregistration function for this observer.
|
||||
* @returns {function()} the `fn` parameter.
|
||||
*/
|
||||
$observe: function(key, fn) {
|
||||
var attrs = this,
|
||||
@@ -830,10 +803,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
fn(attrs[key]);
|
||||
}
|
||||
});
|
||||
|
||||
return function() {
|
||||
arrayRemove(listeners, fn);
|
||||
};
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -881,7 +851,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
$linkNode.data('$' + name + 'Controller', instance);
|
||||
});
|
||||
|
||||
$linkNode.data('$scope', scope);
|
||||
// Attach scope only to non-text nodes.
|
||||
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
|
||||
var node = $linkNode[i],
|
||||
nodeType = node.nodeType;
|
||||
if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
|
||||
$linkNode.eq(i).data('$scope', scope);
|
||||
}
|
||||
}
|
||||
|
||||
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
||||
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
|
||||
@@ -1038,7 +1015,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
case 1: /* Element */
|
||||
// use the node name: <directive>
|
||||
addDirective(directives,
|
||||
directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
|
||||
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
|
||||
|
||||
// iterate over the attributes
|
||||
for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
|
||||
@@ -1058,12 +1035,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
|
||||
if (directiveIsMultiElement(directiveNName)) {
|
||||
if (ngAttrName === directiveNName + 'Start') {
|
||||
attrStartName = name;
|
||||
attrEndName = name.substr(0, name.length - 5) + 'end';
|
||||
name = name.substr(0, name.length - 6);
|
||||
}
|
||||
if (ngAttrName === directiveNName + 'Start') {
|
||||
attrStartName = name;
|
||||
attrEndName = name.substr(0, name.length - 5) + 'end';
|
||||
name = name.substr(0, name.length - 6);
|
||||
}
|
||||
|
||||
nName = directiveNormalize(name.toLowerCase());
|
||||
@@ -1227,25 +1202,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
if (directiveValue = directive.scope) {
|
||||
newScopeDirective = newScopeDirective || directive;
|
||||
|
||||
// skip the check for directives with async templates, we'll check the derived sync
|
||||
// directive when the template arrives
|
||||
if (!directive.templateUrl) {
|
||||
assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
|
||||
$compileNode);
|
||||
if (isObject(directiveValue)) {
|
||||
// This directive is trying to add an isolated scope.
|
||||
// Check that there is no scope of any kind already
|
||||
assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
|
||||
directive, $compileNode);
|
||||
newIsolateScopeDirective = directive;
|
||||
} else {
|
||||
// This directive is trying to add a child scope.
|
||||
// Check that there is no isolated scope already
|
||||
assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
|
||||
$compileNode);
|
||||
}
|
||||
}
|
||||
|
||||
newScopeDirective = newScopeDirective || directive;
|
||||
}
|
||||
|
||||
directiveName = directive.name;
|
||||
@@ -1313,7 +1280,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (jqLiteIsTextNode(directiveValue)) {
|
||||
$template = [];
|
||||
} else {
|
||||
$template = jqLite(wrapTemplate(directive.type, trim(directiveValue)));
|
||||
$template = jqLite(trim(directiveValue));
|
||||
}
|
||||
compileNode = $template[0];
|
||||
|
||||
@@ -1517,7 +1484,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
attrs[attrName], newIsolateScopeDirective.name);
|
||||
};
|
||||
lastValue = isolateScope[scopeName] = parentGet(scope);
|
||||
var unwatch = scope.$watch($parse(attrs[attrName], function parentValueWatch(parentValue) {
|
||||
isolateScope.$watch(function parentValueWatch() {
|
||||
var parentValue = parentGet(scope);
|
||||
if (!compare(parentValue, isolateScope[scopeName])) {
|
||||
// we are out of sync and need to copy
|
||||
if (!compare(parentValue, lastValue)) {
|
||||
@@ -1529,8 +1497,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
}
|
||||
return lastValue = parentValue;
|
||||
}), null, parentGet.literal);
|
||||
isolateScope.$on('$destroy', unwatch);
|
||||
}, null, parentGet.literal);
|
||||
break;
|
||||
|
||||
case '&':
|
||||
@@ -1675,27 +1642,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* looks up the directive and returns true if it is a multi-element directive,
|
||||
* and therefore requires DOM nodes between -start and -end markers to be grouped
|
||||
* together.
|
||||
*
|
||||
* @param {string} name name of the directive to look up.
|
||||
* @returns true if directive was registered as multi-element.
|
||||
*/
|
||||
function directiveIsMultiElement(name) {
|
||||
if (hasDirectives.hasOwnProperty(name)) {
|
||||
for(var directive, directives = $injector.get(name + Suffix),
|
||||
i = 0, ii = directives.length; i<ii; i++) {
|
||||
directive = directives[i];
|
||||
if (directive.multiElement) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the element is replaced with HTML template then the new attributes
|
||||
* on the template need to be merged with the existing attributes in the DOM.
|
||||
@@ -1751,8 +1697,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}),
|
||||
templateUrl = (isFunction(origAsyncDirective.templateUrl))
|
||||
? origAsyncDirective.templateUrl($compileNode, tAttrs)
|
||||
: origAsyncDirective.templateUrl,
|
||||
type = origAsyncDirective.type;
|
||||
: origAsyncDirective.templateUrl;
|
||||
|
||||
$compileNode.empty();
|
||||
|
||||
@@ -1766,7 +1711,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (jqLiteIsTextNode(content)) {
|
||||
$template = [];
|
||||
} else {
|
||||
$template = jqLite(wrapTemplate(type, trim(content)));
|
||||
$template = jqLite(trim(content));
|
||||
}
|
||||
compileNode = $template[0];
|
||||
|
||||
@@ -1873,45 +1818,31 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
|
||||
function addTextInterpolateDirective(directives, text) {
|
||||
var interpolateFn = $interpolate(text, true);
|
||||
if (interpolateFn) {
|
||||
directives.push({
|
||||
priority: 0,
|
||||
compile: function textInterpolateCompileFn(templateNode) {
|
||||
// when transcluding a template that has bindings in the root
|
||||
// then we don't have a parent and should do this in the linkFn
|
||||
var parent = templateNode.parent(), hasCompileParent = parent.length;
|
||||
if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
|
||||
function addTextInterpolateDirective(directives, text) {
|
||||
var interpolateFn = $interpolate(text, true);
|
||||
if (interpolateFn) {
|
||||
directives.push({
|
||||
priority: 0,
|
||||
compile: function textInterpolateCompileFn(templateNode) {
|
||||
// when transcluding a template that has bindings in the root
|
||||
// then we don't have a parent and should do this in the linkFn
|
||||
var parent = templateNode.parent(), hasCompileParent = parent.length;
|
||||
if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
|
||||
|
||||
return function textInterpolateLinkFn(scope, node) {
|
||||
var parent = node.parent(),
|
||||
return function textInterpolateLinkFn(scope, node) {
|
||||
var parent = node.parent(),
|
||||
bindings = parent.data('$binding') || [];
|
||||
bindings.push(interpolateFn);
|
||||
parent.data('$binding', bindings);
|
||||
if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
|
||||
scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
|
||||
node[0].nodeValue = value;
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
bindings.push(interpolateFn);
|
||||
parent.data('$binding', bindings);
|
||||
if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
|
||||
scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
|
||||
node[0].nodeValue = value;
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function wrapTemplate(type, template) {
|
||||
type = lowercase(type || 'html');
|
||||
switch(type) {
|
||||
case 'svg':
|
||||
case 'math':
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = '<'+type+'>'+template+'</'+type+'>';
|
||||
return wrapper.childNodes[0].childNodes;
|
||||
default:
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getTrustedContext(node, attrNormalizedName) {
|
||||
@@ -1921,8 +1852,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var tag = nodeName_(node);
|
||||
// maction[xlink:href] can source SVG. It's not limited to <maction>.
|
||||
if (attrNormalizedName == "xlinkHref" ||
|
||||
(tag == "form" && attrNormalizedName == "action") ||
|
||||
(tag != "img" && (attrNormalizedName == "src" ||
|
||||
(tag == "FORM" && attrNormalizedName == "action") ||
|
||||
(tag != "IMG" && (attrNormalizedName == "src" ||
|
||||
attrNormalizedName == "ngSrc"))) {
|
||||
return $sce.RESOURCE_URL;
|
||||
}
|
||||
@@ -1936,7 +1867,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (!interpolateFn) return;
|
||||
|
||||
|
||||
if (name === "multiple" && nodeName_(node) === "select") {
|
||||
if (name === "multiple" && nodeName_(node) === "SELECT") {
|
||||
throw $compileMinErr("selmulti",
|
||||
"Binding to the 'multiple' attribute is not supported. Element: {0}",
|
||||
startingTag(node));
|
||||
@@ -1957,18 +1888,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
// we need to interpolate again, in case the attribute value has been updated
|
||||
// (e.g. by another directive's compile function)
|
||||
interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name),
|
||||
ALL_OR_NOTHING_ATTRS[name]);
|
||||
interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
|
||||
|
||||
// if attribute was updated so that there is no interpolation going on we don't want to
|
||||
// register any observers
|
||||
if (!interpolateFn) return;
|
||||
|
||||
// initialize attr object so that it's ready in case we need the value for isolate
|
||||
// scope initialization, otherwise the value would not be available from isolate
|
||||
// directive's linking fn during linking phase
|
||||
// TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
|
||||
// actual attr value
|
||||
attr[name] = interpolateFn(scope);
|
||||
|
||||
($$observers[name] || ($$observers[name] = [])).$$inter = true;
|
||||
(attr.$$observers && attr.$$observers[name].$$scope || scope).
|
||||
$watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
|
||||
@@ -2031,25 +1959,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
var fragment = document.createDocumentFragment();
|
||||
fragment.appendChild(firstElementToRemove);
|
||||
|
||||
// Copy over user data (that includes Angular's $scope etc.). Don't copy private
|
||||
// data here because there's no public interface in jQuery to do that and copying over
|
||||
// event listeners (which is the main use of private data) wouldn't work anyway.
|
||||
jqLite(newNode).data(jqLite(firstElementToRemove).data());
|
||||
|
||||
// Remove data of the replaced element. We cannot just call .remove()
|
||||
// on the element it since that would deallocate scope that is needed
|
||||
// for the new node. Instead, remove the data "manually".
|
||||
if (!jQuery) {
|
||||
delete jqLite.cache[firstElementToRemove[jqLite.expando]];
|
||||
} else {
|
||||
// jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after the replaced
|
||||
// element. Note that we need to use the original method here and not the one monkey-patched by Angular
|
||||
// since the patched method emits the $destroy event causing the scope to be trashed and we do need
|
||||
// the very same scope to work with the new element.
|
||||
jQuery.cleanData.$$original([firstElementToRemove]);
|
||||
}
|
||||
|
||||
newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
|
||||
for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
|
||||
var element = elementsToRemove[k];
|
||||
jqLite(element).remove(); // must do this way to clean up expando
|
||||
|
||||
+3
-15
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
function $ControllerProvider() {
|
||||
var controllers = {},
|
||||
globals = false,
|
||||
CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
|
||||
|
||||
|
||||
@@ -33,15 +32,6 @@ function $ControllerProvider() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $controllerProvider#allowGlobals
|
||||
* @description If called, allows `$controller` to find controller constructors on `window`
|
||||
*/
|
||||
this.allowGlobals = function() {
|
||||
globals = true;
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$injector', '$window', function($injector, $window) {
|
||||
|
||||
@@ -56,8 +46,7 @@ function $ControllerProvider() {
|
||||
*
|
||||
* * check if a controller with given name is registered via `$controllerProvider`
|
||||
* * check if evaluating the string on the current scope returns a constructor
|
||||
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
|
||||
* `window` object (not recommended)
|
||||
* * check `window[constructor]` on the global `window` object
|
||||
*
|
||||
* @param {Object} locals Injection locals for Controller.
|
||||
* @return {Object} Instance of given controller.
|
||||
@@ -77,13 +66,12 @@ function $ControllerProvider() {
|
||||
identifier = match[3];
|
||||
expression = controllers.hasOwnProperty(constructor)
|
||||
? controllers[constructor]
|
||||
: getter(locals.$scope, constructor, true) ||
|
||||
(globals ? getter($window, constructor, true) : undefined);
|
||||
: getter(locals.$scope, constructor, true) || getter($window, constructor, true);
|
||||
|
||||
assertArgFn(expression, constructor, true);
|
||||
}
|
||||
|
||||
instance = $injector.instantiate(expression, locals, constructor);
|
||||
instance = $injector.instantiate(expression, locals);
|
||||
|
||||
if (identifier) {
|
||||
if (!(locals && typeof locals.$scope === 'object')) {
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
*
|
||||
* The wrong way to write it:
|
||||
* ```html
|
||||
* <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
|
||||
* <a href="http://www.gravatar.com/avatar/{{hash}}"/>
|
||||
* ```
|
||||
*
|
||||
* The correct way to write it:
|
||||
* ```html
|
||||
* <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
|
||||
* <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
|
||||
* ```
|
||||
*
|
||||
* @element A
|
||||
@@ -351,7 +351,6 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
|
||||
var normalized = directiveNormalize('ng-' + attrName);
|
||||
ngAttributeAliasDirectives[normalized] = function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
priority: 100,
|
||||
link: function(scope, element, attr) {
|
||||
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
|
||||
@@ -362,29 +361,6 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
|
||||
};
|
||||
});
|
||||
|
||||
// aliased input attrs are evaluated
|
||||
forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
|
||||
ngAttributeAliasDirectives[ngAttr] = function() {
|
||||
return {
|
||||
priority: 100,
|
||||
link: function(scope, element, attr) {
|
||||
//special case ngPattern when a literal regular expression value
|
||||
//is used as the expression (this way we don't have to watch anything).
|
||||
if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
|
||||
var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
|
||||
if (match) {
|
||||
attr.$set("ngPattern", new RegExp(match[1], match[2]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
|
||||
attr.$set(ngAttr, value);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
// ng-src, ng-srcset, ng-href are interpolated
|
||||
forEach(['src', 'srcset', 'href'], function(attrName) {
|
||||
@@ -404,12 +380,8 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
|
||||
}
|
||||
|
||||
attr.$observe(normalized, function(value) {
|
||||
if (!value) {
|
||||
if (attrName === 'href') {
|
||||
attr.$set(name, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!value)
|
||||
return;
|
||||
|
||||
attr.$set(name, value);
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
/* global -nullFormCtrl, -SUBMITTED_CLASS */
|
||||
/* global -nullFormCtrl */
|
||||
var nullFormCtrl = {
|
||||
$addControl: noop,
|
||||
$removeControl: noop,
|
||||
$setValidity: noop,
|
||||
$setDirty: noop,
|
||||
$setPristine: noop,
|
||||
$setSubmitted: noop
|
||||
},
|
||||
SUBMITTED_CLASS = 'ng-submitted';
|
||||
$setPristine: noop
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc type
|
||||
@@ -62,7 +60,6 @@ function FormController(element, attrs, $scope, $animate) {
|
||||
form.$pristine = true;
|
||||
form.$valid = true;
|
||||
form.$invalid = false;
|
||||
form.$submitted = false;
|
||||
|
||||
parentForm.$addControl(form);
|
||||
|
||||
@@ -77,40 +74,6 @@ function FormController(element, attrs, $scope, $animate) {
|
||||
$animate.addClass(element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name form.FormController#$rollbackViewValue
|
||||
*
|
||||
* @description
|
||||
* Rollback all form controls pending updates to the `$modelValue`.
|
||||
*
|
||||
* Updates may be pending by a debounced event or because the input is waiting for a some future
|
||||
* event defined in `ng-model-options`. This method is typically needed by the reset button of
|
||||
* a form that uses `ng-model-options` to pend updates.
|
||||
*/
|
||||
form.$rollbackViewValue = function() {
|
||||
forEach(controls, function(control) {
|
||||
control.$rollbackViewValue();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name form.FormController#$commitViewValue
|
||||
*
|
||||
* @description
|
||||
* Commit all form controls pending updates to the `$modelValue`.
|
||||
*
|
||||
* Updates may be pending by a debounced event or because the input is waiting for a some future
|
||||
* event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
|
||||
* usually handles calling this in response to input events.
|
||||
*/
|
||||
form.$commitViewValue = function() {
|
||||
forEach(controls, function(control) {
|
||||
control.$commitViewValue();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name form.FormController#$addControl
|
||||
@@ -231,29 +194,17 @@ function FormController(element, attrs, $scope, $animate) {
|
||||
* saving or resetting it.
|
||||
*/
|
||||
form.$setPristine = function () {
|
||||
$animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
|
||||
$animate.removeClass(element, DIRTY_CLASS);
|
||||
$animate.addClass(element, PRISTINE_CLASS);
|
||||
form.$dirty = false;
|
||||
form.$pristine = true;
|
||||
form.$submitted = false;
|
||||
forEach(controls, function(control) {
|
||||
control.$setPristine();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name form.FormController#setSubmitted
|
||||
*
|
||||
* @description
|
||||
* Sets the form to its submitted state.
|
||||
*/
|
||||
form.$setSubmitted = function () {
|
||||
$animate.addClass(element, SUBMITTED_CLASS);
|
||||
form.$submitted = true;
|
||||
parentForm.$setSubmitted();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngForm
|
||||
@@ -302,7 +253,6 @@ function FormController(element, attrs, $scope, $animate) {
|
||||
* - `ng-invalid` is set if the form is invalid.
|
||||
* - `ng-pristine` is set if the form is pristine.
|
||||
* - `ng-dirty` is set if the form is dirty.
|
||||
* - `ng-submitted` is set if the form was submitted.
|
||||
*
|
||||
* Keep in mind that ngAnimate can detect each of these classes when added and removed.
|
||||
*
|
||||
@@ -336,10 +286,6 @@ function FormController(element, attrs, $scope, $animate) {
|
||||
* hitting enter in any of the input fields will trigger the click handler on the *first* button or
|
||||
* input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
|
||||
*
|
||||
* Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
|
||||
* submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
|
||||
* to have access to the updated model.
|
||||
*
|
||||
* @param {string=} name Name of the form. If specified, the form controller will be published into
|
||||
* related scope, under this name.
|
||||
*
|
||||
@@ -436,24 +382,19 @@ var formDirectiveFactory = function(isNgForm) {
|
||||
// IE 9 is not affected because it doesn't fire a submit event and try to do a full
|
||||
// page reload if the form was destroyed by submission of the form via a click handler
|
||||
// on a button in the form. Looks like an IE9 specific bug.
|
||||
var handleFormSubmission = function(event) {
|
||||
scope.$apply(function() {
|
||||
controller.$commitViewValue();
|
||||
controller.$setSubmitted();
|
||||
});
|
||||
|
||||
var preventDefaultListener = function(event) {
|
||||
event.preventDefault
|
||||
? event.preventDefault()
|
||||
: event.returnValue = false; // IE
|
||||
};
|
||||
|
||||
addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
|
||||
addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
|
||||
|
||||
// unregister the preventDefault listener so that we don't not leak memory but in a
|
||||
// way that will achieve the prevention of the default action.
|
||||
formElement.on('$destroy', function() {
|
||||
$timeout(function() {
|
||||
removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
|
||||
removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
|
||||
}, 0, false);
|
||||
});
|
||||
}
|
||||
|
||||
+214
-1304
File diff suppressed because it is too large
Load Diff
@@ -178,20 +178,19 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
||||
*/
|
||||
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
compile: function (tElement, tAttrs) {
|
||||
compile: function (tElement) {
|
||||
tElement.addClass('ng-binding');
|
||||
|
||||
return function (scope, element, attr) {
|
||||
element.data('$binding', attr.ngBindHtml);
|
||||
var parsed = $parse(attr.ngBindHtml);
|
||||
var changeDetector = $parse(attr.ngBindHtml, function getStringValue(value) {
|
||||
return (value || '').toString();
|
||||
});
|
||||
|
||||
scope.$watch(changeDetector, function ngBindHtmlWatchAction() {
|
||||
// we re-evaluate the expr because we want a TrustedValueHolderType
|
||||
// for $sce, not a string
|
||||
var parsed = $parse(attr.ngBindHtml);
|
||||
|
||||
function getStringValue() {
|
||||
return (parsed(scope) || '').toString();
|
||||
}
|
||||
|
||||
scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
|
||||
element.html($sce.getTrustedHtml(parsed(scope)) || '');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -23,16 +23,10 @@
|
||||
*
|
||||
* @element ANY
|
||||
* @scope
|
||||
* @param {expression} ngController Name of a constructor function registered with the current
|
||||
* {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
|
||||
* that on the current scope evaluates to a constructor function.
|
||||
*
|
||||
* The controller instance can be published into a scope property by specifying
|
||||
* `ng-controller="as propertyName"`.
|
||||
*
|
||||
* If the current `$controllerProvider` is configured to use globals (via
|
||||
* {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
|
||||
* also be the name of a globally accessible constructor function (not recommended).
|
||||
* @param {expression} ngController Name of a globally accessible constructor function or an
|
||||
* {@link guide/expression expression} that on the current scope evaluates to a
|
||||
* constructor function. The controller instance can be published into a scope property
|
||||
* by specifying `as propertyName`.
|
||||
*
|
||||
* @example
|
||||
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
|
||||
@@ -227,7 +221,6 @@
|
||||
*/
|
||||
var ngControllerDirective = [function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: true,
|
||||
controller: '@',
|
||||
priority: 500
|
||||
|
||||
@@ -43,7 +43,6 @@ forEach(
|
||||
var directiveName = directiveNormalize('ng-' + name);
|
||||
ngEventDirectives[directiveName] = ['$parse', function($parse) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
compile: function($element, attr) {
|
||||
var fn = $parse(attr[directiveName]);
|
||||
return function ngEventHandler(scope, element) {
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
*/
|
||||
var ngIfDirective = ['$animate', function($animate) {
|
||||
return {
|
||||
multiElement: true,
|
||||
transclude: 'element',
|
||||
priority: 600,
|
||||
terminal: true,
|
||||
@@ -88,10 +87,10 @@ var ngIfDirective = ['$animate', function($animate) {
|
||||
var block, childScope, previousElements;
|
||||
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
|
||||
|
||||
if (value) {
|
||||
if (toBoolean(value)) {
|
||||
if (!childScope) {
|
||||
$transclude(function (clone, newScope) {
|
||||
childScope = newScope;
|
||||
childScope = $scope.$new();
|
||||
$transclude(childScope, function (clone) {
|
||||
clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
|
||||
// Note: We only need the first/last node of the cloned nodes.
|
||||
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
||||
|
||||
@@ -160,15 +160,6 @@
|
||||
* @description
|
||||
* Emitted every time the ngInclude content is reloaded.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngInclude#$includeContentError
|
||||
* @eventType emit on the scope ngInclude was declared in
|
||||
* @description
|
||||
* Emitted when a template HTTP request yields an erronous response (status < 200 || status > 299)
|
||||
*/
|
||||
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
|
||||
function($http, $templateCache, $anchorScroll, $animate, $sce) {
|
||||
return {
|
||||
@@ -237,10 +228,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate'
|
||||
currentScope.$emit('$includeContentLoaded');
|
||||
scope.$eval(onloadExp);
|
||||
}).error(function() {
|
||||
if (thisChangeId === changeCounter) {
|
||||
cleanupLastIncludeContent();
|
||||
scope.$emit('$includeContentError');
|
||||
}
|
||||
if (thisChangeId === changeCounter) cleanupLastIncludeContent();
|
||||
});
|
||||
scope.$emit('$includeContentRequested');
|
||||
} else {
|
||||
|
||||
@@ -205,7 +205,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
||||
//if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
|
||||
//check it against pluralization rules in $locale service
|
||||
if (!(value in whens)) value = $locale.pluralCat(value - offset);
|
||||
return whensExpFns[value](scope);
|
||||
return whensExpFns[value](scope, element, true);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -100,13 +100,6 @@
|
||||
* For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
|
||||
* will be associated by item identity in the array.
|
||||
*
|
||||
* * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
|
||||
* intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
|
||||
* when a filter is active on the repeater, but the filtered result set is empty.
|
||||
*
|
||||
* For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
|
||||
* the items have been processed through the filter.
|
||||
*
|
||||
* For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
|
||||
* `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
|
||||
* with the corresponding item in the array by identity. Moving the same object in array would move the DOM
|
||||
@@ -139,12 +132,9 @@
|
||||
I have {{friends.length}} friends. They are:
|
||||
<input type="search" ng-model="q" placeholder="filter friends..." />
|
||||
<ul class="example-animate-container">
|
||||
<li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
|
||||
<li class="animate-repeat" ng-repeat="friend in friends | filter:q">
|
||||
[{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
|
||||
</li>
|
||||
<li class="animate-repeat" ng-if="results.length == 0">
|
||||
<strong>No results found...</strong>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</file>
|
||||
@@ -212,16 +202,14 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
var NG_REMOVED = '$$NG_REMOVED';
|
||||
var ngRepeatMinErr = minErr('ngRepeat');
|
||||
return {
|
||||
restrict: 'A',
|
||||
multiElement: true,
|
||||
transclude: 'element',
|
||||
priority: 1000,
|
||||
terminal: true,
|
||||
$$tlb: true,
|
||||
link: function($scope, $element, $attr, ctrl, $transclude){
|
||||
var expression = $attr.ngRepeat;
|
||||
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
|
||||
trackByExp, trackByExpGetter, aliasAs, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
|
||||
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
|
||||
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
|
||||
lhs, rhs, valueIdentifier, keyIdentifier,
|
||||
hashFnLocals = {$id: hashKey};
|
||||
|
||||
@@ -232,8 +220,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
|
||||
lhs = match[1];
|
||||
rhs = match[2];
|
||||
aliasAs = match[3];
|
||||
trackByExp = match[4];
|
||||
trackByExp = match[3];
|
||||
|
||||
if (trackByExp) {
|
||||
trackByExpGetter = $parse(trackByExp);
|
||||
@@ -277,6 +264,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
// lastBlockMap on the next iteration.
|
||||
nextBlockMap = {},
|
||||
arrayLength,
|
||||
childScope,
|
||||
key, value, // key/value of iteration
|
||||
trackById,
|
||||
trackByIdFn,
|
||||
@@ -285,21 +273,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
nextBlockOrder = [],
|
||||
elementsToRemove;
|
||||
|
||||
if (aliasAs) {
|
||||
$scope[aliasAs] = collection;
|
||||
}
|
||||
|
||||
var updateScope = function(scope, index) {
|
||||
scope[valueIdentifier] = value;
|
||||
if (keyIdentifier) scope[keyIdentifier] = key;
|
||||
scope.$index = index;
|
||||
scope.$first = (index === 0);
|
||||
scope.$last = (index === (arrayLength - 1));
|
||||
scope.$middle = !(scope.$first || scope.$last);
|
||||
// jshint bitwise: false
|
||||
scope.$odd = !(scope.$even = (index&1) === 0);
|
||||
// jshint bitwise: true
|
||||
};
|
||||
|
||||
if (isArrayLike(collection)) {
|
||||
collectionKeys = collection;
|
||||
@@ -308,9 +281,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
|
||||
// if object, extract keys, sort them and use to determine order of iteration over obj props
|
||||
collectionKeys = [];
|
||||
for (var itemKey in collection) {
|
||||
if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) != '$') {
|
||||
collectionKeys.push(itemKey);
|
||||
for (key in collection) {
|
||||
if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
|
||||
collectionKeys.push(key);
|
||||
}
|
||||
}
|
||||
collectionKeys.sort();
|
||||
@@ -346,10 +319,10 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
}
|
||||
|
||||
// remove existing items
|
||||
for (var blockKey in lastBlockMap) {
|
||||
for (key in lastBlockMap) {
|
||||
// lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
|
||||
if (lastBlockMap.hasOwnProperty(blockKey)) {
|
||||
block = lastBlockMap[blockKey];
|
||||
if (lastBlockMap.hasOwnProperty(key)) {
|
||||
block = lastBlockMap[key];
|
||||
elementsToRemove = getBlockElements(block.clone);
|
||||
$animate.leave(elementsToRemove);
|
||||
forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
|
||||
@@ -367,6 +340,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
if (block.scope) {
|
||||
// if we have already seen this object, then we need to reuse the
|
||||
// associated scope/element
|
||||
childScope = block.scope;
|
||||
|
||||
nextNode = previousNode;
|
||||
do {
|
||||
nextNode = nextNode.nextSibling;
|
||||
@@ -377,20 +352,32 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
$animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
|
||||
}
|
||||
previousNode = getBlockEnd(block);
|
||||
updateScope(block.scope, index);
|
||||
} else {
|
||||
// new item which we don't know about
|
||||
$transclude(function(clone, scope) {
|
||||
block.scope = scope;
|
||||
childScope = $scope.$new();
|
||||
}
|
||||
|
||||
childScope[valueIdentifier] = value;
|
||||
if (keyIdentifier) childScope[keyIdentifier] = key;
|
||||
childScope.$index = index;
|
||||
childScope.$first = (index === 0);
|
||||
childScope.$last = (index === (arrayLength - 1));
|
||||
childScope.$middle = !(childScope.$first || childScope.$last);
|
||||
// jshint bitwise: false
|
||||
childScope.$odd = !(childScope.$even = (index&1) === 0);
|
||||
// jshint bitwise: true
|
||||
|
||||
if (!block.scope) {
|
||||
$transclude(childScope, function(clone) {
|
||||
clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
|
||||
$animate.enter(clone, null, jqLite(previousNode));
|
||||
previousNode = clone;
|
||||
block.scope = childScope;
|
||||
// Note: We only need the first/last node of the cloned nodes.
|
||||
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
||||
// by a directive with templateUrl when its template arrives.
|
||||
block.clone = clone;
|
||||
nextBlockMap[block.id] = block;
|
||||
updateScope(block.scope, index);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,15 @@
|
||||
* <div ng-show="myValue" class="ng-hide"></div>
|
||||
* ```
|
||||
*
|
||||
* When the ngShow expression evaluates to a falsy value then the ng-hide CSS class is added to the class
|
||||
* attribute on the element causing it to become hidden. When truthy, the ng-hide CSS class is removed
|
||||
* When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
|
||||
* on the element causing it to become hidden. When true, the ng-hide CSS class is removed
|
||||
* from the element causing the element not to appear hidden.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
|
||||
* "f" / "0" / "false" / "no" / "n" / "[]"
|
||||
* </div>
|
||||
*
|
||||
* ## Why is !important used?
|
||||
*
|
||||
* You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
|
||||
@@ -42,7 +47,7 @@
|
||||
*
|
||||
* ```css
|
||||
* .ng-hide {
|
||||
* /* this is just another form of hiding an element */
|
||||
* //this is just another form of hiding an element
|
||||
* display:block!important;
|
||||
* position:absolute;
|
||||
* top:-9999px;
|
||||
@@ -64,15 +69,7 @@
|
||||
* //a working example can be found at the bottom of this page
|
||||
* //
|
||||
* .my-element.ng-hide-add, .my-element.ng-hide-remove {
|
||||
* /* this is required as of 1.3x to properly
|
||||
* apply all styling in a show/hide animation */
|
||||
* transition:0s linear all;
|
||||
* }
|
||||
*
|
||||
* .my-element.ng-hide-add-active,
|
||||
* .my-element.ng-hide-remove-active {
|
||||
* /* the transition is defined in the active class */
|
||||
* transition:1s linear all;
|
||||
* transition:0.5s linear all;
|
||||
* }
|
||||
*
|
||||
* .my-element.ng-hide-add { ... }
|
||||
@@ -81,7 +78,7 @@
|
||||
* .my-element.ng-hide-remove.ng-hide-remove-active { ... }
|
||||
* ```
|
||||
*
|
||||
* Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
|
||||
* Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
|
||||
* property to block during animation states--ngAnimate will handle the style toggling automatically for you.
|
||||
*
|
||||
* @animations
|
||||
@@ -114,6 +111,8 @@
|
||||
</file>
|
||||
<file name="animations.css">
|
||||
.animate-show {
|
||||
-webkit-transition:all linear 0.5s;
|
||||
transition:all linear 0.5s;
|
||||
line-height:20px;
|
||||
opacity:1;
|
||||
padding:10px;
|
||||
@@ -121,12 +120,6 @@
|
||||
background:white;
|
||||
}
|
||||
|
||||
.animate-show.ng-hide-add.ng-hide-add-active,
|
||||
.animate-show.ng-hide-remove.ng-hide-remove-active {
|
||||
-webkit-transition:all linear 0.5s;
|
||||
transition:all linear 0.5s;
|
||||
}
|
||||
|
||||
.animate-show.ng-hide {
|
||||
line-height:0;
|
||||
opacity:0;
|
||||
@@ -156,14 +149,10 @@
|
||||
</example>
|
||||
*/
|
||||
var ngShowDirective = ['$animate', function($animate) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
multiElement: true,
|
||||
link: function(scope, element, attr) {
|
||||
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
|
||||
$animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide');
|
||||
});
|
||||
}
|
||||
return function(scope, element, attr) {
|
||||
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
|
||||
$animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
|
||||
});
|
||||
};
|
||||
}];
|
||||
|
||||
@@ -187,10 +176,15 @@ var ngShowDirective = ['$animate', function($animate) {
|
||||
* <div ng-hide="myValue"></div>
|
||||
* ```
|
||||
*
|
||||
* When the ngHide expression evaluates to a truthy value then the .ng-hide CSS class is added to the class
|
||||
* attribute on the element causing it to become hidden. When falsy, the ng-hide CSS class is removed
|
||||
* When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
|
||||
* on the element causing it to become hidden. When false, the ng-hide CSS class is removed
|
||||
* from the element causing the element not to appear hidden.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
|
||||
* "f" / "0" / "false" / "no" / "n" / "[]"
|
||||
* </div>
|
||||
*
|
||||
* ## Why is !important used?
|
||||
*
|
||||
* You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
|
||||
@@ -210,7 +204,7 @@ var ngShowDirective = ['$animate', function($animate) {
|
||||
*
|
||||
* ```css
|
||||
* .ng-hide {
|
||||
* /* this is just another form of hiding an element */
|
||||
* //this is just another form of hiding an element
|
||||
* display:block!important;
|
||||
* position:absolute;
|
||||
* top:-9999px;
|
||||
@@ -240,7 +234,7 @@ var ngShowDirective = ['$animate', function($animate) {
|
||||
* .my-element.ng-hide-remove.ng-hide-remove-active { ... }
|
||||
* ```
|
||||
*
|
||||
* Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
|
||||
* Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
|
||||
* property to block during animation states--ngAnimate will handle the style toggling automatically for you.
|
||||
*
|
||||
* @animations
|
||||
@@ -311,13 +305,9 @@ var ngShowDirective = ['$animate', function($animate) {
|
||||
</example>
|
||||
*/
|
||||
var ngHideDirective = ['$animate', function($animate) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
multiElement: true,
|
||||
link: function(scope, element, attr) {
|
||||
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
|
||||
$animate[value ? 'addClass' : 'removeClass'](element, 'ng-hide');
|
||||
});
|
||||
}
|
||||
return function(scope, element, attr) {
|
||||
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
|
||||
$animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
|
||||
});
|
||||
};
|
||||
}];
|
||||
|
||||
@@ -152,7 +152,7 @@ var ngSwitchDirective = ['$animate', function($animate) {
|
||||
previousElements.length = 0;
|
||||
|
||||
for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
|
||||
var selected = getBlockElements(selectedElements[i].clone);
|
||||
var selected = selectedElements[i];
|
||||
selectedScopes[i].$destroy();
|
||||
previousElements[i] = selected;
|
||||
$animate.leave(selected, function() {
|
||||
@@ -166,13 +166,12 @@ var ngSwitchDirective = ['$animate', function($animate) {
|
||||
if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
|
||||
scope.$eval(attr.change);
|
||||
forEach(selectedTranscludes, function(selectedTransclude) {
|
||||
selectedTransclude.transclude(function(caseElement, selectedScope) {
|
||||
selectedScopes.push(selectedScope);
|
||||
var selectedScope = scope.$new();
|
||||
selectedScopes.push(selectedScope);
|
||||
selectedTransclude.transclude(selectedScope, function(caseElement) {
|
||||
var anchor = selectedTransclude.element;
|
||||
caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
|
||||
var block = { clone: caseElement };
|
||||
|
||||
selectedElements.push(block);
|
||||
selectedElements.push(caseElement);
|
||||
$animate.enter(caseElement, anchor.parent(), anchor);
|
||||
});
|
||||
});
|
||||
@@ -184,9 +183,8 @@ var ngSwitchDirective = ['$animate', function($animate) {
|
||||
|
||||
var ngSwitchWhenDirective = ngDirective({
|
||||
transclude: 'element',
|
||||
priority: 1200,
|
||||
priority: 800,
|
||||
require: '^ngSwitch',
|
||||
multiElement: true,
|
||||
link: function(scope, element, attrs, ctrl, $transclude) {
|
||||
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
|
||||
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
|
||||
@@ -195,9 +193,8 @@ var ngSwitchWhenDirective = ngDirective({
|
||||
|
||||
var ngSwitchDefaultDirective = ngDirective({
|
||||
transclude: 'element',
|
||||
priority: 1200,
|
||||
priority: 800,
|
||||
require: '^ngSwitch',
|
||||
multiElement: true,
|
||||
link: function(scope, element, attr, ctrl, $transclude) {
|
||||
ctrl.cases['?'] = (ctrl.cases['?'] || []);
|
||||
ctrl.cases['?'].push({ transclude: $transclude, element: element });
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngTransclude
|
||||
* @restrict EAC
|
||||
* @restrict AC
|
||||
*
|
||||
* @description
|
||||
* Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
|
||||
@@ -24,7 +24,7 @@
|
||||
scope: { title:'@' },
|
||||
template: '<div style="border: 1px solid black;">' +
|
||||
'<div style="background-color: gray">{{title}}</div>' +
|
||||
'<ng-transclude></ng-transclude>' +
|
||||
'<div ng-transclude></div>' +
|
||||
'</div>'
|
||||
};
|
||||
})
|
||||
@@ -55,7 +55,6 @@
|
||||
*
|
||||
*/
|
||||
var ngTranscludeDirective = ngDirective({
|
||||
restrict: 'EAC',
|
||||
link: function($scope, $element, $attrs, controller, $transclude) {
|
||||
if (!$transclude) {
|
||||
throw minErr('ngTransclude')('orphan',
|
||||
|
||||
@@ -135,11 +135,7 @@ var ngOptionsMinErr = minErr('ngOptions');
|
||||
</example>
|
||||
*/
|
||||
|
||||
var ngOptionsDirective = valueFn({
|
||||
restrict: 'A',
|
||||
terminal: true
|
||||
});
|
||||
|
||||
var ngOptionsDirective = valueFn({ terminal: true });
|
||||
// jshint maxlen: false
|
||||
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
//000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
|
||||
@@ -168,7 +164,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
};
|
||||
|
||||
|
||||
self.addOption = function(value, element) {
|
||||
self.addOption = function(value) {
|
||||
assertNotHasOwnProperty(value, '"option value"');
|
||||
optionsMap[value] = true;
|
||||
|
||||
@@ -176,12 +172,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
$element.val(value);
|
||||
if (unknownOption.parent()) unknownOption.remove();
|
||||
}
|
||||
// Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
|
||||
// Adding an <option selected="selected"> element to a <select required="required"> should
|
||||
// automatically select the new element
|
||||
if (element[0].hasAttribute('selected')) {
|
||||
element[0].selected = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -644,13 +634,11 @@ var optionDirective = ['$interpolate', function($interpolate) {
|
||||
if (interpolateFn) {
|
||||
scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
|
||||
attr.$set('value', newVal);
|
||||
if (oldVal !== newVal) {
|
||||
selectCtrl.removeOption(oldVal);
|
||||
}
|
||||
selectCtrl.addOption(newVal, element);
|
||||
if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
|
||||
selectCtrl.addOption(newVal);
|
||||
});
|
||||
} else {
|
||||
selectCtrl.addOption(attr.value, element);
|
||||
selectCtrl.addOption(attr.value);
|
||||
}
|
||||
|
||||
element.on('$destroy', function() {
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
var styleDirective = valueFn({
|
||||
restrict: 'E',
|
||||
terminal: false
|
||||
terminal: true
|
||||
});
|
||||
|
||||
@@ -241,32 +241,6 @@ function timeZoneGetter(date) {
|
||||
return paddedZone;
|
||||
}
|
||||
|
||||
function getFirstThursdayOfYear(year) {
|
||||
// 0 = index of January
|
||||
var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
|
||||
// 4 = index of Thursday (+1 to account for 1st = 5)
|
||||
// 11 = index of *next* Thursday (+1 account for 1st = 12)
|
||||
return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
|
||||
}
|
||||
|
||||
function getThursdayThisWeek(datetime) {
|
||||
return new Date(datetime.getFullYear(), datetime.getMonth(),
|
||||
// 4 = index of Thursday
|
||||
datetime.getDate() + (4 - datetime.getDay()));
|
||||
}
|
||||
|
||||
function weekGetter(size) {
|
||||
return function(date) {
|
||||
var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
|
||||
thisThurs = getThursdayThisWeek(date);
|
||||
|
||||
var diff = +thisThurs - +firstThurs,
|
||||
result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
|
||||
|
||||
return padNumber(result, size);
|
||||
};
|
||||
}
|
||||
|
||||
function ampmGetter(date, formats) {
|
||||
return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
|
||||
}
|
||||
@@ -295,12 +269,10 @@ var DATE_FORMATS = {
|
||||
EEEE: dateStrGetter('Day'),
|
||||
EEE: dateStrGetter('Day', true),
|
||||
a: ampmGetter,
|
||||
Z: timeZoneGetter,
|
||||
ww: weekGetter(2),
|
||||
w: weekGetter(1)
|
||||
Z: timeZoneGetter
|
||||
};
|
||||
|
||||
var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/,
|
||||
var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
|
||||
NUMBER_STRING = /^\-?\d+$/;
|
||||
|
||||
/**
|
||||
@@ -335,8 +307,6 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d
|
||||
* * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
|
||||
* * `'a'`: am/pm marker
|
||||
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
|
||||
* * `'ww'`: ISO-8601 week of year (00-53)
|
||||
* * `'w'`: ISO-8601 week of year (0-53)
|
||||
*
|
||||
* `format` string can also be one of the following predefined
|
||||
* {@link guide/i18n localizable formats}:
|
||||
@@ -344,7 +314,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d
|
||||
* * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
|
||||
* (e.g. Sep 3, 2010 12:05:08 pm)
|
||||
* * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm)
|
||||
* * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US locale
|
||||
* * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale
|
||||
* (e.g. Friday, September 3, 2010)
|
||||
* * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010)
|
||||
* * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)
|
||||
|
||||
@@ -145,7 +145,7 @@ function orderByFilter($parse){
|
||||
return 0;
|
||||
}
|
||||
function reverseComparator(comp, descending) {
|
||||
return descending
|
||||
return toBoolean(descending)
|
||||
? function(a,b){return comp(b,a);}
|
||||
: comp;
|
||||
}
|
||||
|
||||
+73
-14
@@ -149,6 +149,12 @@ function $HttpProvider() {
|
||||
*/
|
||||
var interceptorFactories = this.interceptors = [];
|
||||
|
||||
/**
|
||||
* For historical reasons, response interceptors are ordered by the order in which
|
||||
* they are applied to the response. (This is the opposite of interceptorFactories)
|
||||
*/
|
||||
var responseInterceptorFactories = this.responseInterceptors = [];
|
||||
|
||||
this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
|
||||
function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
|
||||
|
||||
@@ -166,6 +172,27 @@ function $HttpProvider() {
|
||||
? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
|
||||
});
|
||||
|
||||
forEach(responseInterceptorFactories, function(interceptorFactory, index) {
|
||||
var responseFn = isString(interceptorFactory)
|
||||
? $injector.get(interceptorFactory)
|
||||
: $injector.invoke(interceptorFactory);
|
||||
|
||||
/**
|
||||
* Response interceptors go before "around" interceptors (no real reason, just
|
||||
* had to pick one.) But they are already reversed, so we can't use unshift, hence
|
||||
* the splice.
|
||||
*/
|
||||
reversedInterceptors.splice(index, 0, {
|
||||
response: function(response) {
|
||||
return responseFn($q.when(response));
|
||||
},
|
||||
responseError: function(response) {
|
||||
return responseFn($q.reject(response));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @kind function
|
||||
@@ -419,6 +446,51 @@ function $HttpProvider() {
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* # Response interceptors (DEPRECATED)
|
||||
*
|
||||
* Before you start creating interceptors, be sure to understand the
|
||||
* {@link ng.$q $q and deferred/promise APIs}.
|
||||
*
|
||||
* For purposes of global error handling, authentication or any kind of synchronous or
|
||||
* asynchronous preprocessing of received responses, it is desirable to be able to intercept
|
||||
* responses for http requests before they are handed over to the application code that
|
||||
* initiated these requests. The response interceptors leverage the {@link ng.$q
|
||||
* promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
|
||||
*
|
||||
* The interceptors are service factories that are registered with the $httpProvider by
|
||||
* adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
|
||||
* injected with dependencies (if specified) and returns the interceptor — a function that
|
||||
* takes a {@link ng.$q promise} and returns the original or a new promise.
|
||||
*
|
||||
* ```js
|
||||
* // register the interceptor as a service
|
||||
* $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
|
||||
* return function(promise) {
|
||||
* return promise.then(function(response) {
|
||||
* // do something on success
|
||||
* return response;
|
||||
* }, function(response) {
|
||||
* // do something on error
|
||||
* if (canRecover(response)) {
|
||||
* return responseOrNewPromise
|
||||
* }
|
||||
* return $q.reject(response);
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* $httpProvider.responseInterceptors.push('myHttpInterceptor');
|
||||
*
|
||||
*
|
||||
* // register the interceptor via an anonymous factory
|
||||
* $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
|
||||
* return function(promise) {
|
||||
* // same as above
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* # Security Considerations
|
||||
*
|
||||
* When designing web applications, consider security threats from:
|
||||
@@ -814,20 +886,7 @@ function $HttpProvider() {
|
||||
* @param {Object=} config Optional configuration object
|
||||
* @returns {HttpPromise} Future object
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $http#patch
|
||||
*
|
||||
* @description
|
||||
* Shortcut method to perform `PATCH` request.
|
||||
*
|
||||
* @param {string} url Relative or absolute URL specifying the destination of the request
|
||||
* @param {*} data Request content
|
||||
* @param {Object=} config Optional configuration object
|
||||
* @returns {HttpPromise} Future object
|
||||
*/
|
||||
createShortMethodsWithData('post', 'put', 'patch');
|
||||
createShortMethodsWithData('post', 'put');
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
|
||||
@@ -196,6 +196,18 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
||||
|
||||
addEventListenerFn(script, "load", callback);
|
||||
addEventListenerFn(script, "error", callback);
|
||||
|
||||
if (msie <= 8) {
|
||||
script.onreadystatechange = function() {
|
||||
if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) {
|
||||
script.onreadystatechange = null;
|
||||
callback({
|
||||
type: 'load'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
rawDocument.body.appendChild(script);
|
||||
return callback;
|
||||
}
|
||||
|
||||
+62
-173
@@ -81,13 +81,7 @@ function $InterpolateProvider() {
|
||||
|
||||
this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
|
||||
var startSymbolLength = startSymbol.length,
|
||||
endSymbolLength = endSymbol.length,
|
||||
escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
|
||||
escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
|
||||
|
||||
function escape(ch) {
|
||||
return '\\\\\\' + ch;
|
||||
}
|
||||
endSymbolLength = endSymbol.length;
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
@@ -111,62 +105,6 @@ function $InterpolateProvider() {
|
||||
* expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
|
||||
* ```
|
||||
*
|
||||
* `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
|
||||
* `true`, the interpolation function will return `undefined` unless all embedded expressions
|
||||
* evaluate to a value other than `undefined`.
|
||||
*
|
||||
* ```js
|
||||
* var $interpolate = ...; // injected
|
||||
* var context = {greeting: 'Hello', name: undefined };
|
||||
*
|
||||
* // default "forgiving" mode
|
||||
* var exp = $interpolate('{{greeting}} {{name}}!');
|
||||
* expect(exp(context)).toEqual('Hello !');
|
||||
*
|
||||
* // "allOrNothing" mode
|
||||
* exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
|
||||
* expect(exp(context)).toBeUndefined();
|
||||
* context.name = 'Angular';
|
||||
* expect(exp(context)).toEqual('Hello Angular!');
|
||||
* ```
|
||||
*
|
||||
* `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
|
||||
*
|
||||
* ####Escaped Interpolation
|
||||
* $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
|
||||
* can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
|
||||
* It will be rendered as a regular start/end marker, and will not be interpreted as an expression
|
||||
* or binding.
|
||||
*
|
||||
* This enables web-servers to prevent script injection attacks and defacing attacks, to some
|
||||
* degree, while also enabling code examples to work without relying on the
|
||||
* {@link ng.directive:ngNonBindable ngNonBindable} directive.
|
||||
*
|
||||
* **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
|
||||
* replacing angle brackets (<, >) with &lt; and &gt; respectively, and replacing all
|
||||
* interpolation start/end markers with their escaped counterparts.**
|
||||
*
|
||||
* Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
|
||||
* output when the $interpolate service processes the text. So, for HTML elements interpolated
|
||||
* by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
|
||||
* set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
|
||||
* this is typically useful only when user-data is used in rendering a template from the server, or
|
||||
* when otherwise untrusted data is used by a directive.
|
||||
*
|
||||
* <example>
|
||||
* <file name="index.html">
|
||||
* <div ng-init="username='A user'">
|
||||
* <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
|
||||
* </p>
|
||||
* <p><strong>{{username}}</strong> attempts to inject code which will deface the
|
||||
* application, but fails to accomplish their task, because the server has correctly
|
||||
* escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
|
||||
* characters.</p>
|
||||
* <p>Instead, the result of the attempted script injection is visible, and can be removed
|
||||
* from the database by an administrator.</p>
|
||||
* </div>
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* @param {string} text The text with markup to interpolate.
|
||||
* @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
|
||||
@@ -176,55 +114,43 @@ function $InterpolateProvider() {
|
||||
* result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
|
||||
* trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that
|
||||
* provides Strict Contextual Escaping for details.
|
||||
* @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
|
||||
* unless all embedded expressions evaluate to a value other than `undefined`.
|
||||
* @returns {function(context)} an interpolation function which is used to compute the
|
||||
* interpolated string. The function has these parameters:
|
||||
*
|
||||
* - `context`: evaluation context for all expressions embedded in the interpolated text
|
||||
* * `context`: an object against which any expressions embedded in the strings are evaluated
|
||||
* against.
|
||||
*
|
||||
*/
|
||||
function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
|
||||
allOrNothing = !!allOrNothing;
|
||||
function $interpolate(text, mustHaveExpression, trustedContext) {
|
||||
var startIndex,
|
||||
endIndex,
|
||||
index = 0,
|
||||
separators = [],
|
||||
expressions = [],
|
||||
parseFns = [],
|
||||
textLength = text.length,
|
||||
parts = [],
|
||||
length = text.length,
|
||||
hasInterpolation = false,
|
||||
hasText = false,
|
||||
fn,
|
||||
exp,
|
||||
concat = [];
|
||||
|
||||
while(index < textLength) {
|
||||
while(index < length) {
|
||||
if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
|
||||
((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
|
||||
if (index !== startIndex) hasText = true;
|
||||
separators.push(text.substring(index, startIndex));
|
||||
exp = text.substring(startIndex + startSymbolLength, endIndex);
|
||||
expressions.push(exp);
|
||||
parseFns.push($parse(exp, parseStringifyInterceptor));
|
||||
(index != startIndex) && parts.push(text.substring(index, startIndex));
|
||||
parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
|
||||
fn.exp = exp;
|
||||
index = endIndex + endSymbolLength;
|
||||
hasInterpolation = true;
|
||||
} else {
|
||||
// we did not find an interpolation, so we have to add the remainder to the separators array
|
||||
if (index !== textLength) {
|
||||
hasText = true;
|
||||
separators.push(text.substring(index));
|
||||
}
|
||||
break;
|
||||
// we did not find anything, so we have to add the remainder to the parts array
|
||||
(index != length) && parts.push(text.substring(index));
|
||||
index = length;
|
||||
}
|
||||
}
|
||||
|
||||
forEach(separators, function(key, i) {
|
||||
separators[i] = separators[i].
|
||||
replace(escapedStartRegexp, startSymbol).
|
||||
replace(escapedEndRegexp, endSymbol);
|
||||
});
|
||||
|
||||
if (separators.length === expressions.length) {
|
||||
separators.push('');
|
||||
if (!(length = parts.length)) {
|
||||
// we added, nothing, must have been an empty string.
|
||||
parts.push('');
|
||||
length = 1;
|
||||
}
|
||||
|
||||
// Concatenating expressions makes it hard to reason about whether some combination of
|
||||
@@ -233,95 +159,58 @@ function $InterpolateProvider() {
|
||||
// that's used is assigned or constructed by some JS code somewhere that is more testable or
|
||||
// make it obvious that you bound the value to some user controlled value. This helps reduce
|
||||
// the load when auditing for XSS issues.
|
||||
if (trustedContext && hasInterpolation && (hasText || expressions.length > 1)) {
|
||||
if (trustedContext && parts.length > 1) {
|
||||
throw $interpolateMinErr('noconcat',
|
||||
"Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
|
||||
"interpolations that concatenate multiple expressions when a trusted value is " +
|
||||
"required. See http://docs.angularjs.org/api/ng.$sce", text);
|
||||
}
|
||||
|
||||
if (!mustHaveExpression || hasInterpolation) {
|
||||
concat.length = separators.length + expressions.length;
|
||||
|
||||
var compute = function(values) {
|
||||
for(var i = 0, ii = expressions.length; i < ii; i++) {
|
||||
if (allOrNothing && isUndefined(values[i])) return;
|
||||
concat[2*i] = separators[i];
|
||||
concat[(2*i)+1] = values[i];
|
||||
}
|
||||
concat[2*ii] = separators[ii];
|
||||
return concat.join('');
|
||||
};
|
||||
|
||||
var getValue = function (value) {
|
||||
return trustedContext ?
|
||||
$sce.getTrusted(trustedContext, value) :
|
||||
$sce.valueOf(value);
|
||||
};
|
||||
|
||||
var stringify = function (value) {
|
||||
if (value == null) { // null || undefined
|
||||
return '';
|
||||
}
|
||||
switch (typeof value) {
|
||||
case 'string': {
|
||||
break;
|
||||
}
|
||||
case 'number': {
|
||||
value = '' + value;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
value = toJson(value);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
return extend(function interpolationFn(context) {
|
||||
var i = 0;
|
||||
var ii = expressions.length;
|
||||
var values = new Array(ii);
|
||||
|
||||
try {
|
||||
for (; i < ii; i++) {
|
||||
values[i] = parseFns[i](context);
|
||||
if (!mustHaveExpression || hasInterpolation) {
|
||||
concat.length = length;
|
||||
fn = function(context) {
|
||||
try {
|
||||
for(var i = 0, ii = length, part; i<ii; i++) {
|
||||
if (typeof (part = parts[i]) == 'function') {
|
||||
part = part(context);
|
||||
if (trustedContext) {
|
||||
part = $sce.getTrusted(trustedContext, part);
|
||||
} else {
|
||||
part = $sce.valueOf(part);
|
||||
}
|
||||
if (part == null) { // null || undefined
|
||||
part = '';
|
||||
} else {
|
||||
switch (typeof part) {
|
||||
case 'string':
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 'number':
|
||||
{
|
||||
part = '' + part;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
part = toJson(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return compute(values);
|
||||
} catch(err) {
|
||||
var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
|
||||
err.toString());
|
||||
$exceptionHandler(newErr);
|
||||
concat[i] = part;
|
||||
}
|
||||
|
||||
}, {
|
||||
// all of these properties are undocumented for now
|
||||
exp: text, //just for compatibility with regular watchers created via $watch
|
||||
separators: separators,
|
||||
expressions: expressions,
|
||||
$$watchDelegate: function (scope, listener, objectEquality, deregisterNotifier) {
|
||||
var lastValue;
|
||||
return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
|
||||
var currValue = compute(values);
|
||||
if (isFunction(listener)) {
|
||||
listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
|
||||
}
|
||||
lastValue = currValue;
|
||||
}, objectEquality, deregisterNotifier);
|
||||
return concat.join('');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseStringifyInterceptor(value) {
|
||||
try {
|
||||
return stringify(getValue(value));
|
||||
} catch(err) {
|
||||
var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
|
||||
err.toString());
|
||||
$exceptionHandler(newErr);
|
||||
}
|
||||
catch(err) {
|
||||
var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
|
||||
err.toString());
|
||||
$exceptionHandler(newErr);
|
||||
}
|
||||
};
|
||||
fn.exp = text;
|
||||
fn.parts = parts;
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -2,8 +2,8 @@
|
||||
|
||||
|
||||
function $IntervalProvider() {
|
||||
this.$get = ['$rootScope', '$window', '$q', '$$q',
|
||||
function($rootScope, $window, $q, $$q) {
|
||||
this.$get = ['$rootScope', '$window', '$q',
|
||||
function($rootScope, $window, $q) {
|
||||
var intervals = {};
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ function $IntervalProvider() {
|
||||
*
|
||||
* // listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
* // to prevent updating time after the DOM element was removed.
|
||||
* element.on('$destroy', function() {
|
||||
* element.bind('$destroy', function() {
|
||||
* $interval.cancel(stopTime);
|
||||
* });
|
||||
* }
|
||||
@@ -134,10 +134,10 @@ function $IntervalProvider() {
|
||||
function interval(fn, delay, count, invokeApply) {
|
||||
var setInterval = $window.setInterval,
|
||||
clearInterval = $window.clearInterval,
|
||||
deferred = $q.defer(),
|
||||
promise = deferred.promise,
|
||||
iteration = 0,
|
||||
skipApply = (isDefined(invokeApply) && !invokeApply),
|
||||
deferred = (skipApply ? $$q : $q).defer(),
|
||||
promise = deferred.promise;
|
||||
skipApply = (isDefined(invokeApply) && !invokeApply);
|
||||
|
||||
count = isDefined(count) ? count : 0;
|
||||
|
||||
|
||||
+1
-1
@@ -646,7 +646,7 @@ function $LocationProvider(){
|
||||
var elm = jqLite(event.target);
|
||||
|
||||
// traverse the DOM up to find first A tag
|
||||
while (nodeName_(elm[0]) !== 'a') {
|
||||
while (lowercase(elm[0].nodeName) !== 'a') {
|
||||
// ignore rewriting if no A tag (reached root element, or no parent - removed from document)
|
||||
if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
|
||||
}
|
||||
|
||||
+279
-147
@@ -1,6 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var $parseMinErr = minErr('$parse');
|
||||
var promiseWarningCache = {};
|
||||
var promiseWarning;
|
||||
|
||||
// Sandboxing Angular Expressions
|
||||
// ------------------------------
|
||||
@@ -43,7 +45,7 @@ function ensureSafeObject(obj, fullExpression) {
|
||||
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (// isWindow(obj)
|
||||
obj.window === obj) {
|
||||
obj.document && obj.location && obj.alert && obj.setInterval) {
|
||||
throw $parseMinErr('isecwindow',
|
||||
'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
@@ -72,7 +74,7 @@ function ensureSafeFunction(obj, fullExpression) {
|
||||
throw $parseMinErr('isecfn',
|
||||
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (obj === CALL || obj === APPLY || obj === BIND) {
|
||||
} else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) {
|
||||
throw $parseMinErr('isecff',
|
||||
'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
@@ -138,8 +140,11 @@ Lexer.prototype = {
|
||||
|
||||
lex: function (text) {
|
||||
this.text = text;
|
||||
|
||||
this.index = 0;
|
||||
this.ch = undefined;
|
||||
this.lastCh = ':'; // can start regexp
|
||||
|
||||
this.tokens = [];
|
||||
|
||||
while (this.index < this.text.length) {
|
||||
@@ -158,6 +163,7 @@ Lexer.prototype = {
|
||||
this.index++;
|
||||
} else if (this.isWhitespace(this.ch)) {
|
||||
this.index++;
|
||||
continue;
|
||||
} else {
|
||||
var ch2 = this.ch + this.peek();
|
||||
var ch3 = ch2 + this.peek(2);
|
||||
@@ -181,6 +187,7 @@ Lexer.prototype = {
|
||||
this.throwError('Unexpected next character ', this.index, this.index + 1);
|
||||
}
|
||||
}
|
||||
this.lastCh = this.ch;
|
||||
}
|
||||
return this.tokens;
|
||||
},
|
||||
@@ -189,6 +196,10 @@ Lexer.prototype = {
|
||||
return chars.indexOf(this.ch) !== -1;
|
||||
},
|
||||
|
||||
was: function(chars) {
|
||||
return chars.indexOf(this.lastCh) !== -1;
|
||||
},
|
||||
|
||||
peek: function(i) {
|
||||
var num = i || 1;
|
||||
return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
|
||||
@@ -252,6 +263,7 @@ Lexer.prototype = {
|
||||
this.tokens.push({
|
||||
index: start,
|
||||
text: number,
|
||||
literal: true,
|
||||
constant: true,
|
||||
fn: function() { return number; }
|
||||
});
|
||||
@@ -304,6 +316,7 @@ Lexer.prototype = {
|
||||
// OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
|
||||
if (OPERATORS.hasOwnProperty(ident)) {
|
||||
token.fn = OPERATORS[ident];
|
||||
token.literal = true;
|
||||
token.constant = true;
|
||||
} else {
|
||||
var getter = getterFn(ident, this.options, this.text);
|
||||
@@ -311,7 +324,7 @@ Lexer.prototype = {
|
||||
return (getter(self, locals));
|
||||
}, {
|
||||
assign: function(self, value) {
|
||||
return setter(self, ident, value, parser.text);
|
||||
return setter(self, ident, value, parser.text, parser.options);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -320,7 +333,7 @@ Lexer.prototype = {
|
||||
|
||||
if (methodName) {
|
||||
this.tokens.push({
|
||||
index: lastDot,
|
||||
index:lastDot,
|
||||
text: '.'
|
||||
});
|
||||
this.tokens.push({
|
||||
@@ -359,6 +372,7 @@ Lexer.prototype = {
|
||||
index: start,
|
||||
text: rawString,
|
||||
string: string,
|
||||
literal: true,
|
||||
constant: true,
|
||||
fn: function() { return string; }
|
||||
});
|
||||
@@ -393,6 +407,7 @@ Parser.prototype = {
|
||||
|
||||
parse: function (text) {
|
||||
this.text = text;
|
||||
|
||||
this.tokens = this.lexer.lex(text);
|
||||
|
||||
var value = this.statements();
|
||||
@@ -422,10 +437,8 @@ Parser.prototype = {
|
||||
if (!primary) {
|
||||
this.throwError('not a primary expression', token);
|
||||
}
|
||||
if (token.constant) {
|
||||
primary.constant = true;
|
||||
primary.literal = true;
|
||||
}
|
||||
primary.literal = !!token.literal;
|
||||
primary.constant = !!token.constant;
|
||||
}
|
||||
|
||||
var next, context;
|
||||
@@ -549,17 +562,21 @@ Parser.prototype = {
|
||||
var token = this.expect();
|
||||
var fn = this.$filter(token.text);
|
||||
var argsFn = [];
|
||||
while(this.expect(':')) {
|
||||
argsFn.push(this.expression());
|
||||
}
|
||||
return valueFn(fnInvoke);
|
||||
|
||||
function fnInvoke(self, locals, input) {
|
||||
var args = [input];
|
||||
for (var i = 0; i < argsFn.length; i++) {
|
||||
args.push(argsFn[i](self, locals));
|
||||
while (true) {
|
||||
if ((token = this.expect(':'))) {
|
||||
argsFn.push(this.expression());
|
||||
} else {
|
||||
var fnInvoke = function(self, locals, input) {
|
||||
var args = [input];
|
||||
for (var i = 0; i < argsFn.length; i++) {
|
||||
args.push(argsFn[i](self, locals));
|
||||
}
|
||||
return fn.apply(self, args);
|
||||
};
|
||||
return function() {
|
||||
return fnInvoke;
|
||||
};
|
||||
}
|
||||
return fn.apply(self, args);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -681,7 +698,7 @@ Parser.prototype = {
|
||||
assign: function(scope, value, locals) {
|
||||
var o = object(scope, locals);
|
||||
if (!o) object.assign(scope, o = {});
|
||||
return setter(o, field, value, parser.text);
|
||||
return setter(o, field, value, parser.text, parser.options);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -695,11 +712,19 @@ Parser.prototype = {
|
||||
return extend(function(self, locals) {
|
||||
var o = obj(self, locals),
|
||||
i = indexFn(self, locals),
|
||||
v;
|
||||
v, p;
|
||||
|
||||
ensureSafeMemberName(i, parser.text);
|
||||
if (!o) return undefined;
|
||||
v = ensureSafeObject(o[i], parser.text);
|
||||
if (v && v.then && parser.options.unwrapPromises) {
|
||||
p = v;
|
||||
if (!('$$v' in v)) {
|
||||
p.$$v = undefined;
|
||||
p.then(function(val) { p.$$v = val; });
|
||||
}
|
||||
v = v.$$v;
|
||||
}
|
||||
return v;
|
||||
}, {
|
||||
assign: function(self, value, locals) {
|
||||
@@ -815,7 +840,9 @@ Parser.prototype = {
|
||||
// Parser helper functions
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
function setter(obj, path, setValue, fullExp) {
|
||||
function setter(obj, path, setValue, fullExp, options) {
|
||||
//needed?
|
||||
options = options || {};
|
||||
|
||||
var element = path.split('.'), key;
|
||||
for (var i = 0; element.length > 1; i++) {
|
||||
@@ -826,6 +853,18 @@ function setter(obj, path, setValue, fullExp) {
|
||||
obj[key] = propertyObj;
|
||||
}
|
||||
obj = propertyObj;
|
||||
if (obj.then && options.unwrapPromises) {
|
||||
promiseWarning(fullExp);
|
||||
if (!("$$v" in obj)) {
|
||||
(function(promise) {
|
||||
promise.then(function(val) { promise.$$v = val; }); }
|
||||
)(obj);
|
||||
}
|
||||
if (obj.$$v === undefined) {
|
||||
obj.$$v = {};
|
||||
}
|
||||
obj = obj.$$v;
|
||||
}
|
||||
}
|
||||
key = ensureSafeMemberName(element.shift(), fullExp);
|
||||
ensureSafeObject(obj, fullExp);
|
||||
@@ -841,37 +880,108 @@ var getterFnCache = {};
|
||||
* - http://jsperf.com/angularjs-parse-getter/4
|
||||
* - http://jsperf.com/path-evaluation-simplified/7
|
||||
*/
|
||||
function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp) {
|
||||
function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
ensureSafeMemberName(key0, fullExp);
|
||||
ensureSafeMemberName(key1, fullExp);
|
||||
ensureSafeMemberName(key2, fullExp);
|
||||
ensureSafeMemberName(key3, fullExp);
|
||||
ensureSafeMemberName(key4, fullExp);
|
||||
|
||||
return function cspSafeGetter(scope, locals) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
|
||||
return !options.unwrapPromises
|
||||
? function cspSafeGetter(scope, locals) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
|
||||
|
||||
if (pathVal == null) return pathVal;
|
||||
pathVal = pathVal[key0];
|
||||
if (pathVal == null) return pathVal;
|
||||
pathVal = pathVal[key0];
|
||||
|
||||
if (!key1) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key1];
|
||||
if (!key1) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key1];
|
||||
|
||||
if (!key2) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key2];
|
||||
if (!key2) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key2];
|
||||
|
||||
if (!key3) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key3];
|
||||
if (!key3) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key3];
|
||||
|
||||
if (!key4) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key4];
|
||||
if (!key4) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key4];
|
||||
|
||||
return pathVal;
|
||||
};
|
||||
return pathVal;
|
||||
}
|
||||
: function cspSafePromiseEnabledGetter(scope, locals) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
|
||||
promise;
|
||||
|
||||
if (pathVal == null) return pathVal;
|
||||
|
||||
pathVal = pathVal[key0];
|
||||
if (pathVal && pathVal.then) {
|
||||
promiseWarning(fullExp);
|
||||
if (!("$$v" in pathVal)) {
|
||||
promise = pathVal;
|
||||
promise.$$v = undefined;
|
||||
promise.then(function(val) { promise.$$v = val; });
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
|
||||
if (!key1) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key1];
|
||||
if (pathVal && pathVal.then) {
|
||||
promiseWarning(fullExp);
|
||||
if (!("$$v" in pathVal)) {
|
||||
promise = pathVal;
|
||||
promise.$$v = undefined;
|
||||
promise.then(function(val) { promise.$$v = val; });
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
|
||||
if (!key2) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key2];
|
||||
if (pathVal && pathVal.then) {
|
||||
promiseWarning(fullExp);
|
||||
if (!("$$v" in pathVal)) {
|
||||
promise = pathVal;
|
||||
promise.$$v = undefined;
|
||||
promise.then(function(val) { promise.$$v = val; });
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
|
||||
if (!key3) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key3];
|
||||
if (pathVal && pathVal.then) {
|
||||
promiseWarning(fullExp);
|
||||
if (!("$$v" in pathVal)) {
|
||||
promise = pathVal;
|
||||
promise.$$v = undefined;
|
||||
promise.then(function(val) { promise.$$v = val; });
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
|
||||
if (!key4) return pathVal;
|
||||
if (pathVal == null) return undefined;
|
||||
pathVal = pathVal[key4];
|
||||
if (pathVal && pathVal.then) {
|
||||
promiseWarning(fullExp);
|
||||
if (!("$$v" in pathVal)) {
|
||||
promise = pathVal;
|
||||
promise.$$v = undefined;
|
||||
promise.then(function(val) { promise.$$v = val; });
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
return pathVal;
|
||||
};
|
||||
}
|
||||
|
||||
function getterFn(path, options, fullExp) {
|
||||
@@ -889,13 +999,14 @@ function getterFn(path, options, fullExp) {
|
||||
// http://jsperf.com/angularjs-parse-getter/6
|
||||
if (options.csp) {
|
||||
if (pathKeysLength < 6) {
|
||||
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp);
|
||||
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
|
||||
options);
|
||||
} else {
|
||||
fn = function(scope, locals) {
|
||||
var i = 0, val;
|
||||
do {
|
||||
val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
|
||||
pathKeys[i++], fullExp)(scope, locals);
|
||||
pathKeys[i++], fullExp, options)(scope, locals);
|
||||
|
||||
locals = undefined; // clear after first iteration
|
||||
scope = val;
|
||||
@@ -912,15 +1023,28 @@ function getterFn(path, options, fullExp) {
|
||||
// we simply dereference 's' on any .dot notation
|
||||
? 's'
|
||||
// but if we are first then we check locals first, and if so read it first
|
||||
: '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '.' + key + ';\n';
|
||||
: '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
|
||||
(options.unwrapPromises
|
||||
? 'if (s && s.then) {\n' +
|
||||
' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
|
||||
' if (!("$$v" in s)) {\n' +
|
||||
' p=s;\n' +
|
||||
' p.$$v = undefined;\n' +
|
||||
' p.then(function(v) {p.$$v=v;});\n' +
|
||||
'}\n' +
|
||||
' s=s.$$v\n' +
|
||||
'}\n'
|
||||
: '');
|
||||
});
|
||||
code += 'return s;';
|
||||
|
||||
/* jshint -W054 */
|
||||
var evaledFnGetter = new Function('s', 'k', code); // s=scope, k=locals
|
||||
var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
|
||||
/* jshint +W054 */
|
||||
evaledFnGetter.toString = valueFn(code);
|
||||
fn = evaledFnGetter;
|
||||
fn = options.unwrapPromises ? function(scope, locals) {
|
||||
return evaledFnGetter(scope, locals, promiseWarning);
|
||||
} : evaledFnGetter;
|
||||
}
|
||||
|
||||
// Only cache the value if it's not going to mess up the cache object
|
||||
@@ -987,123 +1111,131 @@ function $ParseProvider() {
|
||||
var cache = {};
|
||||
|
||||
var $parseOptions = {
|
||||
csp: false
|
||||
csp: false,
|
||||
unwrapPromises: false,
|
||||
logPromiseWarnings: true
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
|
||||
/**
|
||||
* @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
|
||||
*
|
||||
* @ngdoc method
|
||||
* @name $parseProvider#unwrapPromises
|
||||
* @description
|
||||
*
|
||||
* **This feature is deprecated, see deprecation notes below for more info**
|
||||
*
|
||||
* If set to true (default is false), $parse will unwrap promises automatically when a promise is
|
||||
* found at any part of the expression. In other words, if set to true, the expression will always
|
||||
* result in a non-promise value.
|
||||
*
|
||||
* While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
|
||||
* the fulfillment value is used in place of the promise while evaluating the expression.
|
||||
*
|
||||
* **Deprecation notice**
|
||||
*
|
||||
* This is a feature that didn't prove to be wildly useful or popular, primarily because of the
|
||||
* dichotomy between data access in templates (accessed as raw values) and controller code
|
||||
* (accessed as promises).
|
||||
*
|
||||
* In most code we ended up resolving promises manually in controllers anyway and thus unifying
|
||||
* the model access there.
|
||||
*
|
||||
* Other downsides of automatic promise unwrapping:
|
||||
*
|
||||
* - when building components it's often desirable to receive the raw promises
|
||||
* - adds complexity and slows down expression evaluation
|
||||
* - makes expression code pre-generation unattractive due to the amount of code that needs to be
|
||||
* generated
|
||||
* - makes IDE auto-completion and tool support hard
|
||||
*
|
||||
* **Warning Logs**
|
||||
*
|
||||
* If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
|
||||
* promise (to reduce the noise, each expression is logged only once). To disable this logging use
|
||||
* `$parseProvider.logPromiseWarnings(false)` api.
|
||||
*
|
||||
*
|
||||
* @param {boolean=} value New value.
|
||||
* @returns {boolean|self} Returns the current setting when used as getter and self if used as
|
||||
* setter.
|
||||
*/
|
||||
this.unwrapPromises = function(value) {
|
||||
if (isDefined(value)) {
|
||||
$parseOptions.unwrapPromises = !!value;
|
||||
return this;
|
||||
} else {
|
||||
return $parseOptions.unwrapPromises;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
|
||||
*
|
||||
* @ngdoc method
|
||||
* @name $parseProvider#logPromiseWarnings
|
||||
* @description
|
||||
*
|
||||
* Controls whether Angular should log a warning on any encounter of a promise in an expression.
|
||||
*
|
||||
* The default is set to `true`.
|
||||
*
|
||||
* This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
|
||||
*
|
||||
* @param {boolean=} value New value.
|
||||
* @returns {boolean|self} Returns the current setting when used as getter and self if used as
|
||||
* setter.
|
||||
*/
|
||||
this.logPromiseWarnings = function(value) {
|
||||
if (isDefined(value)) {
|
||||
$parseOptions.logPromiseWarnings = value;
|
||||
return this;
|
||||
} else {
|
||||
return $parseOptions.logPromiseWarnings;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
|
||||
$parseOptions.csp = $sniffer.csp;
|
||||
|
||||
return function(exp, interceptorFn) {
|
||||
var parsedExpression, oneTime,
|
||||
cacheKey = (exp = trim(exp));
|
||||
promiseWarning = function promiseWarningFn(fullExp) {
|
||||
if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
|
||||
promiseWarningCache[fullExp] = true;
|
||||
$log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
|
||||
'Automatic unwrapping of promises in Angular expressions is deprecated.');
|
||||
};
|
||||
|
||||
return function(exp) {
|
||||
var parsedExpression;
|
||||
|
||||
switch (typeof exp) {
|
||||
case 'string':
|
||||
if (cache.hasOwnProperty(cacheKey)) {
|
||||
parsedExpression = cache[cacheKey];
|
||||
} else {
|
||||
if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
|
||||
oneTime = true;
|
||||
exp = exp.substring(2);
|
||||
}
|
||||
|
||||
var lexer = new Lexer($parseOptions);
|
||||
var parser = new Parser(lexer, $filter, $parseOptions);
|
||||
parsedExpression = parser.parse(exp);
|
||||
|
||||
if (parsedExpression.constant) {
|
||||
parsedExpression.$$watchDelegate = constantWatch;
|
||||
} else if (oneTime) {
|
||||
parsedExpression.$$watchDelegate = parsedExpression.literal ?
|
||||
oneTimeLiteralWatch : oneTimeWatch;
|
||||
}
|
||||
|
||||
if (cacheKey !== 'hasOwnProperty') {
|
||||
// Only cache the value if it's not going to mess up the cache object
|
||||
// This is more performant that using Object.prototype.hasOwnProperty.call
|
||||
cache[cacheKey] = parsedExpression;
|
||||
}
|
||||
if (cache.hasOwnProperty(exp)) {
|
||||
return cache[exp];
|
||||
}
|
||||
return addInterceptor(parsedExpression, interceptorFn);
|
||||
|
||||
var lexer = new Lexer($parseOptions);
|
||||
var parser = new Parser(lexer, $filter, $parseOptions);
|
||||
parsedExpression = parser.parse(exp);
|
||||
|
||||
if (exp !== 'hasOwnProperty') {
|
||||
// Only cache the value if it's not going to mess up the cache object
|
||||
// This is more performant that using Object.prototype.hasOwnProperty.call
|
||||
cache[exp] = parsedExpression;
|
||||
}
|
||||
|
||||
return parsedExpression;
|
||||
|
||||
case 'function':
|
||||
return addInterceptor(exp, interceptorFn);
|
||||
return exp;
|
||||
|
||||
default:
|
||||
return addInterceptor(noop, interceptorFn);
|
||||
return noop;
|
||||
}
|
||||
};
|
||||
|
||||
function oneTimeWatch(scope, listener, objectEquality, deregisterNotifier, parsedExpression) {
|
||||
var unwatch, lastValue;
|
||||
return unwatch = scope.$watch(function oneTimeWatch(scope) {
|
||||
return parsedExpression(scope);
|
||||
}, function oneTimeListener(value, old, scope) {
|
||||
lastValue = value;
|
||||
if (isFunction(listener)) {
|
||||
listener.apply(this, arguments);
|
||||
}
|
||||
if (isDefined(value)) {
|
||||
scope.$$postDigest(function () {
|
||||
if (isDefined(lastValue)) {
|
||||
unwatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, objectEquality, deregisterNotifier);
|
||||
}
|
||||
|
||||
function oneTimeLiteralWatch(scope, listener, objectEquality, deregisterNotifier, parsedExpression) {
|
||||
var unwatch;
|
||||
return unwatch = scope.$watch(function oneTimeWatch(scope) {
|
||||
return parsedExpression(scope);
|
||||
}, function oneTimeListener(value, old, scope) {
|
||||
if (isFunction(listener)) {
|
||||
listener.call(this, value, old, scope);
|
||||
}
|
||||
if (isAllDefined(value)) {
|
||||
scope.$$postDigest(function () {
|
||||
if(isAllDefined(value)) unwatch();
|
||||
});
|
||||
}
|
||||
}, objectEquality);
|
||||
|
||||
function isAllDefined(value) {
|
||||
var allDefined = true;
|
||||
forEach(value, function (val) {
|
||||
if (!isDefined(val)) allDefined = false;
|
||||
});
|
||||
return allDefined;
|
||||
}
|
||||
}
|
||||
|
||||
function constantWatch(scope, listener, objectEquality, deregisterNotifier, parsedExpression) {
|
||||
var unwatch;
|
||||
return unwatch = scope.$watch(function constantWatch(scope) {
|
||||
return parsedExpression(scope);
|
||||
}, function constantListener(value, old, scope) {
|
||||
if (isFunction(listener)) {
|
||||
listener.apply(this, arguments);
|
||||
}
|
||||
unwatch();
|
||||
}, objectEquality, deregisterNotifier);
|
||||
}
|
||||
|
||||
function addInterceptor(parsedExpression, interceptorFn) {
|
||||
if (isFunction(interceptorFn)) {
|
||||
var fn = function interceptedExpression(scope, locals) {
|
||||
var value = parsedExpression(scope, locals);
|
||||
var result = interceptorFn(value, scope, locals);
|
||||
// we only return the interceptor's result if the
|
||||
// initial value is defined (for bind-once)
|
||||
return isDefined(value) ? result : value;
|
||||
};
|
||||
fn.$$watchDelegate = parsedExpression.$$watchDelegate;
|
||||
return fn;
|
||||
} else {
|
||||
return parsedExpression;
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+126
-211
@@ -8,46 +8,6 @@
|
||||
* @description
|
||||
* A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
|
||||
*
|
||||
* $q can be used in two fashions --- One, which is more similar to Kris Kowal's Q or jQuery's Deferred
|
||||
* implementations, the other resembles ES6 promises to some degree.
|
||||
*
|
||||
* # $q constructor
|
||||
*
|
||||
* The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
|
||||
* function as the first argument). This is similar to the native Promise implementation from ES6 Harmony,
|
||||
* see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
|
||||
*
|
||||
* While the constructor-style use is supported, not all of the supporting methods from Harmony promises are
|
||||
* available yet.
|
||||
*
|
||||
* It can be used like so:
|
||||
*
|
||||
* ```js
|
||||
* return $q(function(resolve, reject) {
|
||||
* // perform some asynchronous operation, resolve or reject the promise when appropriate.
|
||||
* setInterval(function() {
|
||||
* if (pollStatus > 0) {
|
||||
* resolve(polledValue);
|
||||
* } else if (pollStatus < 0) {
|
||||
* reject(polledValue);
|
||||
* } else {
|
||||
* pollStatus = pollAgain(function(value) {
|
||||
* polledValue = value;
|
||||
* });
|
||||
* }
|
||||
* }, 10000);
|
||||
* }).
|
||||
* then(function(value) {
|
||||
* // handle success
|
||||
* }, function(reason) {
|
||||
* // handle failure
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Note, progress/notify callbacks are not currently supported via the ES6-style interface.
|
||||
*
|
||||
* However, the more traditional CommonJS style usage is still available, and documented below.
|
||||
*
|
||||
* [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
|
||||
* interface for interacting with an object that represents the result of an action that is
|
||||
* performed asynchronously, and may or may not be finished at any given point in time.
|
||||
@@ -94,6 +54,7 @@
|
||||
* For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
|
||||
* section on serial or parallel joining of promises.
|
||||
*
|
||||
*
|
||||
* # The Deferred API
|
||||
*
|
||||
* A new instance of deferred is constructed by calling `$q.defer()`.
|
||||
@@ -202,12 +163,6 @@
|
||||
* expect(resolvedValue).toEqual(123);
|
||||
* }));
|
||||
* ```
|
||||
*
|
||||
* @param {function(function, function)} resolver Function which is responsible for resolving or
|
||||
* rejecting the newly created promise. The first parameteter is a function which resolves the
|
||||
* promise, the second parameter is a function which rejects the promise.
|
||||
*
|
||||
* @returns {Promise} The newly created promise.
|
||||
*/
|
||||
function $QProvider() {
|
||||
|
||||
@@ -218,13 +173,6 @@ function $QProvider() {
|
||||
}];
|
||||
}
|
||||
|
||||
function $$QProvider() {
|
||||
this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
|
||||
return qFactory(function(callback) {
|
||||
$browser.defer(callback);
|
||||
}, $exceptionHandler);
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a promise manager.
|
||||
@@ -247,122 +195,143 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
* @returns {Deferred} Returns a new instance of deferred.
|
||||
*/
|
||||
var defer = function() {
|
||||
return new Deferred();
|
||||
};
|
||||
var pending = [],
|
||||
value, deferred;
|
||||
|
||||
function Promise () {
|
||||
this.$$pending = [];
|
||||
}
|
||||
deferred = {
|
||||
|
||||
Promise.prototype = {
|
||||
then: function(callback, errback, progressback) {
|
||||
var result = new Deferred();
|
||||
resolve: function(val) {
|
||||
if (pending) {
|
||||
var callbacks = pending;
|
||||
pending = undefined;
|
||||
value = ref(val);
|
||||
|
||||
var wrappedCallback = function(value) {
|
||||
try {
|
||||
result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
|
||||
} catch(e) {
|
||||
result.reject(e);
|
||||
exceptionHandler(e);
|
||||
if (callbacks.length) {
|
||||
nextTick(function() {
|
||||
var callback;
|
||||
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
||||
callback = callbacks[i];
|
||||
value.then(callback[0], callback[1], callback[2]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
var wrappedErrback = function(reason) {
|
||||
try {
|
||||
result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
|
||||
} catch(e) {
|
||||
result.reject(e);
|
||||
exceptionHandler(e);
|
||||
|
||||
reject: function(reason) {
|
||||
deferred.resolve(createInternalRejectedPromise(reason));
|
||||
},
|
||||
|
||||
|
||||
notify: function(progress) {
|
||||
if (pending) {
|
||||
var callbacks = pending;
|
||||
|
||||
if (pending.length) {
|
||||
nextTick(function() {
|
||||
var callback;
|
||||
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
||||
callback = callbacks[i];
|
||||
callback[2](progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
var wrappedProgressback = function(progress) {
|
||||
try {
|
||||
result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
|
||||
} catch(e) {
|
||||
exceptionHandler(e);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.$$pending) {
|
||||
this.$$pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
|
||||
} else {
|
||||
this.$$value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
|
||||
}
|
||||
promise: {
|
||||
then: function(callback, errback, progressback) {
|
||||
var result = defer();
|
||||
|
||||
return result.promise;
|
||||
},
|
||||
|
||||
"catch": function(callback) {
|
||||
return this.then(null, callback);
|
||||
},
|
||||
"finally": function(callback) {
|
||||
return this.then(function(value) {
|
||||
return handleCallback(value, true, callback);
|
||||
}, function(error) {
|
||||
return handleCallback(error, false, callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
|
||||
function simpleBind(context, fn) {
|
||||
return function(value) {
|
||||
fn.call(context, value);
|
||||
};
|
||||
}
|
||||
|
||||
function Deferred () {
|
||||
this.promise = new Promise();
|
||||
//Necessary to support unbound execution :/
|
||||
this.resolve = simpleBind(this, this.resolve);
|
||||
this.reject = simpleBind(this, this.reject);
|
||||
this.notify = simpleBind(this, this.notify);
|
||||
}
|
||||
|
||||
Deferred.prototype = {
|
||||
resolve: function(val) {
|
||||
if (this.promise.$$pending) {
|
||||
var callbacks = this.promise.$$pending;
|
||||
this.promise.$$pending = undefined;
|
||||
this.promise.$$value = ref(val);
|
||||
|
||||
if (callbacks.length) {
|
||||
nextTick(simpleBind(this, function() {
|
||||
var callback;
|
||||
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
||||
callback = callbacks[i];
|
||||
this.promise.$$value.then(callback[0], callback[1], callback[2]);
|
||||
var wrappedCallback = function(value) {
|
||||
try {
|
||||
result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
|
||||
} catch(e) {
|
||||
result.reject(e);
|
||||
exceptionHandler(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
},
|
||||
reject: function(reason) {
|
||||
this.resolve(createInternalRejectedPromise(reason));
|
||||
},
|
||||
notify: function(progress) {
|
||||
if (this.promise.$$pending) {
|
||||
var callbacks = this.promise.$$pending;
|
||||
};
|
||||
|
||||
if (this.promise.$$pending.length) {
|
||||
nextTick(function() {
|
||||
var callback;
|
||||
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
||||
callback = callbacks[i];
|
||||
callback[2](progress);
|
||||
var wrappedErrback = function(reason) {
|
||||
try {
|
||||
result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
|
||||
} catch(e) {
|
||||
result.reject(e);
|
||||
exceptionHandler(e);
|
||||
}
|
||||
};
|
||||
|
||||
var wrappedProgressback = function(progress) {
|
||||
try {
|
||||
result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
|
||||
} catch(e) {
|
||||
exceptionHandler(e);
|
||||
}
|
||||
};
|
||||
|
||||
if (pending) {
|
||||
pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
|
||||
} else {
|
||||
value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
|
||||
}
|
||||
|
||||
return result.promise;
|
||||
},
|
||||
|
||||
"catch": function(callback) {
|
||||
return this.then(null, callback);
|
||||
},
|
||||
|
||||
"finally": function(callback) {
|
||||
|
||||
function makePromise(value, resolved) {
|
||||
var result = defer();
|
||||
if (resolved) {
|
||||
result.resolve(value);
|
||||
} else {
|
||||
result.reject(value);
|
||||
}
|
||||
return result.promise;
|
||||
}
|
||||
|
||||
function handleCallback(value, isResolved) {
|
||||
var callbackOutput = null;
|
||||
try {
|
||||
callbackOutput = (callback ||defaultCallback)();
|
||||
} catch(e) {
|
||||
return makePromise(e, false);
|
||||
}
|
||||
if (isPromiseLike(callbackOutput)) {
|
||||
return callbackOutput.then(function() {
|
||||
return makePromise(value, isResolved);
|
||||
}, function(error) {
|
||||
return makePromise(error, false);
|
||||
});
|
||||
} else {
|
||||
return makePromise(value, isResolved);
|
||||
}
|
||||
}
|
||||
|
||||
return this.then(function(value) {
|
||||
return handleCallback(value, true);
|
||||
}, function(error) {
|
||||
return handleCallback(error, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
|
||||
var ref = function(value) {
|
||||
if (isPromiseLike(value)) return value;
|
||||
return {
|
||||
then: function(callback) {
|
||||
var result = new Deferred();
|
||||
var result = defer();
|
||||
nextTick(function() {
|
||||
result.resolve(callback(value));
|
||||
});
|
||||
@@ -409,43 +378,15 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
* @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
|
||||
*/
|
||||
var reject = function(reason) {
|
||||
var result = new Deferred();
|
||||
var result = defer();
|
||||
result.reject(reason);
|
||||
return result.promise;
|
||||
};
|
||||
|
||||
var makePromise = function makePromise(value, resolved) {
|
||||
var result = new Deferred();
|
||||
if (resolved) {
|
||||
result.resolve(value);
|
||||
} else {
|
||||
result.reject(value);
|
||||
}
|
||||
return result.promise;
|
||||
};
|
||||
|
||||
var handleCallback = function handleCallback(value, isResolved, callback) {
|
||||
var callbackOutput = null;
|
||||
try {
|
||||
callbackOutput = (callback ||defaultCallback)();
|
||||
} catch(e) {
|
||||
return makePromise(e, false);
|
||||
}
|
||||
if (isPromiseLike(callbackOutput)) {
|
||||
return callbackOutput.then(function() {
|
||||
return makePromise(value, isResolved);
|
||||
}, function(error) {
|
||||
return makePromise(error, false);
|
||||
});
|
||||
} else {
|
||||
return makePromise(value, isResolved);
|
||||
}
|
||||
};
|
||||
|
||||
var createInternalRejectedPromise = function(reason) {
|
||||
return {
|
||||
then: function(callback, errback) {
|
||||
var result = new Deferred();
|
||||
var result = defer();
|
||||
nextTick(function() {
|
||||
try {
|
||||
result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
|
||||
@@ -474,7 +415,7 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
* @returns {Promise} Returns a promise of the passed value or promise
|
||||
*/
|
||||
var when = function(value, callback, errback, progressback) {
|
||||
var result = new Deferred(),
|
||||
var result = defer(),
|
||||
done;
|
||||
|
||||
var wrappedCallback = function(value) {
|
||||
@@ -548,7 +489,7 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
* with the same rejection value.
|
||||
*/
|
||||
function all(promises) {
|
||||
var deferred = new Deferred(),
|
||||
var deferred = defer(),
|
||||
counter = 0,
|
||||
results = isArray(promises) ? [] : {};
|
||||
|
||||
@@ -571,36 +512,10 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
var $Q = function Q(resolver) {
|
||||
if (!isFunction(resolver)) {
|
||||
// TODO(@caitp): minErr this
|
||||
throw new TypeError('Expected resolverFn');
|
||||
}
|
||||
|
||||
if (!(this instanceof Q)) {
|
||||
// More useful when $Q is the Promise itself.
|
||||
return new Q(resolver);
|
||||
}
|
||||
|
||||
var deferred = new Deferred();
|
||||
|
||||
function resolveFn(value) {
|
||||
deferred.resolve(value);
|
||||
}
|
||||
|
||||
function rejectFn(reason) {
|
||||
deferred.reject(reason);
|
||||
}
|
||||
|
||||
resolver(resolveFn, rejectFn);
|
||||
|
||||
return deferred.promise;
|
||||
return {
|
||||
defer: defer,
|
||||
reject: reject,
|
||||
when: when,
|
||||
all: all
|
||||
};
|
||||
|
||||
$Q.defer = defer;
|
||||
$Q.reject = reject;
|
||||
$Q.when = when;
|
||||
$Q.all = all;
|
||||
|
||||
return $Q;
|
||||
}
|
||||
|
||||
+31
-105
@@ -248,6 +248,7 @@ function $RootScopeProvider(){
|
||||
* can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
|
||||
* listener was called due to initialization.
|
||||
*
|
||||
* The example below contains an illustration of using a function as your $watch listener
|
||||
*
|
||||
*
|
||||
* # Example
|
||||
@@ -277,14 +278,14 @@ function $RootScopeProvider(){
|
||||
|
||||
|
||||
|
||||
// Using a function as a watchExpression
|
||||
// Using a listener function
|
||||
var food;
|
||||
scope.foodCounter = 0;
|
||||
expect(scope.foodCounter).toEqual(0);
|
||||
scope.$watch(
|
||||
// This function returns the value being watched. It is called for each turn of the $digest loop
|
||||
// This is the listener function
|
||||
function() { return food; },
|
||||
// This is the change listener, called when the value returned from the above function changes
|
||||
// This is the change handler
|
||||
function(newValue, oldValue) {
|
||||
if ( newValue !== oldValue ) {
|
||||
// Only increment the counter if the value changed
|
||||
@@ -314,25 +315,20 @@ function $RootScopeProvider(){
|
||||
*
|
||||
* - `string`: Evaluated as {@link guide/expression expression}
|
||||
* - `function(scope)`: called with current `scope` as a parameter.
|
||||
* @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
|
||||
* of `watchExpression` changes.
|
||||
* @param {(function()|string)=} listener Callback called whenever the return value of
|
||||
* the `watchExpression` changes.
|
||||
*
|
||||
* - `string`: Evaluated as {@link guide/expression expression}
|
||||
* - `function(newValue, oldValue, scope)`: called with current and previous values as
|
||||
* parameters.
|
||||
*
|
||||
* - `newVal` contains the current value of the `watchExpression`
|
||||
* - `oldVal` contains the previous value of the `watchExpression`
|
||||
* - `scope` refers to the current scope
|
||||
* @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
|
||||
* comparing for reference equality.
|
||||
* @param {function()=} deregisterNotifier Function to call when the deregistration function
|
||||
* get called.
|
||||
* @returns {function()} Returns a deregistration function for this listener.
|
||||
*/
|
||||
$watch: function(watchExp, listener, objectEquality, deregisterNotifier) {
|
||||
var get = compileToFn(watchExp, 'watch');
|
||||
|
||||
if (get.$$watchDelegate) {
|
||||
return get.$$watchDelegate(this, listener, objectEquality, deregisterNotifier, get);
|
||||
}
|
||||
$watch: function(watchExp, listener, objectEquality) {
|
||||
var scope = this,
|
||||
get = compileToFn(watchExp, 'watch'),
|
||||
array = scope.$$watchers,
|
||||
watcher = {
|
||||
fn: listener,
|
||||
@@ -344,8 +340,18 @@ function $RootScopeProvider(){
|
||||
|
||||
lastDirtyWatch = null;
|
||||
|
||||
// in the case user pass string, we need to compile it, do we really need this ?
|
||||
if (!isFunction(listener)) {
|
||||
watcher.fn = noop;
|
||||
var listenFn = compileToFn(listener || noop, 'listener');
|
||||
watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
|
||||
}
|
||||
|
||||
if (typeof watchExp == 'string' && get.constant) {
|
||||
var originalFn = watcher.fn;
|
||||
watcher.fn = function(newVal, oldVal, scope) {
|
||||
originalFn.call(this, newVal, oldVal, scope);
|
||||
arrayRemove(array, watcher);
|
||||
};
|
||||
}
|
||||
|
||||
if (!array) {
|
||||
@@ -358,79 +364,6 @@ function $RootScopeProvider(){
|
||||
return function deregisterWatch() {
|
||||
arrayRemove(array, watcher);
|
||||
lastDirtyWatch = null;
|
||||
if (isFunction(deregisterNotifier)) {
|
||||
deregisterNotifier();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $rootScope.Scope#$watchGroup
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
|
||||
* If any one expression in the collection changes the `listener` is executed.
|
||||
*
|
||||
* - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
|
||||
* call to $digest() to see if any items changes.
|
||||
* - The `listener` is called whenever any expression in the `watchExpressions` array changes.
|
||||
*
|
||||
* @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
|
||||
* watched using {@link ng.$rootScope.Scope#$watch $watch()}
|
||||
*
|
||||
* @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
|
||||
* expression in `watchExpressions` changes
|
||||
* The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
|
||||
* those of `watchExpression`
|
||||
* and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
|
||||
* those of `watchExpression`
|
||||
* The `scope` refers to the current scope.
|
||||
* @returns {function()} Returns a de-registration function for all listeners.
|
||||
*/
|
||||
$watchGroup: function(watchExpressions, listener) {
|
||||
var oldValues = new Array(watchExpressions.length);
|
||||
var newValues = new Array(watchExpressions.length);
|
||||
var deregisterFns = [];
|
||||
var changeCount = 0;
|
||||
var self = this;
|
||||
var masterUnwatch;
|
||||
|
||||
if (watchExpressions.length === 1) {
|
||||
// Special case size of one
|
||||
return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
|
||||
newValues[0] = value;
|
||||
oldValues[0] = oldValue;
|
||||
listener.call(this, newValues, (value === oldValue) ? newValues : oldValues, scope);
|
||||
});
|
||||
}
|
||||
|
||||
forEach(watchExpressions, function (expr, i) {
|
||||
var unwatch = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
|
||||
newValues[i] = value;
|
||||
oldValues[i] = oldValue;
|
||||
changeCount++;
|
||||
}, false, function watchGroupDeregNotifier() {
|
||||
arrayRemove(deregisterFns, unwatch);
|
||||
if (!deregisterFns.length) {
|
||||
masterUnwatch();
|
||||
}
|
||||
});
|
||||
|
||||
deregisterFns.push(unwatch);
|
||||
}, this);
|
||||
|
||||
masterUnwatch = self.$watch(function watchGroupChangeWatch() {
|
||||
return changeCount;
|
||||
}, function watchGroupChangeAction(value, oldValue) {
|
||||
listener(newValues, (value === oldValue) ? newValues : oldValues, self);
|
||||
});
|
||||
|
||||
return function deregisterWatchGroup() {
|
||||
while (deregisterFns.length) {
|
||||
deregisterFns[0]();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@@ -502,14 +435,14 @@ function $RootScopeProvider(){
|
||||
// only track veryOldValue if the listener is asking for it
|
||||
var trackVeryOldValue = (listener.length > 1);
|
||||
var changeDetected = 0;
|
||||
var changeDetector = $parse(obj, $watchCollectionInterceptor);
|
||||
var objGetter = $parse(obj);
|
||||
var internalArray = [];
|
||||
var internalObject = {};
|
||||
var initRun = true;
|
||||
var oldLength = 0;
|
||||
|
||||
function $watchCollectionInterceptor(_value) {
|
||||
newValue = _value;
|
||||
function $watchCollectionWatch() {
|
||||
newValue = objGetter(self);
|
||||
var newLength, key, bothNaN;
|
||||
|
||||
if (!isObject(newValue)) { // if primitive
|
||||
@@ -610,7 +543,7 @@ function $RootScopeProvider(){
|
||||
}
|
||||
}
|
||||
|
||||
return this.$watch(changeDetector, $watchCollectionAction);
|
||||
return this.$watch($watchCollectionWatch, $watchCollectionAction);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -630,7 +563,7 @@ function $RootScopeProvider(){
|
||||
* {@link ng.directive:ngController controllers} or in
|
||||
* {@link ng.$compileProvider#directive directives}.
|
||||
* Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
|
||||
* a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
|
||||
* a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
|
||||
*
|
||||
* If you want to be notified whenever `$digest()` is called,
|
||||
* you can register a `watchExpression` function with
|
||||
@@ -842,7 +775,7 @@ function $RootScopeProvider(){
|
||||
|
||||
// prevent NPEs since these methods have references to properties we nulled out
|
||||
this.$destroy = this.$digest = this.$apply = noop;
|
||||
this.$on = this.$watch = this.$watchGroup = function() { return noop; };
|
||||
this.$on = this.$watch = function() { return noop; };
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1000,8 +933,7 @@ function $RootScopeProvider(){
|
||||
*
|
||||
* - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
|
||||
* `$broadcast`-ed.
|
||||
* - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
|
||||
* event propagates through the scope hierarchy, this property is set to null.
|
||||
* - `currentScope` - `{Scope}`: the current scope which is handling the event.
|
||||
* - `name` - `{string}`: name of the event.
|
||||
* - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
|
||||
* further event propagation (available only for events that were `$emit`-ed).
|
||||
@@ -1095,16 +1027,11 @@ function $RootScopeProvider(){
|
||||
}
|
||||
}
|
||||
//if any listener on the current scope stops propagation, prevent bubbling
|
||||
if (stopPropagation) {
|
||||
event.currentScope = null;
|
||||
return event;
|
||||
}
|
||||
if (stopPropagation) return event;
|
||||
//traverse upwards
|
||||
scope = scope.$parent;
|
||||
} while (scope);
|
||||
|
||||
event.currentScope = null;
|
||||
|
||||
return event;
|
||||
},
|
||||
|
||||
@@ -1177,7 +1104,6 @@ function $RootScopeProvider(){
|
||||
}
|
||||
}
|
||||
|
||||
event.currentScope = null;
|
||||
return event;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
function $$SanitizeUriProvider() {
|
||||
var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
|
||||
imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file|blob):|data:image\//;
|
||||
imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
|
||||
|
||||
/**
|
||||
* @description
|
||||
|
||||
+16
-16
@@ -494,7 +494,7 @@ function $SceDelegateProvider() {
|
||||
* won't work on all browsers. Also, loading templates from `file://` URL does not work on some
|
||||
* browsers.
|
||||
*
|
||||
* ## This feels like too much overhead
|
||||
* ## This feels like too much overhead for the developer?
|
||||
*
|
||||
* It's important to remember that SCE only applies to interpolation expressions.
|
||||
*
|
||||
@@ -578,7 +578,7 @@ function $SceDelegateProvider() {
|
||||
*
|
||||
* <example module="mySceApp" deps="angular-sanitize.js">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="AppController as myCtrl">
|
||||
* <div ng-controller="myAppController as myCtrl">
|
||||
* <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
|
||||
* <b>User comments</b><br>
|
||||
* By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
|
||||
@@ -595,17 +595,17 @@ function $SceDelegateProvider() {
|
||||
* </file>
|
||||
*
|
||||
* <file name="script.js">
|
||||
* angular.module('mySceApp', ['ngSanitize'])
|
||||
* .controller('AppController', ['$http', '$templateCache', '$sce',
|
||||
* function($http, $templateCache, $sce) {
|
||||
* var self = this;
|
||||
* $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
|
||||
* self.userComments = userComments;
|
||||
* });
|
||||
* self.explicitlyTrustedHtml = $sce.trustAsHtml(
|
||||
* '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
|
||||
* 'sanitization."">Hover over this text.</span>');
|
||||
* }]);
|
||||
* var mySceApp = angular.module('mySceApp', ['ngSanitize']);
|
||||
*
|
||||
* mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
|
||||
* var self = this;
|
||||
* $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
|
||||
* self.userComments = userComments;
|
||||
* });
|
||||
* self.explicitlyTrustedHtml = $sce.trustAsHtml(
|
||||
* '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
|
||||
* 'sanitization."">Hover over this text.</span>');
|
||||
* });
|
||||
* </file>
|
||||
*
|
||||
* <file name="test_data.json">
|
||||
@@ -787,9 +787,9 @@ function $SceProvider() {
|
||||
if (parsed.literal && parsed.constant) {
|
||||
return parsed;
|
||||
} else {
|
||||
return $parse(expr, function (value) {
|
||||
return sce.getTrusted(type, value);
|
||||
});
|
||||
return function sceParseAsTrusted(self, locals) {
|
||||
return sce.getTrusted(type, parsed(self, locals));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+4
-4
@@ -2,8 +2,8 @@
|
||||
|
||||
|
||||
function $TimeoutProvider() {
|
||||
this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
|
||||
function($rootScope, $browser, $q, $$q, $exceptionHandler) {
|
||||
this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
|
||||
function($rootScope, $browser, $q, $exceptionHandler) {
|
||||
var deferreds = {};
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ function $TimeoutProvider() {
|
||||
*
|
||||
*/
|
||||
function timeout(fn, delay, invokeApply) {
|
||||
var skipApply = (isDefined(invokeApply) && !invokeApply),
|
||||
deferred = (skipApply ? $$q : $q).defer(),
|
||||
var deferred = $q.defer(),
|
||||
promise = deferred.promise,
|
||||
skipApply = (isDefined(invokeApply) && !invokeApply),
|
||||
timeoutId;
|
||||
|
||||
timeoutId = $browser.defer(function() {
|
||||
|
||||
+238
-278
@@ -6,8 +6,11 @@
|
||||
* @name ngAnimate
|
||||
* @description
|
||||
*
|
||||
* # ngAnimate
|
||||
*
|
||||
* The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
|
||||
*
|
||||
*
|
||||
* <div doc-module-components="ngAnimate"></div>
|
||||
*
|
||||
* # Usage
|
||||
@@ -19,18 +22,17 @@
|
||||
*
|
||||
* Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
|
||||
*
|
||||
* | Directive | Supported Animations |
|
||||
* |-----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
|
||||
* | {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move |
|
||||
* | {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
|
||||
* | {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
|
||||
* | {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
|
||||
* | {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
|
||||
* | {@link ng.directive:ngClass#usage_animations ngClass} | add and remove (the CSS class(es) present) |
|
||||
* | {@link ng.directive:ngShow#usage_animations ngShow} & {@link ng.directive:ngHide#usage_animations ngHide} | add and remove (the ng-hide class value) |
|
||||
* | {@link ng.directive:form#usage_animations form} & {@link ng.directive:ngModel#usage_animations ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
|
||||
* | {@link ngMessages.directive:ngMessage#usage_animations ngMessages} | add and remove (ng-active & ng-inactive) |
|
||||
* | {@link ngMessages.directive:ngMessage#usage_animations ngMessage} | enter and leave |
|
||||
* | Directive | Supported Animations |
|
||||
* |---------------------------------------------------------- |----------------------------------------------------|
|
||||
* | {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move |
|
||||
* | {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
|
||||
* | {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
|
||||
* | {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
|
||||
* | {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
|
||||
* | {@link ng.directive:ngClass#usage_animations ngClass} | add and remove |
|
||||
* | {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
|
||||
* | {@link ng.directive:form#usage_animations form} | add and remove (dirty, pristine, valid, invalid & all other validations) |
|
||||
* | {@link ng.directive:ngModel#usage_animations ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
|
||||
*
|
||||
* You can find out more information about animations upon visiting each directive page.
|
||||
*
|
||||
@@ -142,74 +144,7 @@
|
||||
* immediately resulting in a DOM element that is at its final state. This final state is when the DOM element
|
||||
* has no CSS transition/animation classes applied to it.
|
||||
*
|
||||
* ### Structural transition animations
|
||||
*
|
||||
* Structural transitions (such as enter, leave and move) will always apply a `0s none` transition
|
||||
* value to force the browser into rendering the styles defined in the setup (.ng-enter, .ng-leave
|
||||
* or .ng-move) class. This means that any active transition animations operating on the element
|
||||
* will be cut off to make way for the enter, leave or move animation.
|
||||
*
|
||||
* ### Class-based transition animations
|
||||
*
|
||||
* Class-based transitions refer to transition animations that are triggered when a CSS class is
|
||||
* added to or removed from the element (via `$animate.addClass`, `$animate.removeClass`,
|
||||
* `$animate.setClass`, or by directives such as `ngClass`, `ngModel` and `form`).
|
||||
* They are different when compared to structural animations since they **do not cancel existing
|
||||
* animations** nor do they **block successive transitions** from rendering on the same element.
|
||||
* This distinction allows for **multiple class-based transitions** to be performed on the same element.
|
||||
*
|
||||
* In addition to ngAnimate supporting the default (natural) functionality of class-based transition
|
||||
* animations, ngAnimate also decorates the element with starting and ending CSS classes to aid the
|
||||
* developer in further styling the element throughout the transition animation. Earlier versions
|
||||
* of ngAnimate may have caused natural CSS transitions to break and not render properly due to
|
||||
* $animate temporarily blocking transitions using `0s none` in order to allow the setup CSS class
|
||||
* (the `-add` or `-remove` class) to be applied without triggering an animation. However, as of
|
||||
* **version 1.3**, this workaround has been removed with ngAnimate and all non-ngAnimate CSS
|
||||
* class transitions are compatible with ngAnimate.
|
||||
*
|
||||
* There is, however, one special case when dealing with class-based transitions in ngAnimate.
|
||||
* When rendering class-based transitions that make use of the setup and active CSS classes
|
||||
* (e.g. `.fade-add` and `.fade-add-active` for when `.fade` is added) be sure to define
|
||||
* the transition value **on the active CSS class** and not the setup class.
|
||||
*
|
||||
* ```css
|
||||
* .fade-add {
|
||||
* /* remember to place a 0s transition here
|
||||
* to ensure that the styles are applied instantly
|
||||
* even if the element already has a transition style */
|
||||
* transition:0s linear all;
|
||||
*
|
||||
* /* starting CSS styles */
|
||||
* opacity:1;
|
||||
* }
|
||||
* .fade-add.fade-add-active {
|
||||
* /* this will be the length of the animation */
|
||||
* transition:1s linear all;
|
||||
* opacity:0;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The setup CSS class (in this case `.fade-add`) also has a transition style property, however, it
|
||||
* has a duration of zero. This may not be required, however, incase the browser is unable to render
|
||||
* the styling present in this CSS class instantly then it could be that the browser is attempting
|
||||
* to perform an unnecessary transition.
|
||||
*
|
||||
* This workaround, however, does not apply to standard class-based transitions that are rendered
|
||||
* when a CSS class containing a transition is applied to an element:
|
||||
*
|
||||
* ```css
|
||||
* .fade {
|
||||
* /* this works as expected */
|
||||
* transition:1s linear all;
|
||||
* opacity:0;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Please keep this in mind when coding the CSS markup that will be used within class-based transitions.
|
||||
* Also, try not to mix the two class-based animation flavors together since the CSS code may become
|
||||
* overly complex.
|
||||
*
|
||||
* ### CSS Staggering Animations
|
||||
* <h3>CSS Staggering Animations</h3>
|
||||
* A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
|
||||
* curtain-like effect. The ngAnimate module, as of 1.2.0, supports staggering animations and the stagger effect can be
|
||||
* performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
|
||||
@@ -425,16 +360,6 @@ angular.module('ngAnimate', ['ng'])
|
||||
element.data(NG_ANIMATE_STATE, data);
|
||||
}
|
||||
|
||||
function runAnimationPostDigest(fn) {
|
||||
var cancelFn;
|
||||
$rootScope.$$postDigest(function() {
|
||||
cancelFn = fn();
|
||||
});
|
||||
return function() {
|
||||
cancelFn && cancelFn();
|
||||
};
|
||||
}
|
||||
|
||||
function lookup(name) {
|
||||
if (name) {
|
||||
var matches = [],
|
||||
@@ -638,27 +563,23 @@ angular.module('ngAnimate', ['ng'])
|
||||
*
|
||||
* Below is a breakdown of each step that occurs during enter animation:
|
||||
*
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|
|
||||
* | 1. $animate.enter(...) is called | class="my-animation" |
|
||||
* | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" |
|
||||
* | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
|
||||
* | 4. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
|
||||
* | 5. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" |
|
||||
* | 7. $animate blocks all CSS transitions on the element to ensure the .ng-enter class styling is applied right away | class="my-animation ng-animate ng-enter" |
|
||||
* | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-enter" |
|
||||
* | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-enter" |
|
||||
* | 10. the .ng-enter-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-enter ng-enter-active" |
|
||||
* | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-enter ng-enter-active" |
|
||||
* | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 13. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |----------------------------------------------------------------------------------------------|---------------------------------------------|
|
||||
* | 1. $animate.enter(...) is called | class="my-animation" |
|
||||
* | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" |
|
||||
* | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
|
||||
* | 4. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" |
|
||||
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" |
|
||||
* | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-enter" |
|
||||
* | 7. the .ng-enter-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
|
||||
* | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
|
||||
* | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
||||
*
|
||||
* @param {DOMElement} element the element that will be the focus of the enter animation
|
||||
* @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation
|
||||
* @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation
|
||||
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
||||
* @return {function} the animation cancellation function
|
||||
*/
|
||||
enter : function(element, parentElement, afterElement, doneCallback) {
|
||||
element = angular.element(element);
|
||||
@@ -667,8 +588,9 @@ angular.module('ngAnimate', ['ng'])
|
||||
|
||||
blockElementAnimations(element);
|
||||
$delegate.enter(element, parentElement, afterElement);
|
||||
return runAnimationPostDigest(function() {
|
||||
return performAnimation('enter', 'ng-enter', stripCommentsFromElement(element), parentElement, afterElement, noop, doneCallback);
|
||||
$rootScope.$$postDigest(function() {
|
||||
element = stripCommentsFromElement(element);
|
||||
performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -683,34 +605,28 @@ angular.module('ngAnimate', ['ng'])
|
||||
*
|
||||
* Below is a breakdown of each step that occurs during leave animation:
|
||||
*
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|
|
||||
* | 1. $animate.leave(...) is called | class="my-animation" |
|
||||
* | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
|
||||
* | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
|
||||
* | 4. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" |
|
||||
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" |
|
||||
* | 6. $animate blocks all CSS transitions on the element to ensure the .ng-leave class styling is applied right away | class="my-animation ng-animate ng-leave” |
|
||||
* | 7. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-leave" |
|
||||
* | 8. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-leave” |
|
||||
* | 9. the .ng-leave-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-leave ng-leave-active" |
|
||||
* | 10. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-leave ng-leave-active" |
|
||||
* | 11. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 12. The element is removed from the DOM | ... |
|
||||
* | 13. The doneCallback() callback is fired (if provided) | ... |
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |----------------------------------------------------------------------------------------------|---------------------------------------------|
|
||||
* | 1. $animate.leave(...) is called | class="my-animation" |
|
||||
* | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
|
||||
* | 3. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" |
|
||||
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" |
|
||||
* | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-leave" |
|
||||
* | 6. the .ng-leave-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
|
||||
* | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 9. The element is removed from the DOM | ... |
|
||||
* | 10. The doneCallback() callback is fired (if provided) | ... |
|
||||
*
|
||||
* @param {DOMElement} element the element that will be the focus of the leave animation
|
||||
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
||||
* @return {function} the animation cancellation function
|
||||
*/
|
||||
leave : function(element, doneCallback) {
|
||||
element = angular.element(element);
|
||||
|
||||
cancelChildAnimations(element);
|
||||
blockElementAnimations(element);
|
||||
this.enabled(false, element);
|
||||
return runAnimationPostDigest(function() {
|
||||
return performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
|
||||
$rootScope.$$postDigest(function() {
|
||||
performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
|
||||
$delegate.leave(element);
|
||||
}, doneCallback);
|
||||
});
|
||||
@@ -728,27 +644,23 @@ angular.module('ngAnimate', ['ng'])
|
||||
*
|
||||
* Below is a breakdown of each step that occurs during move animation:
|
||||
*
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------|
|
||||
* | 1. $animate.move(...) is called | class="my-animation" |
|
||||
* | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" |
|
||||
* | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
|
||||
* | 4. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
|
||||
* | 5. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" |
|
||||
* | 7. $animate blocks all CSS transitions on the element to ensure the .ng-move class styling is applied right away | class="my-animation ng-animate ng-move” |
|
||||
* | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-move" |
|
||||
* | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-move” |
|
||||
* | 10. the .ng-move-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-move ng-move-active" |
|
||||
* | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-move ng-move-active" |
|
||||
* | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 13. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |----------------------------------------------------------------------------------------------|---------------------------------------------|
|
||||
* | 1. $animate.move(...) is called | class="my-animation" |
|
||||
* | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" |
|
||||
* | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
|
||||
* | 4. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" |
|
||||
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" |
|
||||
* | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-move" |
|
||||
* | 7. the .ng-move-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
|
||||
* | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
|
||||
* | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
||||
*
|
||||
* @param {DOMElement} element the element that will be the focus of the move animation
|
||||
* @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation
|
||||
* @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation
|
||||
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
||||
* @return {function} the animation cancellation function
|
||||
*/
|
||||
move : function(element, parentElement, afterElement, doneCallback) {
|
||||
element = angular.element(element);
|
||||
@@ -758,8 +670,9 @@ angular.module('ngAnimate', ['ng'])
|
||||
cancelChildAnimations(element);
|
||||
blockElementAnimations(element);
|
||||
$delegate.move(element, parentElement, afterElement);
|
||||
return runAnimationPostDigest(function() {
|
||||
return performAnimation('move', 'ng-move', stripCommentsFromElement(element), parentElement, afterElement, noop, doneCallback);
|
||||
$rootScope.$$postDigest(function() {
|
||||
element = stripCommentsFromElement(element);
|
||||
performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -771,32 +684,31 @@ angular.module('ngAnimate', ['ng'])
|
||||
* Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
|
||||
* Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
|
||||
* the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
|
||||
* or keyframes are defined on the -add-active or base CSS class).
|
||||
* or keyframes are defined on the -add or base CSS class).
|
||||
*
|
||||
* Below is a breakdown of each step that occurs during addClass animation:
|
||||
*
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |----------------------------------------------------------------------------------------------------|------------------------------------------------------------------|
|
||||
* | 1. $animate.addClass(element, 'super') is called | class="my-animation" |
|
||||
* | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
|
||||
* | 3. the .super-add class is added to the element | class="my-animation ng-animate super-add" |
|
||||
* | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate super-add" |
|
||||
* | 5. the .super and .super-add-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate super super-add super-add-active" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" |
|
||||
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation super super-add super-add-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
|
||||
* | 9. The super class is kept on the element | class="my-animation super" |
|
||||
* | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" |
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |------------------------------------------------------------------------------------------------|---------------------------------------------|
|
||||
* | 1. $animate.addClass(element, 'super') is called | class="my-animation" |
|
||||
* | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
|
||||
* | 3. the .super-add class are added to the element | class="my-animation ng-animate super-add" |
|
||||
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" |
|
||||
* | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate super-add" |
|
||||
* | 6. the .super, .super-add-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super super-add super-add-active" |
|
||||
* | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation super super-add super-add-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
|
||||
* | 9. The super class is kept on the element | class="my-animation super" |
|
||||
* | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" |
|
||||
*
|
||||
* @param {DOMElement} element the element that will be animated
|
||||
* @param {string} className the CSS class that will be added to the element and then animated
|
||||
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
||||
* @return {function} the animation cancellation function
|
||||
*/
|
||||
addClass : function(element, className, doneCallback) {
|
||||
element = angular.element(element);
|
||||
element = stripCommentsFromElement(element);
|
||||
return performAnimation('addClass', className, element, null, null, function() {
|
||||
performAnimation('addClass', className, element, null, null, function() {
|
||||
$delegate.addClass(element, className);
|
||||
}, doneCallback);
|
||||
},
|
||||
@@ -813,64 +725,49 @@ angular.module('ngAnimate', ['ng'])
|
||||
*
|
||||
* Below is a breakdown of each step that occurs during removeClass animation:
|
||||
*
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|
|
||||
* | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" |
|
||||
* | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation super ng-animate" |
|
||||
* | 3. the .super-remove class is added to the element | class="my-animation super ng-animate super-remove" |
|
||||
* | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation super ng-animate super-remove" |
|
||||
* | 5. the .super-remove-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate super-remove super-remove-active" |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" |
|
||||
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate super-remove super-remove-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |-----------------------------------------------------------------------------------------------|---------------------------------------------|
|
||||
* | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" |
|
||||
* | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation super ng-animate" |
|
||||
* | 3. the .super-remove class are added to the element | class="my-animation super ng-animate super-remove"|
|
||||
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" |
|
||||
* | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation super ng-animate super-remove" |
|
||||
* | 6. the .super-remove-active and .ng-animate-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
|
||||
* | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
||||
*
|
||||
*
|
||||
* @param {DOMElement} element the element that will be animated
|
||||
* @param {string} className the CSS class that will be animated and then removed from the element
|
||||
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
||||
* @return {function} the animation cancellation function
|
||||
*/
|
||||
removeClass : function(element, className, doneCallback) {
|
||||
element = angular.element(element);
|
||||
element = stripCommentsFromElement(element);
|
||||
return performAnimation('removeClass', className, element, null, null, function() {
|
||||
performAnimation('removeClass', className, element, null, null, function() {
|
||||
$delegate.removeClass(element, className);
|
||||
}, doneCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @ngdoc method
|
||||
* @name $animate#setClass
|
||||
*
|
||||
* @description Adds and/or removes the given CSS classes to and from the element.
|
||||
* Once complete, the done() callback will be fired (if provided).
|
||||
*
|
||||
* | Animation Step | What the element class attribute looks like |
|
||||
* |--------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
|
||||
* | 1. $animate.removeClass(element, ‘on’, ‘off’) is called | class="my-animation super off” |
|
||||
* | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation super ng-animate off” |
|
||||
* | 3. the .on-add and .off-remove classes are added to the element | class="my-animation ng-animate on-add off-remove off” |
|
||||
* | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate on-add off-remove off” |
|
||||
* | 5. the .on, .on-add-active and .off-remove-active classes are added and .off is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active” |
|
||||
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
|
||||
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
|
||||
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||
* | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
||||
*
|
||||
* @param {DOMElement} element the element which will have its CSS classes changed
|
||||
* removed from it
|
||||
* @param {string} add the CSS classes which will be added to the element
|
||||
* @param {string} remove the CSS class which will be removed from the element
|
||||
* @param {function=} done the callback function (if provided) that will be fired after the
|
||||
* CSS classes have been set on the element
|
||||
* @return {function} the animation cancellation function
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* @ngdoc function
|
||||
* @name $animate#setClass
|
||||
* @function
|
||||
* @description Adds and/or removes the given CSS classes to and from the element.
|
||||
* Once complete, the done() callback will be fired (if provided).
|
||||
* @param {DOMElement} element the element which will its CSS classes changed
|
||||
* removed from it
|
||||
* @param {string} add the CSS classes which will be added to the element
|
||||
* @param {string} remove the CSS class which will be removed from the element
|
||||
* @param {Function=} done the callback function (if provided) that will be fired after the
|
||||
* CSS classes have been set on the element
|
||||
*/
|
||||
setClass : function(element, add, remove, doneCallback) {
|
||||
element = angular.element(element);
|
||||
element = stripCommentsFromElement(element);
|
||||
return performAnimation('setClass', [add, remove], element, null, null, function() {
|
||||
performAnimation('setClass', [add, remove], element, null, null, function() {
|
||||
$delegate.setClass(element, add, remove);
|
||||
}, doneCallback);
|
||||
},
|
||||
@@ -921,14 +818,13 @@ angular.module('ngAnimate', ['ng'])
|
||||
*/
|
||||
function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
|
||||
|
||||
var noopCancel = noop;
|
||||
var runner = animationRunner(element, animationEvent, className);
|
||||
if(!runner) {
|
||||
fireDOMOperation();
|
||||
fireBeforeCallbackAsync();
|
||||
fireAfterCallbackAsync();
|
||||
closeAnimation();
|
||||
return noopCancel;
|
||||
return;
|
||||
}
|
||||
|
||||
className = runner.className;
|
||||
@@ -962,7 +858,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
fireBeforeCallbackAsync();
|
||||
fireAfterCallbackAsync();
|
||||
closeAnimation();
|
||||
return noopCancel;
|
||||
return;
|
||||
}
|
||||
|
||||
var skipAnimation = false;
|
||||
@@ -975,9 +871,10 @@ angular.module('ngAnimate', ['ng'])
|
||||
//cancel all animations when a structural animation takes place
|
||||
for(var klass in runningAnimations) {
|
||||
animationsToCancel.push(runningAnimations[klass]);
|
||||
cleanup(element, klass);
|
||||
}
|
||||
ngAnimateState = {};
|
||||
cleanup(element, true);
|
||||
runningAnimations = {};
|
||||
totalActiveAnimations = 0;
|
||||
}
|
||||
} else if(lastAnimation.event == 'setClass') {
|
||||
animationsToCancel.push(lastAnimation);
|
||||
@@ -1000,9 +897,6 @@ angular.module('ngAnimate', ['ng'])
|
||||
}
|
||||
}
|
||||
|
||||
runningAnimations = ngAnimateState.active || {};
|
||||
totalActiveAnimations = ngAnimateState.totalActive || 0;
|
||||
|
||||
if(runner.isClassBased && !runner.isSetClassOperation && !skipAnimation) {
|
||||
skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR
|
||||
}
|
||||
@@ -1012,7 +906,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
fireBeforeCallbackAsync();
|
||||
fireAfterCallbackAsync();
|
||||
fireDoneCallbackAsync();
|
||||
return noopCancel;
|
||||
return;
|
||||
}
|
||||
|
||||
if(animationEvent == 'leave') {
|
||||
@@ -1065,8 +959,6 @@ angular.module('ngAnimate', ['ng'])
|
||||
}
|
||||
});
|
||||
|
||||
return runner.cancel;
|
||||
|
||||
function fireDOMCallback(animationPhase) {
|
||||
var eventName = '$animate:' + animationPhase;
|
||||
if(elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) {
|
||||
@@ -1255,6 +1147,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
|
||||
var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
|
||||
var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
|
||||
var NG_ANIMATE_BLOCK_CLASS_NAME = 'ng-animate-block-transitions';
|
||||
var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
|
||||
var CLOSING_TIME_BUFFER = 1.5;
|
||||
var ONE_SECOND = 1000;
|
||||
@@ -1310,9 +1203,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
forEach(elements, function(element) {
|
||||
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
if(elementData) {
|
||||
forEach(elementData.closeAnimationFns, function(fn) {
|
||||
fn();
|
||||
});
|
||||
(elementData.closeAnimationFn || noop)();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1396,9 +1287,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
return parentID + '-' + extractElementNode(element).getAttribute('class');
|
||||
}
|
||||
|
||||
function animateSetup(animationEvent, element, className) {
|
||||
var structural = ['ng-enter','ng-leave','ng-move'].indexOf(className) >= 0;
|
||||
|
||||
function animateSetup(animationEvent, element, className, calculationDecorator) {
|
||||
var cacheKey = getCacheKey(element);
|
||||
var eventCacheKey = cacheKey + ' ' + className;
|
||||
var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
|
||||
@@ -1416,47 +1305,87 @@ angular.module('ngAnimate', ['ng'])
|
||||
applyClasses && element.removeClass(staggerClassName);
|
||||
}
|
||||
|
||||
/* the animation itself may need to add/remove special CSS classes
|
||||
* before calculating the anmation styles */
|
||||
calculationDecorator = calculationDecorator ||
|
||||
function(fn) { return fn(); };
|
||||
|
||||
element.addClass(className);
|
||||
|
||||
var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {};
|
||||
var timings = getElementAnimationDetails(element, eventCacheKey);
|
||||
|
||||
var timings = calculationDecorator(function() {
|
||||
return getElementAnimationDetails(element, eventCacheKey);
|
||||
});
|
||||
|
||||
var transitionDuration = timings.transitionDuration;
|
||||
var animationDuration = timings.animationDuration;
|
||||
|
||||
if(structural && transitionDuration === 0 && animationDuration === 0) {
|
||||
if(transitionDuration === 0 && animationDuration === 0) {
|
||||
element.removeClass(className);
|
||||
return false;
|
||||
}
|
||||
|
||||
var blockTransition = structural && transitionDuration > 0;
|
||||
var blockAnimation = animationDuration > 0 &&
|
||||
stagger.animationDelay > 0 &&
|
||||
stagger.animationDuration === 0;
|
||||
|
||||
var closeAnimationFns = formerData.closeAnimationFns || [];
|
||||
element.data(NG_ANIMATE_CSS_DATA_KEY, {
|
||||
stagger : stagger,
|
||||
cacheKey : eventCacheKey,
|
||||
running : formerData.running || 0,
|
||||
itemIndex : itemIndex,
|
||||
blockTransition : blockTransition,
|
||||
blockAnimation : blockAnimation,
|
||||
closeAnimationFns : closeAnimationFns
|
||||
stagger : stagger,
|
||||
timings : timings,
|
||||
closeAnimationFn : noop
|
||||
});
|
||||
|
||||
var node = extractElementNode(element);
|
||||
|
||||
if(blockTransition) {
|
||||
node.style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
|
||||
//temporarily disable the transition so that the enter styles
|
||||
//don't animate twice (this is here to avoid a bug in Chrome/FF).
|
||||
var isCurrentlyAnimating = formerData.running > 0 || animationEvent == 'setClass';
|
||||
if(transitionDuration > 0) {
|
||||
blockTransitions(element, className, isCurrentlyAnimating);
|
||||
}
|
||||
|
||||
if(blockAnimation) {
|
||||
node.style[ANIMATION_PROP] = 'none 0s';
|
||||
//staggering keyframe animations work by adjusting the `animation-delay` CSS property
|
||||
//on the given element, however, the delay value can only calculated after the reflow
|
||||
//since by that time $animate knows how many elements are being animated. Therefore,
|
||||
//until the reflow occurs the element needs to be blocked (where the keyframe animation
|
||||
//is set to `none 0s`). This blocking mechanism should only be set for when a stagger
|
||||
//animation is detected and when the element item index is greater than 0.
|
||||
if(animationDuration > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0) {
|
||||
blockKeyframeAnimations(element);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isStructuralAnimation(className) {
|
||||
return className == 'ng-enter' || className == 'ng-move' || className == 'ng-leave';
|
||||
}
|
||||
|
||||
function blockTransitions(element, className, isAnimating) {
|
||||
if(isStructuralAnimation(className) || !isAnimating) {
|
||||
extractElementNode(element).style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
|
||||
} else {
|
||||
element.addClass(NG_ANIMATE_BLOCK_CLASS_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
function blockKeyframeAnimations(element) {
|
||||
extractElementNode(element).style[ANIMATION_PROP] = 'none 0s';
|
||||
}
|
||||
|
||||
function unblockTransitions(element, className) {
|
||||
var prop = TRANSITION_PROP + PROPERTY_KEY;
|
||||
var node = extractElementNode(element);
|
||||
if(node.style[prop] && node.style[prop].length > 0) {
|
||||
node.style[prop] = '';
|
||||
}
|
||||
element.removeClass(NG_ANIMATE_BLOCK_CLASS_NAME);
|
||||
}
|
||||
|
||||
function unblockKeyframeAnimations(element) {
|
||||
var prop = ANIMATION_PROP;
|
||||
var node = extractElementNode(element);
|
||||
if(node.style[prop] && node.style[prop].length > 0) {
|
||||
node.style[prop] = '';
|
||||
}
|
||||
}
|
||||
|
||||
function animateRun(animationEvent, element, className, activeAnimationComplete) {
|
||||
var node = extractElementNode(element);
|
||||
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
@@ -1465,36 +1394,21 @@ angular.module('ngAnimate', ['ng'])
|
||||
return;
|
||||
}
|
||||
|
||||
if(elementData.blockTransition) {
|
||||
node.style[TRANSITION_PROP + PROPERTY_KEY] = '';
|
||||
}
|
||||
|
||||
if(elementData.blockAnimation) {
|
||||
node.style[ANIMATION_PROP] = '';
|
||||
}
|
||||
|
||||
var activeClassName = '';
|
||||
forEach(className.split(' '), function(klass, i) {
|
||||
activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
|
||||
});
|
||||
|
||||
element.addClass(activeClassName);
|
||||
var eventCacheKey = elementData.cacheKey + ' ' + activeClassName;
|
||||
var timings = getElementAnimationDetails(element, eventCacheKey);
|
||||
|
||||
var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
|
||||
if(maxDuration === 0) {
|
||||
element.removeClass(activeClassName);
|
||||
animateClose(element, className);
|
||||
activeAnimationComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
|
||||
var stagger = elementData.stagger;
|
||||
var timings = elementData.timings;
|
||||
var itemIndex = elementData.itemIndex;
|
||||
var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
|
||||
var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
|
||||
var maxDelayTime = maxDelay * ONE_SECOND;
|
||||
|
||||
var startTime = Date.now();
|
||||
var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
|
||||
|
||||
var style = '', appliedStyles = [];
|
||||
if(timings.transitionDuration > 0) {
|
||||
var propertyStyle = timings.transitionPropertyStyle;
|
||||
@@ -1529,14 +1443,12 @@ angular.module('ngAnimate', ['ng'])
|
||||
node.setAttribute('style', oldStyle + '; ' + style);
|
||||
}
|
||||
|
||||
var startTime = Date.now();
|
||||
var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
|
||||
|
||||
element.on(css3AnimationEvents, onAnimationProgress);
|
||||
elementData.closeAnimationFns.push(function() {
|
||||
element.addClass(activeClassName);
|
||||
elementData.closeAnimationFn = function() {
|
||||
onEnd();
|
||||
activeAnimationComplete();
|
||||
});
|
||||
};
|
||||
|
||||
var staggerTime = itemIndex * (Math.max(stagger.animationDelay, stagger.transitionDelay) || 0);
|
||||
var animationTime = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER;
|
||||
@@ -1624,6 +1536,8 @@ angular.module('ngAnimate', ['ng'])
|
||||
//happen in the first place
|
||||
var cancel = preReflowCancellation;
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element, className);
|
||||
unblockKeyframeAnimations(element);
|
||||
//once the reflow is complete then we point cancel to
|
||||
//the new cancellation function which will remove all of the
|
||||
//animation properties from the active animation
|
||||
@@ -1664,27 +1578,49 @@ angular.module('ngAnimate', ['ng'])
|
||||
beforeSetClass : function(element, add, remove, animationCompleted) {
|
||||
var className = suffixClasses(remove, '-remove') + ' ' +
|
||||
suffixClasses(add, '-add');
|
||||
var cancellationMethod = animateBefore('setClass', element, className);
|
||||
var cancellationMethod = animateBefore('setClass', element, className, function(fn) {
|
||||
/* when classes are removed from an element then the transition style
|
||||
* that is applied is the transition defined on the element without the
|
||||
* CSS class being there. This is how CSS3 functions outside of ngAnimate.
|
||||
* http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
|
||||
var klass = element.attr('class');
|
||||
element.removeClass(remove);
|
||||
element.addClass(add);
|
||||
var timings = fn();
|
||||
element.attr('class', klass);
|
||||
return timings;
|
||||
});
|
||||
|
||||
if(cancellationMethod) {
|
||||
afterReflow(element, animationCompleted);
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element, className);
|
||||
unblockKeyframeAnimations(element);
|
||||
animationCompleted();
|
||||
});
|
||||
return cancellationMethod;
|
||||
}
|
||||
animationCompleted();
|
||||
},
|
||||
|
||||
beforeAddClass : function(element, className, animationCompleted) {
|
||||
var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'));
|
||||
if(cancellationMethod) {
|
||||
afterReflow(element, animationCompleted);
|
||||
return cancellationMethod;
|
||||
}
|
||||
animationCompleted();
|
||||
},
|
||||
var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), function(fn) {
|
||||
|
||||
/* when a CSS class is added to an element then the transition style that
|
||||
* is applied is the transition defined on the element when the CSS class
|
||||
* is added at the time of the animation. This is how CSS3 functions
|
||||
* outside of ngAnimate. */
|
||||
element.addClass(className);
|
||||
var timings = fn();
|
||||
element.removeClass(className);
|
||||
return timings;
|
||||
});
|
||||
|
||||
beforeRemoveClass : function(element, className, animationCompleted) {
|
||||
var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'));
|
||||
if(cancellationMethod) {
|
||||
afterReflow(element, animationCompleted);
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element, className);
|
||||
unblockKeyframeAnimations(element);
|
||||
animationCompleted();
|
||||
});
|
||||
return cancellationMethod;
|
||||
}
|
||||
animationCompleted();
|
||||
@@ -1701,6 +1637,30 @@ angular.module('ngAnimate', ['ng'])
|
||||
return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted);
|
||||
},
|
||||
|
||||
beforeRemoveClass : function(element, className, animationCompleted) {
|
||||
var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), function(fn) {
|
||||
/* when classes are removed from an element then the transition style
|
||||
* that is applied is the transition defined on the element without the
|
||||
* CSS class being there. This is how CSS3 functions outside of ngAnimate.
|
||||
* http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
|
||||
var klass = element.attr('class');
|
||||
element.removeClass(className);
|
||||
var timings = fn();
|
||||
element.attr('class', klass);
|
||||
return timings;
|
||||
});
|
||||
|
||||
if(cancellationMethod) {
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element, className);
|
||||
unblockKeyframeAnimations(element);
|
||||
animationCompleted();
|
||||
});
|
||||
return cancellationMethod;
|
||||
}
|
||||
animationCompleted();
|
||||
},
|
||||
|
||||
removeClass : function(element, className, animationCompleted) {
|
||||
return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted);
|
||||
}
|
||||
|
||||
Vendored
+5
-5
@@ -58,8 +58,8 @@ $provide.value("$locale", {
|
||||
"medium": "d MMM y HH:mm:ss",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "HH:mm:ss",
|
||||
"short": "y-MM-dd HH:mm",
|
||||
"shortDate": "y-MM-dd",
|
||||
"short": "yyyy-MM-dd HH:mm",
|
||||
"shortDate": "yyyy-MM-dd",
|
||||
"shortTime": "HH:mm"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
@@ -86,14 +86,14 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4-",
|
||||
"negSuf": "",
|
||||
"negPre": "(\u00a4",
|
||||
"negSuf": ")",
|
||||
"posPre": "\u00a4",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "af-na",
|
||||
"pluralCat": function (n, opt_precision) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
"pluralCat": function (n) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Vendored
+5
-5
@@ -58,8 +58,8 @@ $provide.value("$locale", {
|
||||
"medium": "dd MMM y h:mm:ss a",
|
||||
"mediumDate": "dd MMM y",
|
||||
"mediumTime": "h:mm:ss a",
|
||||
"short": "y-MM-dd h:mm a",
|
||||
"shortDate": "y-MM-dd",
|
||||
"short": "yyyy-MM-dd h:mm a",
|
||||
"shortDate": "yyyy-MM-dd",
|
||||
"shortTime": "h:mm a"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
@@ -86,14 +86,14 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4-",
|
||||
"negSuf": "",
|
||||
"negPre": "(\u00a4",
|
||||
"negSuf": ")",
|
||||
"posPre": "\u00a4",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "af-za",
|
||||
"pluralCat": function (n, opt_precision) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
"pluralCat": function (n) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Vendored
+5
-5
@@ -58,8 +58,8 @@ $provide.value("$locale", {
|
||||
"medium": "dd MMM y h:mm:ss a",
|
||||
"mediumDate": "dd MMM y",
|
||||
"mediumTime": "h:mm:ss a",
|
||||
"short": "y-MM-dd h:mm a",
|
||||
"shortDate": "y-MM-dd",
|
||||
"short": "yyyy-MM-dd h:mm a",
|
||||
"shortDate": "yyyy-MM-dd",
|
||||
"shortTime": "h:mm a"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
@@ -86,14 +86,14 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4-",
|
||||
"negSuf": "",
|
||||
"negPre": "(\u00a4",
|
||||
"negSuf": ")",
|
||||
"posPre": "\u00a4",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "af",
|
||||
"pluralCat": function (n, opt_precision) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
"pluralCat": function (n) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Vendored
+9
-9
@@ -4,8 +4,8 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"\u1325\u12cb\u1275",
|
||||
"\u12a8\u1230\u12d3\u1275"
|
||||
"\u1321\u12cb\u1275",
|
||||
"\u12a8\u1233\u12d3\u1275"
|
||||
],
|
||||
"DAY": [
|
||||
"\u12a5\u1211\u12f5",
|
||||
@@ -20,7 +20,7 @@ $provide.value("$locale", {
|
||||
"\u1303\u1295\u12e9\u12c8\u122a",
|
||||
"\u134c\u1265\u1229\u12c8\u122a",
|
||||
"\u121b\u122d\u127d",
|
||||
"\u12a4\u1355\u122a\u120d",
|
||||
"\u12a4\u1355\u1228\u120d",
|
||||
"\u121c\u12ed",
|
||||
"\u1301\u1295",
|
||||
"\u1301\u120b\u12ed",
|
||||
@@ -43,7 +43,7 @@ $provide.value("$locale", {
|
||||
"\u1303\u1295\u12e9",
|
||||
"\u134c\u1265\u1229",
|
||||
"\u121b\u122d\u127d",
|
||||
"\u12a4\u1355\u122a",
|
||||
"\u12a4\u1355\u1228",
|
||||
"\u121c\u12ed",
|
||||
"\u1301\u1295",
|
||||
"\u1301\u120b\u12ed",
|
||||
@@ -58,8 +58,8 @@ $provide.value("$locale", {
|
||||
"medium": "d MMM y h:mm:ss a",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "h:mm:ss a",
|
||||
"short": "dd/MM/y h:mm a",
|
||||
"shortDate": "dd/MM/y",
|
||||
"short": "dd/MM/yyyy h:mm a",
|
||||
"shortDate": "dd/MM/yyyy",
|
||||
"shortTime": "h:mm a"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
@@ -86,14 +86,14 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4-",
|
||||
"negSuf": "",
|
||||
"negPre": "(\u00a4",
|
||||
"negSuf": ")",
|
||||
"posPre": "\u00a4",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "am-et",
|
||||
"pluralCat": function (n, opt_precision) { var i = n | 0; if (i == 0 || n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
"pluralCat": function (n) { if (n == 0 || n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Vendored
+9
-9
@@ -4,8 +4,8 @@ var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"\u1325\u12cb\u1275",
|
||||
"\u12a8\u1230\u12d3\u1275"
|
||||
"\u1321\u12cb\u1275",
|
||||
"\u12a8\u1233\u12d3\u1275"
|
||||
],
|
||||
"DAY": [
|
||||
"\u12a5\u1211\u12f5",
|
||||
@@ -20,7 +20,7 @@ $provide.value("$locale", {
|
||||
"\u1303\u1295\u12e9\u12c8\u122a",
|
||||
"\u134c\u1265\u1229\u12c8\u122a",
|
||||
"\u121b\u122d\u127d",
|
||||
"\u12a4\u1355\u122a\u120d",
|
||||
"\u12a4\u1355\u1228\u120d",
|
||||
"\u121c\u12ed",
|
||||
"\u1301\u1295",
|
||||
"\u1301\u120b\u12ed",
|
||||
@@ -43,7 +43,7 @@ $provide.value("$locale", {
|
||||
"\u1303\u1295\u12e9",
|
||||
"\u134c\u1265\u1229",
|
||||
"\u121b\u122d\u127d",
|
||||
"\u12a4\u1355\u122a",
|
||||
"\u12a4\u1355\u1228",
|
||||
"\u121c\u12ed",
|
||||
"\u1301\u1295",
|
||||
"\u1301\u120b\u12ed",
|
||||
@@ -58,8 +58,8 @@ $provide.value("$locale", {
|
||||
"medium": "d MMM y h:mm:ss a",
|
||||
"mediumDate": "d MMM y",
|
||||
"mediumTime": "h:mm:ss a",
|
||||
"short": "dd/MM/y h:mm a",
|
||||
"shortDate": "dd/MM/y",
|
||||
"short": "dd/MM/yyyy h:mm a",
|
||||
"shortDate": "dd/MM/yyyy",
|
||||
"shortTime": "h:mm a"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
@@ -86,14 +86,14 @@ $provide.value("$locale", {
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4-",
|
||||
"negSuf": "",
|
||||
"negPre": "(\u00a4",
|
||||
"negSuf": ")",
|
||||
"posPre": "\u00a4",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "am",
|
||||
"pluralCat": function (n, opt_precision) { var i = n | 0; if (i == 0 || n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
"pluralCat": function (n) { if (n == 0 || n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
+13
-13
@@ -55,11 +55,11 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE\u060c d MMMM\u060c y",
|
||||
"longDate": "d MMMM\u060c y",
|
||||
"medium": "dd\u200f/MM\u200f/y h:mm:ss a",
|
||||
"mediumDate": "dd\u200f/MM\u200f/y",
|
||||
"medium": "dd\u200f/MM\u200f/yyyy h:mm:ss a",
|
||||
"mediumDate": "dd\u200f/MM\u200f/yyyy",
|
||||
"mediumTime": "h:mm:ss a",
|
||||
"short": "d\u200f/M\u200f/y h:mm a",
|
||||
"shortDate": "d\u200f/M\u200f/y",
|
||||
"short": "d\u200f/M\u200f/yyyy h:mm a",
|
||||
"shortDate": "d\u200f/M\u200f/yyyy",
|
||||
"shortTime": "h:mm a"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
@@ -68,32 +68,32 @@ $provide.value("$locale", {
|
||||
"GROUP_SEP": "\u066c",
|
||||
"PATTERNS": [
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"gSize": 0,
|
||||
"lgSize": 0,
|
||||
"macFrac": 0,
|
||||
"maxFrac": 3,
|
||||
"minFrac": 0,
|
||||
"minInt": 1,
|
||||
"negPre": "-",
|
||||
"negSuf": "",
|
||||
"negPre": "",
|
||||
"negSuf": "-",
|
||||
"posPre": "",
|
||||
"posSuf": ""
|
||||
},
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"gSize": 0,
|
||||
"lgSize": 0,
|
||||
"macFrac": 0,
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"negPre": "\u00a4\u00a0",
|
||||
"negSuf": "-",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "ar-001",
|
||||
"pluralCat": function (n, opt_precision) { if (n == 0) { return PLURAL_CATEGORY.ZERO; } if (n == 1) { return PLURAL_CATEGORY.ONE; } if (n == 2) { return PLURAL_CATEGORY.TWO; } if (n % 100 >= 3 && n % 100 <= 10) { return PLURAL_CATEGORY.FEW; } if (n % 100 >= 11 && n % 100 <= 99) { return PLURAL_CATEGORY.MANY; } return PLURAL_CATEGORY.OTHER;}
|
||||
"pluralCat": function (n) { if (n == 0) { return PLURAL_CATEGORY.ZERO; } if (n == 1) { return PLURAL_CATEGORY.ONE; } if (n == 2) { return PLURAL_CATEGORY.TWO; } if (n == (n | 0) && n % 100 >= 3 && n % 100 <= 10) { return PLURAL_CATEGORY.FEW; } if (n == (n | 0) && n % 100 >= 11 && n % 100 <= 99) { return PLURAL_CATEGORY.MANY; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Vendored
+13
-13
@@ -55,11 +55,11 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE\u060c d MMMM\u060c y",
|
||||
"longDate": "d MMMM\u060c y",
|
||||
"medium": "dd\u200f/MM\u200f/y h:mm:ss a",
|
||||
"mediumDate": "dd\u200f/MM\u200f/y",
|
||||
"medium": "dd\u200f/MM\u200f/yyyy h:mm:ss a",
|
||||
"mediumDate": "dd\u200f/MM\u200f/yyyy",
|
||||
"mediumTime": "h:mm:ss a",
|
||||
"short": "d\u200f/M\u200f/y h:mm a",
|
||||
"shortDate": "d\u200f/M\u200f/y",
|
||||
"short": "d\u200f/M\u200f/yyyy h:mm a",
|
||||
"shortDate": "d\u200f/M\u200f/yyyy",
|
||||
"shortTime": "h:mm a"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
@@ -68,32 +68,32 @@ $provide.value("$locale", {
|
||||
"GROUP_SEP": "\u066c",
|
||||
"PATTERNS": [
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"gSize": 0,
|
||||
"lgSize": 0,
|
||||
"macFrac": 0,
|
||||
"maxFrac": 3,
|
||||
"minFrac": 0,
|
||||
"minInt": 1,
|
||||
"negPre": "-",
|
||||
"negSuf": "",
|
||||
"negPre": "",
|
||||
"negSuf": "-",
|
||||
"posPre": "",
|
||||
"posSuf": ""
|
||||
},
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"gSize": 0,
|
||||
"lgSize": 0,
|
||||
"macFrac": 0,
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"negPre": "\u00a4\u00a0",
|
||||
"negSuf": "-",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "ar-ae",
|
||||
"pluralCat": function (n, opt_precision) { if (n == 0) { return PLURAL_CATEGORY.ZERO; } if (n == 1) { return PLURAL_CATEGORY.ONE; } if (n == 2) { return PLURAL_CATEGORY.TWO; } if (n % 100 >= 3 && n % 100 <= 10) { return PLURAL_CATEGORY.FEW; } if (n % 100 >= 11 && n % 100 <= 99) { return PLURAL_CATEGORY.MANY; } return PLURAL_CATEGORY.OTHER;}
|
||||
"pluralCat": function (n) { if (n == 0) { return PLURAL_CATEGORY.ZERO; } if (n == 1) { return PLURAL_CATEGORY.ONE; } if (n == 2) { return PLURAL_CATEGORY.TWO; } if (n == (n | 0) && n % 100 >= 3 && n % 100 <= 10) { return PLURAL_CATEGORY.FEW; } if (n == (n | 0) && n % 100 >= 11 && n % 100 <= 99) { return PLURAL_CATEGORY.MANY; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Vendored
+13
-13
@@ -55,11 +55,11 @@ $provide.value("$locale", {
|
||||
],
|
||||
"fullDate": "EEEE\u060c d MMMM\u060c y",
|
||||
"longDate": "d MMMM\u060c y",
|
||||
"medium": "dd\u200f/MM\u200f/y h:mm:ss a",
|
||||
"mediumDate": "dd\u200f/MM\u200f/y",
|
||||
"medium": "dd\u200f/MM\u200f/yyyy h:mm:ss a",
|
||||
"mediumDate": "dd\u200f/MM\u200f/yyyy",
|
||||
"mediumTime": "h:mm:ss a",
|
||||
"short": "d\u200f/M\u200f/y h:mm a",
|
||||
"shortDate": "d\u200f/M\u200f/y",
|
||||
"short": "d\u200f/M\u200f/yyyy h:mm a",
|
||||
"shortDate": "d\u200f/M\u200f/yyyy",
|
||||
"shortTime": "h:mm a"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
@@ -68,32 +68,32 @@ $provide.value("$locale", {
|
||||
"GROUP_SEP": "\u066c",
|
||||
"PATTERNS": [
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"gSize": 0,
|
||||
"lgSize": 0,
|
||||
"macFrac": 0,
|
||||
"maxFrac": 3,
|
||||
"minFrac": 0,
|
||||
"minInt": 1,
|
||||
"negPre": "-",
|
||||
"negSuf": "",
|
||||
"negPre": "",
|
||||
"negSuf": "-",
|
||||
"posPre": "",
|
||||
"posSuf": ""
|
||||
},
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"gSize": 0,
|
||||
"lgSize": 0,
|
||||
"macFrac": 0,
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"negPre": "\u00a4\u00a0",
|
||||
"negSuf": "-",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "ar-bh",
|
||||
"pluralCat": function (n, opt_precision) { if (n == 0) { return PLURAL_CATEGORY.ZERO; } if (n == 1) { return PLURAL_CATEGORY.ONE; } if (n == 2) { return PLURAL_CATEGORY.TWO; } if (n % 100 >= 3 && n % 100 <= 10) { return PLURAL_CATEGORY.FEW; } if (n % 100 >= 11 && n % 100 <= 99) { return PLURAL_CATEGORY.MANY; } return PLURAL_CATEGORY.OTHER;}
|
||||
"pluralCat": function (n) { if (n == 0) { return PLURAL_CATEGORY.ZERO; } if (n == 1) { return PLURAL_CATEGORY.ONE; } if (n == 2) { return PLURAL_CATEGORY.TWO; } if (n == (n | 0) && n % 100 >= 3 && n % 100 <= 10) { return PLURAL_CATEGORY.FEW; } if (n == (n | 0) && n % 100 >= 11 && n % 100 <= 99) { return PLURAL_CATEGORY.MANY; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Vendored
-99
@@ -1,99 +0,0 @@
|
||||
'use strict';
|
||||
angular.module("ngLocale", [], ["$provide", function($provide) {
|
||||
var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
|
||||
$provide.value("$locale", {
|
||||
"DATETIME_FORMATS": {
|
||||
"AMPMS": [
|
||||
"\u0635",
|
||||
"\u0645"
|
||||
],
|
||||
"DAY": [
|
||||
"\u0627\u0644\u0623\u062d\u062f",
|
||||
"\u0627\u0644\u0627\u062b\u0646\u064a\u0646",
|
||||
"\u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621",
|
||||
"\u0627\u0644\u0623\u0631\u0628\u0639\u0627\u0621",
|
||||
"\u0627\u0644\u062e\u0645\u064a\u0633",
|
||||
"\u0627\u0644\u062c\u0645\u0639\u0629",
|
||||
"\u0627\u0644\u0633\u0628\u062a"
|
||||
],
|
||||
"MONTH": [
|
||||
"\u064a\u0646\u0627\u064a\u0631",
|
||||
"\u0641\u0628\u0631\u0627\u064a\u0631",
|
||||
"\u0645\u0627\u0631\u0633",
|
||||
"\u0623\u0628\u0631\u064a\u0644",
|
||||
"\u0645\u0627\u064a\u0648",
|
||||
"\u064a\u0648\u0646\u064a\u0648",
|
||||
"\u064a\u0648\u0644\u064a\u0648",
|
||||
"\u0623\u063a\u0633\u0637\u0633",
|
||||
"\u0633\u0628\u062a\u0645\u0628\u0631",
|
||||
"\u0623\u0643\u062a\u0648\u0628\u0631",
|
||||
"\u0646\u0648\u0641\u0645\u0628\u0631",
|
||||
"\u062f\u064a\u0633\u0645\u0628\u0631"
|
||||
],
|
||||
"SHORTDAY": [
|
||||
"\u0627\u0644\u0623\u062d\u062f",
|
||||
"\u0627\u0644\u0627\u062b\u0646\u064a\u0646",
|
||||
"\u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621",
|
||||
"\u0627\u0644\u0623\u0631\u0628\u0639\u0627\u0621",
|
||||
"\u0627\u0644\u062e\u0645\u064a\u0633",
|
||||
"\u0627\u0644\u062c\u0645\u0639\u0629",
|
||||
"\u0627\u0644\u0633\u0628\u062a"
|
||||
],
|
||||
"SHORTMONTH": [
|
||||
"\u064a\u0646\u0627\u064a\u0631",
|
||||
"\u0641\u0628\u0631\u0627\u064a\u0631",
|
||||
"\u0645\u0627\u0631\u0633",
|
||||
"\u0623\u0628\u0631\u064a\u0644",
|
||||
"\u0645\u0627\u064a\u0648",
|
||||
"\u064a\u0648\u0646\u064a\u0648",
|
||||
"\u064a\u0648\u0644\u064a\u0648",
|
||||
"\u0623\u063a\u0633\u0637\u0633",
|
||||
"\u0633\u0628\u062a\u0645\u0628\u0631",
|
||||
"\u0623\u0643\u062a\u0648\u0628\u0631",
|
||||
"\u0646\u0648\u0641\u0645\u0628\u0631",
|
||||
"\u062f\u064a\u0633\u0645\u0628\u0631"
|
||||
],
|
||||
"fullDate": "EEEE\u060c d MMMM\u060c y",
|
||||
"longDate": "d MMMM\u060c y",
|
||||
"medium": "dd\u200f/MM\u200f/y h:mm:ss a",
|
||||
"mediumDate": "dd\u200f/MM\u200f/y",
|
||||
"mediumTime": "h:mm:ss a",
|
||||
"short": "d\u200f/M\u200f/y h:mm a",
|
||||
"shortDate": "d\u200f/M\u200f/y",
|
||||
"shortTime": "h:mm a"
|
||||
},
|
||||
"NUMBER_FORMATS": {
|
||||
"CURRENCY_SYM": "\u00a3",
|
||||
"DECIMAL_SEP": "\u066b",
|
||||
"GROUP_SEP": "\u066c",
|
||||
"PATTERNS": [
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"macFrac": 0,
|
||||
"maxFrac": 3,
|
||||
"minFrac": 0,
|
||||
"minInt": 1,
|
||||
"negPre": "-",
|
||||
"negSuf": "",
|
||||
"posPre": "",
|
||||
"posSuf": ""
|
||||
},
|
||||
{
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"macFrac": 0,
|
||||
"maxFrac": 2,
|
||||
"minFrac": 2,
|
||||
"minInt": 1,
|
||||
"negPre": "\u00a4\u00a0-",
|
||||
"negSuf": "",
|
||||
"posPre": "\u00a4\u00a0",
|
||||
"posSuf": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": "ar-dj",
|
||||
"pluralCat": function (n, opt_precision) { if (n == 0) { return PLURAL_CATEGORY.ZERO; } if (n == 1) { return PLURAL_CATEGORY.ONE; } if (n == 2) { return PLURAL_CATEGORY.TWO; } if (n % 100 >= 3 && n % 100 <= 10) { return PLURAL_CATEGORY.FEW; } if (n % 100 >= 11 && n % 100 <= 99) { return PLURAL_CATEGORY.MANY; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user